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, 2009 Ship-Simu Developer Team
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__);
79 * Creates an instance of this company class or throws an exception if the
80 * given user owns no company.
82 * @param $userInstance A user class
83 * @return $companyInstance Prepared company instance
84 * @todo Add functionality if user participates in a company
86 public final static function createShippingCompany (ManageableAccount $userInstance) {
88 $companyInstance = new ShippingCompany();
90 // Does the given user owns a company?
91 if ($companyInstance->ifUserParticipatesInCompany($userInstance)) {
92 // Then do some nasty caching here but don't throw an exception
93 // because then you will hurt our web helpers... :/
94 $companyInstance->partialStub("Don't throw exceptions here.");
98 $companyInstance->initCompanyLists();
101 return $companyInstance;
105 * Checks wether the given user participates in a company
107 * @param $userInstance An instance of a user class
108 * @return $participates Wether the user participates at lease in one company
110 protected function ifUserParticipatesInCompany (ManageableAccount $userInstance) {
111 // By default no user owns any company... ;)
112 $participates = false;
114 // Get a company database wrapper class
115 $wrapperInstance = ObjectFactory::createObjectByConfiguredName('company_db_wrapper_class', array($this));
117 // Ask the wrapper if this user participates
118 $participates = $wrapperInstance->ifUserParticipatesInCompany($userInstance);
120 // Get the result instance
121 $resultInstance = $wrapperInstance->getResultInstance();
123 // Caches the result instance here, if set (we don't the wrapper anymore!)
124 if ($resultInstance instanceof SearchableResult) {
125 // Set the result instance
126 $this->setResultInstance($resultInstance);
130 return $participates;
134 * Checks wether the current user in registry is the company founder
136 * @return $isFounder Wether the current user is the company founder
137 * @todo Check if user is company founder
139 public function ifUserIsFounder () {
140 // Default is not the founder
143 // Get result instance
144 $resultInstance = $this->getResultInstance();
147 if ($resultInstance instanceof SearchableResult) {
148 // Result found so analyse it
149 $this->partialStub("Check if user is company founder.");
157 * Checks wether the current user in registry is the company owner
159 * @return $isOwner Wether the current user is the company owner
160 * @todo Check if user is company owner
162 public function ifUserIsOwner () {
163 // Default is not the owner
166 // Get result instance
167 $resultInstance = $this->getResultInstance();
170 if ($resultInstance instanceof SearchableResult) {
171 // Result found so analyse it
172 $this->partialStub("Check if user is company owner.");
180 * Checks wether the current user in registry is an employee in this company
182 * @return $isOwner Wether the current user is an employee in this company
184 public function ifUserIsEmployee () {
185 // Default is no employee
188 // Get result instance
189 $resultInstance = $this->getResultInstance();
192 if ($resultInstance instanceof SearchableResult) {
193 // Result found so he is employee
201 //------------------------------------------------------------------------------\
202 // Below here is very old code which needs to be translated and changed heavily |
203 //------------------------------------------------------------------------------/
206 * Intialize all lists
209 * @todo Maybe we don't need these big lists anymore?! So we can deprecate/remove it
211 protected function initCompanyLists () {
213 $this->employeeList = new FrameworkArrayObject("FakedEmployeeList");
216 $this->shipyardList = new FrameworkArrayObject("FakedShipyardList");
219 $this->contractList = new FrameworkArrayObject("FakedContractList");
222 // Setter-Methode fuer Firmennamen
223 public final function setCompanyName ($companyName) {
224 $this->companyName = (string) $companyName;
227 // Getter-Methode fuer Firmennamen
228 public final function getCompanyName () {
229 return $this->companyName;
232 // Setter-Methode fuer Firmensitz
233 public final function setHQInstance (Harbor $hqInstance) {
234 $this->hqInstance = $hqInstance;
238 private function initShortName () {
239 // Mindestens eine Leerstelle?
240 $dummy = explode(" ", $this->getCompanyName());
241 foreach ($dummy as $part) {
242 $this->shortName .= substr($part, 0, 1);
246 // Reedereien Werften bauen lassen
247 public function createShipyardInHarbor($shipyardName, Harbor $harborInstance) {
248 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->debugOutput(sprintf("[%s:%d] Die Reederei <strong>%s</strong> baut im <strong>%s</strong> eine Werft <strong>%s</strong>.",
251 $this->getCompanyName(),
252 $harborInstance->getHarborName(),
256 // Wird im HQ gebaut?
257 if ($this->hqInstance->equals($harborInstance)) {
258 // Die neue Werft wird im HQ gebaut!
259 $this->hqInstance->addNewShipyardNotify($shipyardName, $this);
260 // Die Werft drueber in Kenntnis setzen, welcher Reederei sie angehoert
262 // Ausserhalb des Heimathafens soll eine Werft gebaut werden
263 $harborInstance->addNewShipyardNotify($shipyardName, $this);
267 // Setter fuer Reederei-Gruender
268 public final function setCompanyFounder(CompanyEmployee $founderInstance) {
269 $this->founderInstance = $founderInstance;
272 // Getter for founder instance
273 public final function getFounderInstance () {
274 return $this->founderInstance;
277 // Neue(n) Angestellte(n) in Angestellten-Liste aufnehmen
278 public function addNewEmployee (SimulatorPersonell $employeeInstance) {
279 $this->employeeList->append($employeeInstance);
282 // Neue Werft in Liste aufnehmen
283 public function addNewShipyard (Shipyard $shipyardInstance) {
284 $this->shipyardList->append($shipyardInstance);
287 // Neue Mitarbeiter per Zufall einstellen/rekrutieren
288 public function recruitRandomEmployees($amount, SimulatorPersonell $personellInstance) {
289 // Anzahl Mitarbeiter absichern
290 $amount = (int) $amount;
292 // Debug-Meldung ausgeben
293 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->debugOutput(sprintf("[%s:%d] Die Reederei <strong>%s</strong> stellt per Zufall <strong>%d</strong> neue Mitarbeiter ein.",
296 $this->getCompanyName(),
300 // Gesamtanzahl verfuegbarer Erwerbsloser holen
301 $totalUnemployed = $personellInstance->getAllUnemployed();
303 // Existiert die gewuenschte Anzahl freier Arbeiter? (doppelt geht derzeit nicht)
304 if ($totalUnemployed < $amount) {
305 // Reichte nicht aus!
306 throw new ToMuchEmployeesException(array($amount, $personellInstance->getAllUnemployed()), self::EXCEPTION_NOT_ENOUGTH_UNEMPLOYEES);
309 // Get list for all unemployed people
310 $list = $personellInstance->getSpecialPersonellList(false); // Should be cached
312 // Get iterator of the list
313 $iterator = $list->getIterator();
315 // Get the requested amount of personell
316 for ($idx = 0; $idx < $amount; $idx++) {
318 // Is this personl unemployed?
319 while (is_null($employee) || $employee->isEmployed()) {
320 // Generate random number
321 $pos = mt_rand(0, ($totalUnemployed - 1)); // Don't remove the -1 here:
322 // E.g. 100 entries means latest position is 99...
324 // Seek for the position
325 $iterator->seek($pos);
327 // Is the current position valid?
328 if ($iterator->valid() === false) {
329 // Should normally not happen... :(
330 throw new StructuresOutOfBoundsException($idx, self::EXCEPTION_INDEX_OUT_OF_BOUNDS);
333 // Get current element
334 $employee = $iterator->current();
337 // A dummy just for the description and real class
338 $dummy = CompanyEmployee::createCompanyEmployee("", "", "M", 1970, 1, 1, $employee->isMarried(), 0);
340 // Make this person employed and give him some money to work
341 $employee->setEmployed(true);
342 $employee->setRealClass($dummy->__toString());
343 $employee->increaseSalary((mt_rand(7, 14) * 100)); // Are 700 to 1400 EUR for the begin okay?
346 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->debugOutput(sprintf("[%s:%d] Die Reederei <strong>%s</strong> stellt den/die Angestellte(n) <strong>%s %s</strong> ein.",
349 $this->getCompanyName(),
350 $employee->getSurname(),
351 $employee->getFamily()
355 $this->addNewEmployee($employee);
359 $personellInstance->resetCache();
361 // Debug-Meldung ausgeben
362 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->debugOutput(sprintf("[%s:%d] Die Reederei <strong>%s</strong> hat per Zufall <strong>%d</strong> neue Mitarbeiter eingestellt.",
365 $this->getCompanyName(),
370 // Distribute all personells on all shipyards
371 public function distributeAllPersonellOnShipyards () {
372 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->debugOutput(sprintf("[%s:%d] Die Reederei <strong>%s</strong> verteilt alle ihre <strong>%d</strong> Mitarbeiter auf alle <strong>%d</strong> Werft(en).",
375 $this->getCompanyName(),
376 $this->getTotalEmployee(),
377 $this->getTotalShipyards()
380 // Do we have some shipyards?
381 if (is_null($this->shipyardList)) {
382 // No shipyards created
383 throw new NoShipyardsConstructedException($this, self::EXCEPTION_HARBOR_HAS_NO_SHIPYARDS);
386 // Get iterator for shipyards
387 $shipyardIter = $this->shipyardList->getIterator();
389 // Iterate through all employees
390 for ($idx = $this->employeeList->getIterator(); $idx->valid(); $idx->next()) {
391 // Is the shipyard iterator still okay?
392 if ($shipyardIter->valid() === false) {
393 // Rewind to first position
394 $shipyardIter->seek(0);
397 // Get Shipyard object
398 $shipyard = $shipyardIter->current();
400 // Is this a Shipyard object?
401 if (is_null($shipyard)) {
403 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
404 } elseif (!is_object($shipyard)) {
405 // Not an object! ;-(
406 throw new InvalidObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
407 } elseif ($shipyard->isClass("Shipyard") === false) {
408 // Nope, so throw exception
409 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
412 // Add employee to the shipyard
413 $shipyard->addNewPersonell($idx->current());
415 // Continue to next shipyard
416 $shipyardIter->next();
420 // Getter for total employees
421 public final function getTotalEmployee () {
423 $total = $this->employeeList->count();
426 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->debugOutput(sprintf("[%s:%d] Die Reederei <strong>%s</strong> hat <strong>%d</strong> Mitarbeiter.",
429 $this->getCompanyName(),
437 // Getter for total shipyards
438 public final function getTotalShipyards () {
439 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->debugOutput(sprintf("[%s:%d] Für die Reederei <strong>%s</strong> werden die Anzahl der Werften in allen Häfen ermittelt.",
442 $this->getCompanyName()
445 // Do we have some shipyards?
446 if (is_null($this->shipyardList)) {
447 // No shipyards created
448 throw new NoShipyardsConstructedException($this, self::EXCEPTION_HARBOR_HAS_NO_SHIPYARDS);
452 $total = $this->shipyardList->count();
455 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->debugOutput(sprintf("[%s:%d] Die Reederei <strong>%s</strong> hat <strong>%d</strong> Werft(en).",
458 $this->getCompanyName(),
466 // Add a ship type (class) to all shipyards
467 public function addShipTypeToAllShipyards ($shipType) {
469 $shipType = (string) $shipType;
471 // Is the class there?
472 if (!class_exists($shipType)) {
474 throw new ClassNotFoundException($shipType, self::EXCEPTION_CLASS_NOT_FOUND);
478 eval(sprintf("\$shipInstance = %s::create%s(\"M/S Dummy\");",
483 // Iterate shipyard list
484 for ($idx = $this->shipyardList->getIterator(); $idx->valid(); $idx->next()) {
485 // Get current element
486 $shipyard = $idx->current();
488 // Is this a shipyard?
489 if (is_null($shipyard)) {
491 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
492 } elseif (!is_object($shipyard)) {
493 // Not an object! ;-(
494 throw new InvalidObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
495 } elseif ($shipyard->isClass("Shipyard") === false) {
496 // Class is not a shipyard
497 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
500 // Add the new ship type to the shipyard
501 $shipyard->addNewConstructableShipType($shipType);
505 // Validate the requested ship type with the company if they can construct it
506 public function validateWorksContractShipType (SignableContract $contractInstance) {
507 // First get the ship type
508 $shipInstance = $contractInstance->getShipInstance();
510 // Ist there a ship instance?
511 if (is_null($shipInstance)) {
512 // Opps! Empty entry?
513 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
514 } elseif (!is_object($shipInstance)) {
515 // Not an object! ;-(
516 throw new InvalidObjectException($shipInstance, self::EXCEPTION_IS_NO_OBJECT);
519 // Get it's real class name
520 $shipType = $shipInstance->__toString();
522 // Now check if ship type is in any list and return the result
523 return ($this->isShipTypeConstructable($shipType));
526 // Is the ship type constructable?
527 public function isShipTypeConstructable ($shipType) {
528 // The type must be a string!
529 $shipType = (string) $shipType;
532 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->debugOutput(sprintf("[%s:%d] Die Reederei <strong>%s</strong> fragt alle Werften ab, ob diese Schiffe vom Typ <strong>%s</strong> bauen können.",
535 $this->getCompanyName(),
539 // First everthing is failed...
542 // Iterate through all shipyards
543 for ($idx = $this->shipyardList->getIterator(); $idx->valid(); $idx->next()) {
544 // Get current Shipyard instance
545 $shipyard = $idx->current();
547 // Is this a shipyard?
548 if (is_null($shipyard)) {
550 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
551 } elseif (!is_object($shipyard)) {
552 // Not an object! ;-(
553 throw new InvalidObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
554 } elseif ($shipyard->isClass("Shipyard") === false) {
555 // Class is not a shipyard
556 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
559 // Validate if first found shipyard can construct the requested type
560 $result = $shipyard->isShipTypeConstructable($shipType);
562 // Does this shipyard construct the requested ship type?
563 if ($result) break; // Then abort the search!
567 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->debugOutput(sprintf("[%s:%d] Die Reederei <strong>%s</strong> hat die Suche nach einer Werft beendet, die Schiffe vom Typ <strong>%s</strong> bauen kann.",
570 $this->getCompanyName(),
578 // As a customer the shipping company can add new contracts
579 public function addNewWorksContract (SignableContract $contractInstance) {
580 $this->contractList->append($contractInstance);
583 // As a customer the shippng company can withdraw from a contract
584 public function withdrawFromContract (SignableContract $contractInstance) {
585 ApplicationEntryPoint::app_die("WITHDRAW:<pre>".print_r($contractInstance, true)."</pre>");
588 // Get latest added contract instance
589 public final function getLastContractInstance () {
591 $iter = $this->contractList->getIterator();
593 // Get latest entry (total - 1)
594 $iter->seek($iter->count() - 1);
597 return $iter->current();
600 // Sign a contract with an other party which must also implement Customer
601 public function signContract (SignableContract $contractInstance, ContractPartner $partnerInstance) {
602 // Check wether the other party is our contract partner
603 if ($partnerInstance->isContractPartner($contractInstance) === false) {
604 // Invalid contract partner!
605 throw new InvalidContractPartnerException($partnerInstance, self::EXCEPTION_CONTRACT_PARTNER_INVALID);
608 // Determine if company "signs" own contract (must be done) or with an other party
609 if ($this->equals($partnerInstance)) {
611 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->debugOutput(sprintf("[%s:%d] Die Reederei <strong>%s</strong> erteilt an sich selbst einen Bauauftrag für das <strong>%s</strong> "<strong>%s</strong>".",
614 $this->getCompanyName(),
615 $contractInstance->getShipInstance()->getObjectDescription(),
616 $contractInstance->getShipInstance()->getShipName()
619 // Other external company
620 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->debugOutput(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>.",
623 $this->getCompanyName(),
624 $contractInstance->getShipInstance()->getObjectDescription(),
625 $contractInstance->getShipInstance()->getShipName(),
626 $partnerInstance->getCompanyName()
631 $contractInstance->signContract($this, $partnerInstance);
634 * @todo Maybe do something more here...
638 // Is this the right contract partner?
639 public function isContractPartner (SignableContract $contractInstance) {
640 // Get contract partner instance and compare it with $this contract partner
641 return ($this->equals($contractInstance->getContractPartner()));
644 // Setter for merchant instance
645 public final function setMerchantInstance (Merchant $merchantInstance) {
647 $contractInstance = $this->getLastContractInstance();
649 if (is_null($contractInstance)) {
650 // Opps! Empty contract instance?
651 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
652 } elseif (!is_object($contractInstance)) {
653 // Not an object! ;-(
654 throw new InvalidObjectException($contractInstance, self::EXCEPTION_IS_NO_OBJECT);
655 } elseif ($contractInstance->isClass("WorksContract") === false) {
657 throw new ClassMismatchException(array($contractInstance->__toString(), "WorksContract"), self::EXCEPTION_CLASSES_NOT_MATCHING);
660 // Set the merchant in the contract (for getting prices)
661 $contractInstance->setMerchantInstance($merchantInstance);