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 if (((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) && (defined('DEBUG_CONSTRUCT'))) {
76 $this->getDebugInstance()->output(sprintf("[%s:%d] Konstruktor erreicht.<br />\n",
83 $this->setObjectDescription("Reederei");
85 // Generate unique ID number
86 $this->createUniqueID();
89 $this->removeSystemArray();
92 // Reederei gruenden (create wegen Namenskonvention)
93 public final static function createShippingCompany ($companyName, Harbor $hqInstance) {
95 $companyInstance = new ShippingCompany();
97 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $companyInstance->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> wird gegründet.<br />\n",
103 // Firmennamen setzen
104 $companyInstance->setCompanyName($companyName);
107 $companyInstance->createShortName();
110 $companyInstance->setHQInstance($hqInstance);
112 // Werftenliste erstellen
113 $companyInstance->createshipyardList();
115 // Angestellten-Liste erstellen
116 $companyInstance->createEmployeeList();
118 // Auftragsliste erstellen
119 $companyInstance->createContractList();
122 $companyInstance->removeWidth();
123 $companyInstance->removeHeight();
124 $companyInstance->removeLength();
125 $companyInstance->removeDraught();
126 $companyInstance->removePartInstance();
128 // Instanz zurueckgeben
129 return $companyInstance;
132 // Angestellten-Liste erstellen
133 private function createEmployeeList () {
134 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",
137 $this->getCompanyName()
139 $this->employeeList = new FrameworkArrayObject();
142 // Werftenliste erstellen
143 public function createShipyardList () {
144 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> erhält eine Werftsliste.<br />\n",
147 $this->getCompanyName()
149 $this->shipyardList = new FrameworkArrayObject();
152 // Auftragsliste erstellen
153 public function createContractList () {
154 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> erhält eine Auftragsliste.<br />\n",
157 $this->getCompanyName()
159 $this->contractList = new FrameworkArrayObject();
162 // Setter-Methode fuer Firmennamen
163 public final function setCompanyName ($companyName) {
164 $this->companyName = (string) $companyName;
167 // Getter-Methode fuer Firmennamen
168 public final function getCompanyName () {
169 return $this->companyName;
172 // Setter-Methode fuer Firmensitz
173 public final function setHQInstance (Harbor $hqInstance) {
174 $this->hqInstance = $hqInstance;
178 private function createShortName () {
179 // Mindestens eine Leerstelle?
180 $dummy = explode(" ", $this->getCompanyName());
181 foreach ($dummy as $part) {
182 $this->shortName .= substr($part, 0, 1);
186 // Reedereien Werften bauen lassen
187 public function createShipyardInHarbor($shipyardName, Harbor $harborInstance) {
188 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",
191 $this->getCompanyName(),
192 $harborInstance->getHarborName(),
196 // Wird im HQ gebaut?
197 if ($this->hqInstance->equals($harborInstance)) {
198 // Die neue Werft wird im HQ gebaut!
199 $this->hqInstance->addNewShipyardNotify($shipyardName, $this);
200 // Die Werft drueber in Kenntnis setzen, welcher Reederei sie angehoert
202 // Ausserhalb des Heimathafens soll eine Werft gebaut werden
203 $harborInstance->addNewShipyardNotify($shipyardName, $this);
207 // Setter fuer Reederei-Gruender
208 public final function setCompanyFounder(CompanyEmployee $founderInstance) {
209 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",
212 $this->getCompanyName(),
213 $founderInstance->getSurname(),
214 $founderInstance->getFamily()
216 $this->founderInstance = $founderInstance;
219 // Getter for founder instance
220 public final function getFounderInstance () {
221 return $this->founderInstance;
224 // Neue(n) Angestellte(n) in Angestellten-Liste aufnehmen
225 public function addNewEmployee (SimulatorPersonell $employeeInstance) {
226 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",
229 $employeeInstance->getSurname(),
230 $employeeInstance->getFamily(),
231 $this->getCompanyName(),
232 $employeeInstance->getObjectDescription(),
233 $this->formatCurrency($employeeInstance->getSalary())
235 $this->employeeList->append($employeeInstance);
238 // Neue Werft in Liste aufnehmen
239 public function addNewShipyard (Shipyard $shipyardInstance) {
240 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",
243 $this->getCompanyName(),
244 $shipyardInstance->getShipyardName()
246 $this->shipyardList->append($shipyardInstance);
249 // Neue Mitarbeiter per Zufall einstellen/rekrutieren
250 public function recruitRandomEmployees($amount, SimulatorPersonell $personellInstance) {
251 // Anzahl Mitarbeiter absichern
252 $amount = (int) $amount;
254 // Debug-Meldung ausgeben
255 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",
258 $this->getCompanyName(),
262 // Gesamtanzahl verfuegbarer Erwerbsloser holen
263 $totalUnemployed = $personellInstance->getAllUnemployed();
265 // Existiert die gewuenschte Anzahl freier Arbeiter? (doppelt geht derzeit nicht)
266 if ($totalUnemployed < $amount) {
267 // Reichte nicht aus!
268 throw new ToMuchEmployeesException(array($amount, $personellInstance->getAllUnemployed()), self::EXCEPTION_NOT_ENOUGTH_UNEMPLOYEES);
271 // Get list for all unemployed people
272 $list = $personellInstance->getSpecialPersonellList(false); // Should be cached
274 // Get iterator of the list
275 $iterator = $list->getIterator();
277 // Get the requested amount of personell
278 for ($idx = 0; $idx < $amount; $idx++) {
280 // Is this personl unemployed?
281 while (is_null($employee) || $employee->isEmployed()) {
282 // Generate random number
283 $pos = mt_rand(0, ($totalUnemployed - 1)); // Don't remove the -1 here:
284 // E.g. 100 entries means latest position is 99...
286 // Seek for the position
287 $iterator->seek($pos);
289 // Is the current position valid?
290 if ($iterator->valid()) {
292 $employee = $iterator->current();
294 // Should normally not happen... :(
295 throw new StructuresOutOfBoundsException($idx, self::EXCEPTION_INDEX_OUT_OF_BOUNDS);
299 // A dummy just for the description and real class
300 $dummy = CompanyEmployee::createCompanyEmployee("", "", "M", 1970, 1, 1, $employee->isMarried(), 0);
302 // Make this person employed and give him some money to work
303 $employee->setEmployed(true);
304 $employee->setObjectDescription($dummy->getObjectDescription());
305 $employee->setRealClass($dummy->__toString());
306 $employee->increaseSalary((mt_rand(7, 14) * 100)); // Are 700 to 1400 EUR for the begin okay?
309 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",
312 $this->getCompanyName(),
313 $employee->getSurname(),
314 $employee->getFamily()
318 $this->addNewEmployee($employee);
322 $personellInstance->resetCache();
324 // Debug-Meldung ausgeben
325 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",
328 $this->getCompanyName(),
333 // Distribute all personells on all shipyards
334 public function distributeAllPersonellOnShipyards () {
335 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",
338 $this->getCompanyName(),
339 $this->getTotalEmployee(),
340 $this->getTotalShipyards()
343 // Do we have some shipyards?
344 if (is_null($this->shipyardList)) {
345 // No shipyards created
346 throw new NoShipyardsConstructedException($this, self::EXCEPTION_HARBOR_HAS_NO_SHIPYARDS);
349 // Get iterator for shipyards
350 $shipyardIter = $this->shipyardList->getIterator();
352 // Iterate through all employees
353 for ($idx = $this->employeeList->getIterator(); $idx->valid(); $idx->next()) {
354 // Is the shipyard iterator still okay?
355 if (!$shipyardIter->valid()) {
356 // Rewind to first position
357 $shipyardIter->seek(0);
360 // Get Shipyard object
361 $shipyard = $shipyardIter->current();
363 // Is this a Shipyard object?
364 if (is_null($shipyard)) {
366 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
367 } elseif (!is_object($shipyard)) {
368 // Not an object! ;-(
369 throw new NoObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
370 } elseif (!$shipyard->isClass("Shipyard")) {
371 // Nope, so throw exception
372 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
375 // Add employee to the shipyard
376 $shipyard->addNewPersonell($idx->current());
378 // Continue to next shipyard
379 $shipyardIter->next();
383 // Getter for total employees
384 public final function getTotalEmployee () {
386 $total = $this->employeeList->count();
389 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",
392 $this->getCompanyName(),
400 // Getter for total shipyards
401 public final function getTotalShipyards () {
402 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",
405 $this->getCompanyName()
408 // Do we have some shipyards?
409 if (is_null($this->shipyardList)) {
410 // No shipyards created
411 throw new NoShipyardsConstructedException($this, self::EXCEPTION_HARBOR_HAS_NO_SHIPYARDS);
415 $total = $this->shipyardList->count();
418 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",
421 $this->getCompanyName(),
429 // Add a ship type (class) to all shipyards
430 public function addShipTypeToAllShipyards ($shipType) {
432 $shipType = (string) $shipType;
434 // Is the class there?
435 if (!class_exists($shipType)) {
437 throw new ClassNotFoundException($shipType, 0);
441 eval(sprintf("\$shipInstance = %s::create%s(\"M/S Dummy\");",
447 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",
450 $this->getCompanyName(),
451 $shipInstance->getObjectDescription()
454 // Iterate shipyard list
455 for ($idx = $this->shipyardList->getIterator(); $idx->valid(); $idx->next()) {
456 // Get current element
457 $shipyard = $idx->current();
459 // Is this a shipyard?
460 if (is_null($shipyard)) {
462 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
463 } elseif (!is_object($shipyard)) {
464 // Not an object! ;-(
465 throw new NoObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
466 } elseif (!$shipyard->isClass("Shipyard")) {
467 // Class is not a shipyard
468 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
471 // Add the new ship type to the shipyard
472 $shipyard->addNewConstructableShipType($shipType);
476 // Validate the requested ship type with the company if they can construct it
477 public function validateWorksContractShipType (SignableContract $contractInstance) {
478 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",
481 $this->getCompanyName(),
482 $contractInstance->getShipName()
485 // First get the ship type
486 $shipInstance = $contractInstance->getShipInstance();
488 // Ist there a ship instance?
489 if (is_null($shipInstance)) {
490 // Opps! Empty entry?
491 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
492 } elseif (!is_object($shipInstance)) {
493 // Not an object! ;-(
494 throw new NoObjectException($shipInstance, self::EXCEPTION_IS_NO_OBJECT);
497 // Get it's real class name
498 $shipType = $shipInstance->__toString();
501 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",
504 $this->getCompanyName(),
505 $contractInstance->getShipName(),
506 $shipInstance->getObjectDescription()
509 // Now check if the ship type is in any list and return the result
510 return ($this->isShipTypeConstructable($shipType));
513 // Is the ship type constructable?
514 public function isShipTypeConstructable ($shipType) {
515 // The type must be a string!
516 $shipType = (string) $shipType;
519 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",
522 $this->getCompanyName(),
526 // First everthing is failed...
529 // Iterate through all shipyards
530 for ($idx = $this->shipyardList->getIterator(); $idx->valid(); $idx->next()) {
531 // Get current Shipyard instance
532 $shipyard = $idx->current();
534 // Is this a shipyard?
535 if (is_null($shipyard)) {
537 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
538 } elseif (!is_object($shipyard)) {
539 // Not an object! ;-(
540 throw new NoObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
541 } elseif (!$shipyard->isClass("Shipyard")) {
542 // Class is not a shipyard
543 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
546 // Validate if the first found shipyard can construct the requested type
547 $result = $shipyard->isShipTypeConstructable($shipType);
549 // Does this shipyard construct the requested ship type?
550 if ($result) break; // Then abort the search!
554 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",
557 $this->getCompanyName(),
565 // As a customer the shipping company can add new contracts
566 public function addNewWorksContract (SignableContract $contractInstance) {
567 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",
570 $this->getCompanyName(),
571 $contractInstance->getShipInstance()->getObjectDescription(),
572 $contractInstance->getShipInstance()->getShipName()
574 $this->contractList->append($contractInstance);
577 // As a customer the shippng company can withdraw from a contract
578 public function withdrawFromContract (SignableContract $contractInstance) {
579 ApplicationEntryPoint::app_die("WITHDRAW:<pre>".print_r($contractInstance, true)."</pre>");
582 // Get latest added contract instance
583 public final function getLastContractInstance () {
585 $iter = $this->contractList->getIterator();
587 // Get latest entry (total - 1)
588 $iter->seek($iter->count() - 1);
591 return $iter->current();
594 // Sign a contract with an other party which must also implement Customer
595 public function signContract (SignableContract $contractInstance, ContractPartner $partnerInstance) {
596 // Check wether the other party is our contract partner
597 if (!$partnerInstance->isContractPartner($contractInstance)) {
598 // Invalid contract partner!
599 throw new InvalidContractPartnerException($partnerInstance, self::EXCEPTION_CONTRACT_PARTNER_INVALID);
602 // Determine if company "signs" own contract (must be done) or with an other party
603 if ($this->equals($partnerInstance)) {
605 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",
608 $this->getCompanyName(),
609 $contractInstance->getShipInstance()->getObjectDescription(),
610 $contractInstance->getShipInstance()->getShipName()
613 // Other external company
614 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",
617 $this->getCompanyName(),
618 $contractInstance->getShipInstance()->getObjectDescription(),
619 $contractInstance->getShipInstance()->getShipName(),
620 $partnerInstance->getCompanyName()
625 $contractInstance->signContract($this, $partnerInstance);
628 * @todo Maybe do something more here...
632 // Is this the right contract partner?
633 public function isContractPartner (SignableContract $contractInstance) {
634 // Get contract partner instance and compare it with $this contract partner
635 return ($this->equals($contractInstance->getContractPartner()));
638 // Setter for merchant instance
639 public final function setMerchantInstance (Merchant $merchantInstance) {
641 $contractInstance = $this->getLastContractInstance();
643 if (is_null($contractInstance)) {
644 // Opps! Empty contract instance?
645 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
646 } elseif (!is_object($contractInstance)) {
647 // Not an object! ;-(
648 throw new NoObjectException($contractInstance, self::EXCEPTION_IS_NO_OBJECT);
649 } elseif (!$contractInstance->isClass('WorksContract')) {
651 throw new ClassMismatchException(array($contractInstance->__toString(), "WorksContract"), self::EXCEPTION_CLASSES_NOT_MATCHING);
654 // Set the merchant in the contract (for getting prices)
655 $contractInstance->setMerchantInstance($merchantInstance);
661 public function saveObjectToDatabase () {
662 $this->getDebugInstance()->output(sprintf("[%s:] Stub <strong>%s</strong> erreicht.",
669 * Limits this object with an ObjectLimits instance
671 public function limitObject (ObjectLimits $limitInstance) {
672 ApplicationEntryPoint::app_die("".__METHOD__." reached! Stub!");