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 * Headquarter harbor instance
43 private $hqInstance = null;
46 * Employed people by this company
48 private $employeeList = 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;
65 // Exception constants
66 const EXCEPTION_USER_OWNS_NO_COMPANY = 0x200;
69 * Protected constructor
73 protected function __construct () {
74 // Call parent constructor
75 parent::__construct(__CLASS__);
78 $this->setObjectDescription("A shipping company class");
80 // Generate unique ID number
81 $this->generateUniqueId();
84 $this->removeSystemArray();
88 * Creates an instance of this company class or throws an exception if the
89 * given user owns no company.
91 * @param $userInstance A user class
92 * @return $companyInstance Prepared company instance
94 public final static function createShippingCompany (BaseUser $userInstance) {
96 $companyInstance = new ShippingCompany();
98 // Does the given user owns a company?
99 if ($companyInstance->ifUserParticipatesInCompany($userInstance)) {
100 // Then do some nastly caching here but don't throw an exception
101 // because then you will hurt our web helpers... :/
102 $companyInstance->partialStub("Don't throw exceptions here.");
106 $companyInstance->initCompanyLists();
109 return $companyInstance;
113 * Checks wether the given user participates in a company
115 * @param $userInstance An instance of a user class
116 * @return $participates Wether the user participates at lease in one company
118 protected function ifUserParticipatesInCompany (BaseUser $userInstance) {
119 // By default no user owns any company... ;)
120 $participates = false;
122 // Get a company database wrapper class
123 $wrapperInstance = ObjectFactory::createObjectByConfiguredName('company_db_wrapper_class');
125 // Ask the wrapper if this user participates
126 $participates = $wrapperInstance->ifUserParticipatesInCompany($userInstance);
128 // Get the result instance
129 $resultInstance = $wrapperInstance->getResultInstance();
131 // Caches the result instance here, if set (we don't the wrapper anymore!)
132 if ($resultInstance instanceof SearchableResult) {
133 // Set the result instance
134 $this->setResultInstance($resultInstance);
138 return $participates;
141 //----------------------------------------------------------------------------
142 // From here is very old code which needs to be translated and changed heavily
143 //----------------------------------------------------------------------------
146 * Intialize all lists
149 * @todo Maybe we don't need these big lists anymore?! So we can deprecate/remove it
151 protected function initCompanyLists () {
153 $this->employeeList = new FrameworkArrayObject("FakedEmployeeList");
156 $this->shipyardList = new FrameworkArrayObject("FakedShipyardList");
159 $this->contractList = new FrameworkArrayObject("FakedContractList");
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 initShortName () {
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>.",
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 $this->founderInstance = $founderInstance;
212 // Getter for founder instance
213 public final function getFounderInstance () {
214 return $this->founderInstance;
217 // Neue(n) Angestellte(n) in Angestellten-Liste aufnehmen
218 public function addNewEmployee (SimulatorPersonell $employeeInstance) {
219 $this->employeeList->append($employeeInstance);
222 // Neue Werft in Liste aufnehmen
223 public function addNewShipyard (Shipyard $shipyardInstance) {
224 $this->shipyardList->append($shipyardInstance);
227 // Neue Mitarbeiter per Zufall einstellen/rekrutieren
228 public function recruitRandomEmployees($amount, SimulatorPersonell $personellInstance) {
229 // Anzahl Mitarbeiter absichern
230 $amount = (int) $amount;
232 // Debug-Meldung ausgeben
233 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.",
236 $this->getCompanyName(),
240 // Gesamtanzahl verfuegbarer Erwerbsloser holen
241 $totalUnemployed = $personellInstance->getAllUnemployed();
243 // Existiert die gewuenschte Anzahl freier Arbeiter? (doppelt geht derzeit nicht)
244 if ($totalUnemployed < $amount) {
245 // Reichte nicht aus!
246 throw new ToMuchEmployeesException(array($amount, $personellInstance->getAllUnemployed()), self::EXCEPTION_NOT_ENOUGTH_UNEMPLOYEES);
249 // Get list for all unemployed people
250 $list = $personellInstance->getSpecialPersonellList(false); // Should be cached
252 // Get iterator of the list
253 $iterator = $list->getIterator();
255 // Get the requested amount of personell
256 for ($idx = 0; $idx < $amount; $idx++) {
258 // Is this personl unemployed?
259 while (is_null($employee) || $employee->isEmployed()) {
260 // Generate random number
261 $pos = mt_rand(0, ($totalUnemployed - 1)); // Don't remove the -1 here:
262 // E.g. 100 entries means latest position is 99...
264 // Seek for the position
265 $iterator->seek($pos);
267 // Is the current position valid?
268 if ($iterator->valid()) {
270 $employee = $iterator->current();
272 // Should normally not happen... :(
273 throw new StructuresOutOfBoundsException($idx, self::EXCEPTION_INDEX_OUT_OF_BOUNDS);
277 // A dummy just for the description and real class
278 $dummy = CompanyEmployee::createCompanyEmployee("", "", "M", 1970, 1, 1, $employee->isMarried(), 0);
280 // Make this person employed and give him some money to work
281 $employee->setEmployed(true);
282 $employee->setObjectDescription($dummy->getObjectDescription());
283 $employee->setRealClass($dummy->__toString());
284 $employee->increaseSalary((mt_rand(7, 14) * 100)); // Are 700 to 1400 EUR for the begin okay?
287 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.",
290 $this->getCompanyName(),
291 $employee->getSurname(),
292 $employee->getFamily()
296 $this->addNewEmployee($employee);
300 $personellInstance->resetCache();
302 // Debug-Meldung ausgeben
303 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.",
306 $this->getCompanyName(),
311 // Distribute all personells on all shipyards
312 public function distributeAllPersonellOnShipyards () {
313 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).",
316 $this->getCompanyName(),
317 $this->getTotalEmployee(),
318 $this->getTotalShipyards()
321 // Do we have some shipyards?
322 if (is_null($this->shipyardList)) {
323 // No shipyards created
324 throw new NoShipyardsConstructedException($this, self::EXCEPTION_HARBOR_HAS_NO_SHIPYARDS);
327 // Get iterator for shipyards
328 $shipyardIter = $this->shipyardList->getIterator();
330 // Iterate through all employees
331 for ($idx = $this->employeeList->getIterator(); $idx->valid(); $idx->next()) {
332 // Is the shipyard iterator still okay?
333 if (!$shipyardIter->valid()) {
334 // Rewind to first position
335 $shipyardIter->seek(0);
338 // Get Shipyard object
339 $shipyard = $shipyardIter->current();
341 // Is this a Shipyard object?
342 if (is_null($shipyard)) {
344 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
345 } elseif (!is_object($shipyard)) {
346 // Not an object! ;-(
347 throw new NoObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
348 } elseif (!$shipyard->isClass("Shipyard")) {
349 // Nope, so throw exception
350 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
353 // Add employee to the shipyard
354 $shipyard->addNewPersonell($idx->current());
356 // Continue to next shipyard
357 $shipyardIter->next();
361 // Getter for total employees
362 public final function getTotalEmployee () {
364 $total = $this->employeeList->count();
367 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> hat <strong>%d</strong> Mitarbeiter.",
370 $this->getCompanyName(),
378 // Getter for total shipyards
379 public final function getTotalShipyards () {
380 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.",
383 $this->getCompanyName()
386 // Do we have some shipyards?
387 if (is_null($this->shipyardList)) {
388 // No shipyards created
389 throw new NoShipyardsConstructedException($this, self::EXCEPTION_HARBOR_HAS_NO_SHIPYARDS);
393 $total = $this->shipyardList->count();
396 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> hat <strong>%d</strong> Werft(en).",
399 $this->getCompanyName(),
407 // Add a ship type (class) to all shipyards
408 public function addShipTypeToAllShipyards ($shipType) {
410 $shipType = (string) $shipType;
412 // Is the class there?
413 if (!class_exists($shipType)) {
415 throw new ClassNotFoundException($shipType, self::EXCEPTION_CLASS_NOT_FOUND);
419 eval(sprintf("\$shipInstance = %s::create%s(\"M/S Dummy\");",
425 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>.",
428 $this->getCompanyName(),
429 $shipInstance->getObjectDescription()
432 // Iterate shipyard list
433 for ($idx = $this->shipyardList->getIterator(); $idx->valid(); $idx->next()) {
434 // Get current element
435 $shipyard = $idx->current();
437 // Is this a shipyard?
438 if (is_null($shipyard)) {
440 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
441 } elseif (!is_object($shipyard)) {
442 // Not an object! ;-(
443 throw new NoObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
444 } elseif (!$shipyard->isClass("Shipyard")) {
445 // Class is not a shipyard
446 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
449 // Add the new ship type to the shipyard
450 $shipyard->addNewConstructableShipType($shipType);
454 // Validate the requested ship type with the company if they can construct it
455 public function validateWorksContractShipType (SignableContract $contractInstance) {
456 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>.",
459 $this->getCompanyName(),
460 $contractInstance->getShipName()
463 // First get the ship type
464 $shipInstance = $contractInstance->getShipInstance();
466 // Ist there a ship instance?
467 if (is_null($shipInstance)) {
468 // Opps! Empty entry?
469 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
470 } elseif (!is_object($shipInstance)) {
471 // Not an object! ;-(
472 throw new NoObjectException($shipInstance, self::EXCEPTION_IS_NO_OBJECT);
475 // Get it's real class name
476 $shipType = $shipInstance->__toString();
479 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.",
482 $this->getCompanyName(),
483 $contractInstance->getShipName(),
484 $shipInstance->getObjectDescription()
487 // Now check if the ship type is in any list and return the result
488 return ($this->isShipTypeConstructable($shipType));
491 // Is the ship type constructable?
492 public function isShipTypeConstructable ($shipType) {
493 // The type must be a string!
494 $shipType = (string) $shipType;
497 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.",
500 $this->getCompanyName(),
504 // First everthing is failed...
507 // Iterate through all shipyards
508 for ($idx = $this->shipyardList->getIterator(); $idx->valid(); $idx->next()) {
509 // Get current Shipyard instance
510 $shipyard = $idx->current();
512 // Is this a shipyard?
513 if (is_null($shipyard)) {
515 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
516 } elseif (!is_object($shipyard)) {
517 // Not an object! ;-(
518 throw new NoObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
519 } elseif (!$shipyard->isClass("Shipyard")) {
520 // Class is not a shipyard
521 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
524 // Validate if the first found shipyard can construct the requested type
525 $result = $shipyard->isShipTypeConstructable($shipType);
527 // Does this shipyard construct the requested ship type?
528 if ($result) break; // Then abort the search!
532 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.",
535 $this->getCompanyName(),
543 // As a customer the shipping company can add new contracts
544 public function addNewWorksContract (SignableContract $contractInstance) {
545 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>.",
548 $this->getCompanyName(),
549 $contractInstance->getShipInstance()->getObjectDescription(),
550 $contractInstance->getShipInstance()->getShipName()
552 $this->contractList->append($contractInstance);
555 // As a customer the shippng company can withdraw from a contract
556 public function withdrawFromContract (SignableContract $contractInstance) {
557 ApplicationEntryPoint::app_die("WITHDRAW:<pre>".print_r($contractInstance, true)."</pre>");
560 // Get latest added contract instance
561 public final function getLastContractInstance () {
563 $iter = $this->contractList->getIterator();
565 // Get latest entry (total - 1)
566 $iter->seek($iter->count() - 1);
569 return $iter->current();
572 // Sign a contract with an other party which must also implement Customer
573 public function signContract (SignableContract $contractInstance, ContractPartner $partnerInstance) {
574 // Check wether the other party is our contract partner
575 if (!$partnerInstance->isContractPartner($contractInstance)) {
576 // Invalid contract partner!
577 throw new InvalidContractPartnerException($partnerInstance, self::EXCEPTION_CONTRACT_PARTNER_INVALID);
580 // Determine if company "signs" own contract (must be done) or with an other party
581 if ($this->equals($partnerInstance)) {
583 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>".",
586 $this->getCompanyName(),
587 $contractInstance->getShipInstance()->getObjectDescription(),
588 $contractInstance->getShipInstance()->getShipName()
591 // Other external company
592 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>.",
595 $this->getCompanyName(),
596 $contractInstance->getShipInstance()->getObjectDescription(),
597 $contractInstance->getShipInstance()->getShipName(),
598 $partnerInstance->getCompanyName()
603 $contractInstance->signContract($this, $partnerInstance);
606 * @todo Maybe do something more here...
610 // Is this the right contract partner?
611 public function isContractPartner (SignableContract $contractInstance) {
612 // Get contract partner instance and compare it with $this contract partner
613 return ($this->equals($contractInstance->getContractPartner()));
616 // Setter for merchant instance
617 public final function setMerchantInstance (Merchant $merchantInstance) {
619 $contractInstance = $this->getLastContractInstance();
621 if (is_null($contractInstance)) {
622 // Opps! Empty contract instance?
623 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
624 } elseif (!is_object($contractInstance)) {
625 // Not an object! ;-(
626 throw new NoObjectException($contractInstance, self::EXCEPTION_IS_NO_OBJECT);
627 } elseif (!$contractInstance->isClass('WorksContract')) {
629 throw new ClassMismatchException(array($contractInstance->__toString(), "WorksContract"), self::EXCEPTION_CLASSES_NOT_MATCHING);
632 // Set the merchant in the contract (for getting prices)
633 $contractInstance->setMerchantInstance($merchantInstance);