3 * A shipping company may be founded with this class
5 * @author Roland Haeder <webmaster@ship-simu.org>
7 * @copyright Copyright(c) 2007, 2008 Roland Haeder, this is free software
8 * @license GNU GPL 3.0 or any newer version
9 * @link http://www.ship-simu.org
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 class ShippingCompany extends BaseSimulator implements Customer, ContractPartner {
26 * Full name of this company
28 private $companyName = "Namenlose Reederei";
31 * Shorted name of this company
33 private $shortName = "";
36 * Instance of the founder
38 private $founderInstance = null;
41 * Employed people by this company
43 private $employeeList = null;
46 * Headquarter harbor instance
48 private $hqInstance = null;
51 * List of all assigned shipyards
53 private $shipyardList = null;
58 private $ownedShips = null;
61 * Work constracts this company is currently working on
63 private $contractList = null;
70 protected function __construct () {
71 // Call parent constructor
72 parent::__construct(__CLASS__);
75 $this->setObjectDescription("Reederei");
77 // Generate unique ID number
78 $this->createUniqueID();
81 $this->removeSystemArray();
84 // Reederei gruenden (create wegen Namenskonvention)
85 public final static function createShippingCompany ($companyName, Harbor $hqInstance) {
87 $companyInstance = new ShippingCompany();
89 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $companyInstance->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> wird gegründet.<br />\n",
96 $companyInstance->setCompanyName($companyName);
99 $companyInstance->createShortName();
102 $companyInstance->setHQInstance($hqInstance);
104 // Werftenliste erstellen
105 $companyInstance->createshipyardList();
107 // Angestellten-Liste erstellen
108 $companyInstance->createEmployeeList();
110 // Auftragsliste erstellen
111 $companyInstance->createContractList();
114 $companyInstance->removeWidth();
115 $companyInstance->removeHeight();
116 $companyInstance->removeLength();
117 $companyInstance->removeDraught();
118 $companyInstance->removePartInstance();
120 // Instanz zurueckgeben
121 return $companyInstance;
124 // Angestellten-Liste erstellen
125 private function createEmployeeList () {
126 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> erhält eine Angestelltenliste.<br />\n",
129 $this->getCompanyName()
131 $this->employeeList = new FrameworkArrayObject();
134 // Werftenliste erstellen
135 public function createShipyardList () {
136 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> erhält eine Werftsliste.<br />\n",
139 $this->getCompanyName()
141 $this->shipyardList = new FrameworkArrayObject();
144 // Auftragsliste erstellen
145 public function createContractList () {
146 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> erhält eine Auftragsliste.<br />\n",
149 $this->getCompanyName()
151 $this->contractList = new FrameworkArrayObject();
154 // Setter-Methode fuer Firmennamen
155 public final function setCompanyName ($companyName) {
156 $this->companyName = (string) $companyName;
159 // Getter-Methode fuer Firmennamen
160 public final function getCompanyName () {
161 return $this->companyName;
164 // Setter-Methode fuer Firmensitz
165 public final function setHQInstance (Harbor $hqInstance) {
166 $this->hqInstance = $hqInstance;
170 private function createShortName () {
171 // Mindestens eine Leerstelle?
172 $dummy = explode(" ", $this->getCompanyName());
173 foreach ($dummy as $part) {
174 $this->shortName .= substr($part, 0, 1);
178 // Reedereien Werften bauen lassen
179 public function createShipyardInHarbor($shipyardName, Harbor $harborInstance) {
180 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> baut im <strong>%s</strong> eine Werft <strong>%s</strong>.<br />\n",
183 $this->getCompanyName(),
184 $harborInstance->getHarborName(),
188 // Wird im HQ gebaut?
189 if ($this->hqInstance->equals($harborInstance)) {
190 // Die neue Werft wird im HQ gebaut!
191 $this->hqInstance->addNewShipyardNotify($shipyardName, $this);
192 // Die Werft drueber in Kenntnis setzen, welcher Reederei sie angehoert
194 // Ausserhalb des Heimathafens soll eine Werft gebaut werden
195 $harborInstance->addNewShipyardNotify($shipyardName, $this);
199 // Setter fuer Reederei-Gruender
200 public final function setCompanyFounder(CompanyEmployee $founderInstance) {
201 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> ist von <strong>%s %s</strong> gegründet worden.<br />\n",
204 $this->getCompanyName(),
205 $founderInstance->getSurname(),
206 $founderInstance->getFamily()
208 $this->founderInstance = $founderInstance;
211 // Getter for founder instance
212 public final function getFounderInstance () {
213 return $this->founderInstance;
216 // Neue(n) Angestellte(n) in Angestellten-Liste aufnehmen
217 public function addNewEmployee (SimulatorPersonell $employeeInstance) {
218 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] <strong>%s %s</strong> tritt der Reederei <strong>%s</strong> als <strong>%s</strong> bei und erhält ein Gehalt von <strong>%s</strong>.<br />\n",
221 $employeeInstance->getSurname(),
222 $employeeInstance->getFamily(),
223 $this->getCompanyName(),
224 $employeeInstance->getObjectDescription(),
225 $this->formatCurrency($employeeInstance->getSalary())
227 $this->employeeList->append($employeeInstance);
230 // Neue Werft in Liste aufnehmen
231 public function addNewShipyard (Shipyard $shipyardInstance) {
232 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> erhält die Werft <strong>%s</strong> hinzugefügt.<br />\n",
235 $this->getCompanyName(),
236 $shipyardInstance->getShipyardName()
238 $this->shipyardList->append($shipyardInstance);
241 // Neue Mitarbeiter per Zufall einstellen/rekrutieren
242 public function recruitRandomEmployees($amount, SimulatorPersonell $personellInstance) {
243 // Anzahl Mitarbeiter absichern
244 $amount = (int) $amount;
246 // Debug-Meldung ausgeben
247 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> stellt per Zufall <strong>%d</strong> neue Mitarbeiter ein.<br />\n",
250 $this->getCompanyName(),
254 // Gesamtanzahl verfuegbarer Erwerbsloser holen
255 $totalUnemployed = $personellInstance->getAllUnemployed();
257 // Existiert die gewuenschte Anzahl freier Arbeiter? (doppelt geht derzeit nicht)
258 if ($totalUnemployed < $amount) {
259 // Reichte nicht aus!
260 throw new ToMuchEmployeesException(array($amount, $personellInstance->getAllUnemployed()), self::EXCEPTION_NOT_ENOUGTH_UNEMPLOYEES);
263 // Get list for all unemployed people
264 $list = $personellInstance->getSpecialPersonellList(false); // Should be cached
266 // Get iterator of the list
267 $iterator = $list->getIterator();
269 // Get the requested amount of personell
270 for ($idx = 0; $idx < $amount; $idx++) {
272 // Is this personl unemployed?
273 while (is_null($employee) || $employee->isEmployed()) {
274 // Generate random number
275 $pos = mt_rand(0, ($totalUnemployed - 1)); // Don't remove the -1 here:
276 // E.g. 100 entries means latest position is 99...
278 // Seek for the position
279 $iterator->seek($pos);
281 // Is the current position valid?
282 if ($iterator->valid()) {
284 $employee = $iterator->current();
286 // Should normally not happen... :(
287 throw new StructuresOutOfBoundsException($idx, self::EXCEPTION_INDEX_OUT_OF_BOUNDS);
291 // A dummy just for the description and real class
292 $dummy = CompanyEmployee::createCompanyEmployee("", "", "M", 1970, 1, 1, $employee->isMarried(), 0);
294 // Make this person employed and give him some money to work
295 $employee->setEmployed(true);
296 $employee->setObjectDescription($dummy->getObjectDescription());
297 $employee->setRealClass($dummy->__toString());
298 $employee->increaseSalary((mt_rand(7, 14) * 100)); // Are 700 to 1400 EUR for the begin okay?
301 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> stellt den/die Angestellte(n) <strong>%s %s</strong> ein.<br />\n",
304 $this->getCompanyName(),
305 $employee->getSurname(),
306 $employee->getFamily()
310 $this->addNewEmployee($employee);
314 $personellInstance->resetCache();
316 // Debug-Meldung ausgeben
317 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> hat per Zufall <strong>%d</strong> neue Mitarbeiter eingestellt.<br />\n",
320 $this->getCompanyName(),
325 // Distribute all personells on all shipyards
326 public function distributeAllPersonellOnShipyards () {
327 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> verteilt alle ihre <strong>%d</strong> Mitarbeiter auf alle <strong>%d</strong> Werft(en).<br />\n",
330 $this->getCompanyName(),
331 $this->getTotalEmployee(),
332 $this->getTotalShipyards()
335 // Do we have some shipyards?
336 if (is_null($this->shipyardList)) {
337 // No shipyards created
338 throw new NoShipyardsConstructedException($this, self::EXCEPTION_HARBOR_HAS_NO_SHIPYARDS);
341 // Get iterator for shipyards
342 $shipyardIter = $this->shipyardList->getIterator();
344 // Iterate through all employees
345 for ($idx = $this->employeeList->getIterator(); $idx->valid(); $idx->next()) {
346 // Is the shipyard iterator still okay?
347 if (!$shipyardIter->valid()) {
348 // Rewind to first position
349 $shipyardIter->seek(0);
352 // Get Shipyard object
353 $shipyard = $shipyardIter->current();
355 // Is this a Shipyard object?
356 if (is_null($shipyard)) {
358 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
359 } elseif (!is_object($shipyard)) {
360 // Not an object! ;-(
361 throw new NoObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
362 } elseif (!$shipyard->isClass("Shipyard")) {
363 // Nope, so throw exception
364 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
367 // Add employee to the shipyard
368 $shipyard->addNewPersonell($idx->current());
370 // Continue to next shipyard
371 $shipyardIter->next();
375 // Getter for total employees
376 public final function getTotalEmployee () {
378 $total = $this->employeeList->count();
381 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> hat <strong>%d</strong> Mitarbeiter.<br />\n",
384 $this->getCompanyName(),
392 // Getter for total shipyards
393 public final function getTotalShipyards () {
394 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Für die Reederei <strong>%s</strong> werden die Anzahl der Werften in allen Häfen ermittelt.<br />\n",
397 $this->getCompanyName()
400 // Do we have some shipyards?
401 if (is_null($this->shipyardList)) {
402 // No shipyards created
403 throw new NoShipyardsConstructedException($this, self::EXCEPTION_HARBOR_HAS_NO_SHIPYARDS);
407 $total = $this->shipyardList->count();
410 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> hat <strong>%d</strong> Werft(en).<br />\n",
413 $this->getCompanyName(),
421 // Add a ship type (class) to all shipyards
422 public function addShipTypeToAllShipyards ($shipType) {
424 $shipType = (string) $shipType;
426 // Is the class there?
427 if (!class_exists($shipType)) {
429 throw new ClassNotFoundException($shipType, self::EXCEPTION_CLASS_NOT_FOUND);
433 eval(sprintf("\$shipInstance = %s::create%s(\"M/S Dummy\");",
439 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> baut in allen Werften bald Schiffe vom Typ <strong>%s</strong>.<br />\n",
442 $this->getCompanyName(),
443 $shipInstance->getObjectDescription()
446 // Iterate shipyard list
447 for ($idx = $this->shipyardList->getIterator(); $idx->valid(); $idx->next()) {
448 // Get current element
449 $shipyard = $idx->current();
451 // Is this a shipyard?
452 if (is_null($shipyard)) {
454 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
455 } elseif (!is_object($shipyard)) {
456 // Not an object! ;-(
457 throw new NoObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
458 } elseif (!$shipyard->isClass("Shipyard")) {
459 // Class is not a shipyard
460 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
463 // Add the new ship type to the shipyard
464 $shipyard->addNewConstructableShipType($shipType);
468 // Validate the requested ship type with the company if they can construct it
469 public function validateWorksContractShipType (SignableContract $contractInstance) {
470 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> prüft den Bauauftrag der <strong>%s</strong>.<br />\n",
473 $this->getCompanyName(),
474 $contractInstance->getShipName()
477 // First get the ship type
478 $shipInstance = $contractInstance->getShipInstance();
480 // Ist there a ship instance?
481 if (is_null($shipInstance)) {
482 // Opps! Empty entry?
483 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
484 } elseif (!is_object($shipInstance)) {
485 // Not an object! ;-(
486 throw new NoObjectException($shipInstance, self::EXCEPTION_IS_NO_OBJECT);
489 // Get it's real class name
490 $shipType = $shipInstance->__toString();
493 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> prüft, ob die <strong>%s</strong> (Typ:<strong>%s</strong>) gebaut werden kann.<br />\n",
496 $this->getCompanyName(),
497 $contractInstance->getShipName(),
498 $shipInstance->getObjectDescription()
501 // Now check if the ship type is in any list and return the result
502 return ($this->isShipTypeConstructable($shipType));
505 // Is the ship type constructable?
506 public function isShipTypeConstructable ($shipType) {
507 // The type must be a string!
508 $shipType = (string) $shipType;
511 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> fragt alle Werften ab, ob diese Schiffe vom Typ <strong>%s</strong> bauen können.<br />\n",
514 $this->getCompanyName(),
518 // First everthing is failed...
521 // Iterate through all shipyards
522 for ($idx = $this->shipyardList->getIterator(); $idx->valid(); $idx->next()) {
523 // Get current Shipyard instance
524 $shipyard = $idx->current();
526 // Is this a shipyard?
527 if (is_null($shipyard)) {
529 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
530 } elseif (!is_object($shipyard)) {
531 // Not an object! ;-(
532 throw new NoObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
533 } elseif (!$shipyard->isClass("Shipyard")) {
534 // Class is not a shipyard
535 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
538 // Validate if the first found shipyard can construct the requested type
539 $result = $shipyard->isShipTypeConstructable($shipType);
541 // Does this shipyard construct the requested ship type?
542 if ($result) break; // Then abort the search!
546 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> hat die Suche nach einer Werft beendet, die Schiffe vom Typ <strong>%s</strong> bauen kann.<br />\n",
549 $this->getCompanyName(),
557 // As a customer the shipping company can add new contracts
558 public function addNewWorksContract (SignableContract $contractInstance) {
559 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> erstellt einen Bauauftrag für ein <strong>%s</strong> mit dem Namen <strong>%s</strong>.<br />\n",
562 $this->getCompanyName(),
563 $contractInstance->getShipInstance()->getObjectDescription(),
564 $contractInstance->getShipInstance()->getShipName()
566 $this->contractList->append($contractInstance);
569 // As a customer the shippng company can withdraw from a contract
570 public function withdrawFromContract (SignableContract $contractInstance) {
571 ApplicationEntryPoint::app_die("WITHDRAW:<pre>".print_r($contractInstance, true)."</pre>");
574 // Get latest added contract instance
575 public final function getLastContractInstance () {
577 $iter = $this->contractList->getIterator();
579 // Get latest entry (total - 1)
580 $iter->seek($iter->count() - 1);
583 return $iter->current();
586 // Sign a contract with an other party which must also implement Customer
587 public function signContract (SignableContract $contractInstance, ContractPartner $partnerInstance) {
588 // Check wether the other party is our contract partner
589 if (!$partnerInstance->isContractPartner($contractInstance)) {
590 // Invalid contract partner!
591 throw new InvalidContractPartnerException($partnerInstance, self::EXCEPTION_CONTRACT_PARTNER_INVALID);
594 // Determine if company "signs" own contract (must be done) or with an other party
595 if ($this->equals($partnerInstance)) {
597 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> erteilt an sich selbst einen Bauauftrag für das <strong>%s</strong> "<strong>%s</strong>".<br />\n",
600 $this->getCompanyName(),
601 $contractInstance->getShipInstance()->getObjectDescription(),
602 $contractInstance->getShipInstance()->getShipName()
605 // Other external company
606 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> unterzeichnet einen Bauauftrag für das <strong>%s</strong> "<strong>%s</strong>" mit der <strong>%s</strong>.<br />\n",
609 $this->getCompanyName(),
610 $contractInstance->getShipInstance()->getObjectDescription(),
611 $contractInstance->getShipInstance()->getShipName(),
612 $partnerInstance->getCompanyName()
617 $contractInstance->signContract($this, $partnerInstance);
620 * @todo Maybe do something more here...
624 // Is this the right contract partner?
625 public function isContractPartner (SignableContract $contractInstance) {
626 // Get contract partner instance and compare it with $this contract partner
627 return ($this->equals($contractInstance->getContractPartner()));
630 // Setter for merchant instance
631 public final function setMerchantInstance (Merchant $merchantInstance) {
633 $contractInstance = $this->getLastContractInstance();
635 if (is_null($contractInstance)) {
636 // Opps! Empty contract instance?
637 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
638 } elseif (!is_object($contractInstance)) {
639 // Not an object! ;-(
640 throw new NoObjectException($contractInstance, self::EXCEPTION_IS_NO_OBJECT);
641 } elseif (!$contractInstance->isClass('WorksContract')) {
643 throw new ClassMismatchException(array($contractInstance->__toString(), "WorksContract"), self::EXCEPTION_CLASSES_NOT_MATCHING);
646 // Set the merchant in the contract (for getting prices)
647 $contractInstance->setMerchantInstance($merchantInstance);