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;
66 * Database result instance
68 private $resultInstance = null;
70 // Exception constants
71 const EXCEPTION_USER_OWNS_NO_COMPANY = 0x200;
74 * Protected constructor
78 protected function __construct () {
79 // Call parent constructor
80 parent::__construct(__CLASS__);
83 $this->setObjectDescription("A shipping company class");
85 // Generate unique ID number
86 $this->generateUniqueId();
89 $this->removeSystemArray();
93 * Creates an instance of this company class or throws an exception if the
94 * given user owns no company.
96 * @param $userInstance A user class
97 * @return $companyInstance Prepared company instance
98 * @throws NoShippingCompanyOwnedException If the user owns no shipping companies
100 public final static function createShippingCompany (BaseUser $userInstance) {
102 $companyInstance = new ShippingCompany();
104 // Does the given user owns a company?
105 if (!$companyInstance->ifUserOwnsShippingCompany($userInstance)) {
106 // Throw an exception here
107 throw new NoShippingCompanyOwnedException(array($companyInstance, $userInstance), self::EXCEPTION_USER_OWNS_NO_COMPANY);
110 // Set the user instance. We don't care here if he is founder or employee.
111 $companyInstance->setUserInstance($userInstance);
114 $companyInstance->initCompanyLists();
117 return $companyInstance;
121 * Checks wether the given user owns a company or not
123 * @param $userInstance An instance of a user class
124 * @return $ownsCompany Wether the user owns at least one company
126 protected function ifUserOwnsShippingCompany (BaseUser $userInstance) {
127 // By default no user owns any company... ;)
128 $ownsCompany = false;
130 // Get a company database wrapper class
131 $wrapperInstance = ObjectFactory::createObjectByConfiguredName('company_db_wrapper_class');
133 // Get a search criteria class
134 $criteriaInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class');
136 // Add the user primary key as a search criteria
137 $criteriaInstance->addCriteria('company_owner', $userInstance->getPrimaryKey());
138 $criteriaInstance->setLimit(1);
140 // Get the result back
141 $resultInstance = $wrapperInstance->doSelectByCriteria($criteriaInstance);
142 $resultInstance->debugInstance();
146 * Intialize all lists
150 protected function initCompanyLists () {
152 $this->employeeList = new FrameworkArrayObject("FakedEmployeeList");
155 $this->shipyardList = new FrameworkArrayObject("FakedShipyardList");
158 $this->contractList = new FrameworkArrayObject("FakedContractList");
161 //----------------------------------------------------------------------------
162 // From here is very old code which needs to be translated and changed heavily
163 //----------------------------------------------------------------------------
165 // Setter-Methode fuer Firmennamen
166 public final function setCompanyName ($companyName) {
167 $this->companyName = (string) $companyName;
170 // Getter-Methode fuer Firmennamen
171 public final function getCompanyName () {
172 return $this->companyName;
175 // Setter-Methode fuer Firmensitz
176 public final function setHQInstance (Harbor $hqInstance) {
177 $this->hqInstance = $hqInstance;
181 private function initShortName () {
182 // Mindestens eine Leerstelle?
183 $dummy = explode(" ", $this->getCompanyName());
184 foreach ($dummy as $part) {
185 $this->shortName .= substr($part, 0, 1);
189 // Reedereien Werften bauen lassen
190 public function createShipyardInHarbor($shipyardName, Harbor $harborInstance) {
191 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>.",
194 $this->getCompanyName(),
195 $harborInstance->getHarborName(),
199 // Wird im HQ gebaut?
200 if ($this->hqInstance->equals($harborInstance)) {
201 // Die neue Werft wird im HQ gebaut!
202 $this->hqInstance->addNewShipyardNotify($shipyardName, $this);
203 // Die Werft drueber in Kenntnis setzen, welcher Reederei sie angehoert
205 // Ausserhalb des Heimathafens soll eine Werft gebaut werden
206 $harborInstance->addNewShipyardNotify($shipyardName, $this);
210 // Setter fuer Reederei-Gruender
211 public final function setCompanyFounder(CompanyEmployee $founderInstance) {
212 $this->founderInstance = $founderInstance;
215 // Getter for founder instance
216 public final function getFounderInstance () {
217 return $this->founderInstance;
220 // Neue(n) Angestellte(n) in Angestellten-Liste aufnehmen
221 public function addNewEmployee (SimulatorPersonell $employeeInstance) {
222 $this->employeeList->append($employeeInstance);
225 // Neue Werft in Liste aufnehmen
226 public function addNewShipyard (Shipyard $shipyardInstance) {
227 $this->shipyardList->append($shipyardInstance);
230 // Neue Mitarbeiter per Zufall einstellen/rekrutieren
231 public function recruitRandomEmployees($amount, SimulatorPersonell $personellInstance) {
232 // Anzahl Mitarbeiter absichern
233 $amount = (int) $amount;
235 // Debug-Meldung ausgeben
236 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.",
239 $this->getCompanyName(),
243 // Gesamtanzahl verfuegbarer Erwerbsloser holen
244 $totalUnemployed = $personellInstance->getAllUnemployed();
246 // Existiert die gewuenschte Anzahl freier Arbeiter? (doppelt geht derzeit nicht)
247 if ($totalUnemployed < $amount) {
248 // Reichte nicht aus!
249 throw new ToMuchEmployeesException(array($amount, $personellInstance->getAllUnemployed()), self::EXCEPTION_NOT_ENOUGTH_UNEMPLOYEES);
252 // Get list for all unemployed people
253 $list = $personellInstance->getSpecialPersonellList(false); // Should be cached
255 // Get iterator of the list
256 $iterator = $list->getIterator();
258 // Get the requested amount of personell
259 for ($idx = 0; $idx < $amount; $idx++) {
261 // Is this personl unemployed?
262 while (is_null($employee) || $employee->isEmployed()) {
263 // Generate random number
264 $pos = mt_rand(0, ($totalUnemployed - 1)); // Don't remove the -1 here:
265 // E.g. 100 entries means latest position is 99...
267 // Seek for the position
268 $iterator->seek($pos);
270 // Is the current position valid?
271 if ($iterator->valid()) {
273 $employee = $iterator->current();
275 // Should normally not happen... :(
276 throw new StructuresOutOfBoundsException($idx, self::EXCEPTION_INDEX_OUT_OF_BOUNDS);
280 // A dummy just for the description and real class
281 $dummy = CompanyEmployee::createCompanyEmployee("", "", "M", 1970, 1, 1, $employee->isMarried(), 0);
283 // Make this person employed and give him some money to work
284 $employee->setEmployed(true);
285 $employee->setObjectDescription($dummy->getObjectDescription());
286 $employee->setRealClass($dummy->__toString());
287 $employee->increaseSalary((mt_rand(7, 14) * 100)); // Are 700 to 1400 EUR for the begin okay?
290 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.",
293 $this->getCompanyName(),
294 $employee->getSurname(),
295 $employee->getFamily()
299 $this->addNewEmployee($employee);
303 $personellInstance->resetCache();
305 // Debug-Meldung ausgeben
306 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.",
309 $this->getCompanyName(),
314 // Distribute all personells on all shipyards
315 public function distributeAllPersonellOnShipyards () {
316 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).",
319 $this->getCompanyName(),
320 $this->getTotalEmployee(),
321 $this->getTotalShipyards()
324 // Do we have some shipyards?
325 if (is_null($this->shipyardList)) {
326 // No shipyards created
327 throw new NoShipyardsConstructedException($this, self::EXCEPTION_HARBOR_HAS_NO_SHIPYARDS);
330 // Get iterator for shipyards
331 $shipyardIter = $this->shipyardList->getIterator();
333 // Iterate through all employees
334 for ($idx = $this->employeeList->getIterator(); $idx->valid(); $idx->next()) {
335 // Is the shipyard iterator still okay?
336 if (!$shipyardIter->valid()) {
337 // Rewind to first position
338 $shipyardIter->seek(0);
341 // Get Shipyard object
342 $shipyard = $shipyardIter->current();
344 // Is this a Shipyard object?
345 if (is_null($shipyard)) {
347 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
348 } elseif (!is_object($shipyard)) {
349 // Not an object! ;-(
350 throw new NoObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
351 } elseif (!$shipyard->isClass("Shipyard")) {
352 // Nope, so throw exception
353 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
356 // Add employee to the shipyard
357 $shipyard->addNewPersonell($idx->current());
359 // Continue to next shipyard
360 $shipyardIter->next();
364 // Getter for total employees
365 public final function getTotalEmployee () {
367 $total = $this->employeeList->count();
370 if ((defined('DEBUG_COMPANY_EMPLOYEE')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> hat <strong>%d</strong> Mitarbeiter.",
373 $this->getCompanyName(),
381 // Getter for total shipyards
382 public final function getTotalShipyards () {
383 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.",
386 $this->getCompanyName()
389 // Do we have some shipyards?
390 if (is_null($this->shipyardList)) {
391 // No shipyards created
392 throw new NoShipyardsConstructedException($this, self::EXCEPTION_HARBOR_HAS_NO_SHIPYARDS);
396 $total = $this->shipyardList->count();
399 if ((defined('DEBUG_COMPANY')) || (defined('DEBUG_ALL'))) $this->getDebugInstance()->output(sprintf("[%s:%d] Die Reederei <strong>%s</strong> hat <strong>%d</strong> Werft(en).",
402 $this->getCompanyName(),
410 // Add a ship type (class) to all shipyards
411 public function addShipTypeToAllShipyards ($shipType) {
413 $shipType = (string) $shipType;
415 // Is the class there?
416 if (!class_exists($shipType)) {
418 throw new ClassNotFoundException($shipType, self::EXCEPTION_CLASS_NOT_FOUND);
422 eval(sprintf("\$shipInstance = %s::create%s(\"M/S Dummy\");",
428 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>.",
431 $this->getCompanyName(),
432 $shipInstance->getObjectDescription()
435 // Iterate shipyard list
436 for ($idx = $this->shipyardList->getIterator(); $idx->valid(); $idx->next()) {
437 // Get current element
438 $shipyard = $idx->current();
440 // Is this a shipyard?
441 if (is_null($shipyard)) {
443 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
444 } elseif (!is_object($shipyard)) {
445 // Not an object! ;-(
446 throw new NoObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
447 } elseif (!$shipyard->isClass("Shipyard")) {
448 // Class is not a shipyard
449 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
452 // Add the new ship type to the shipyard
453 $shipyard->addNewConstructableShipType($shipType);
457 // Validate the requested ship type with the company if they can construct it
458 public function validateWorksContractShipType (SignableContract $contractInstance) {
459 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>.",
462 $this->getCompanyName(),
463 $contractInstance->getShipName()
466 // First get the ship type
467 $shipInstance = $contractInstance->getShipInstance();
469 // Ist there a ship instance?
470 if (is_null($shipInstance)) {
471 // Opps! Empty entry?
472 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
473 } elseif (!is_object($shipInstance)) {
474 // Not an object! ;-(
475 throw new NoObjectException($shipInstance, self::EXCEPTION_IS_NO_OBJECT);
478 // Get it's real class name
479 $shipType = $shipInstance->__toString();
482 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.",
485 $this->getCompanyName(),
486 $contractInstance->getShipName(),
487 $shipInstance->getObjectDescription()
490 // Now check if the ship type is in any list and return the result
491 return ($this->isShipTypeConstructable($shipType));
494 // Is the ship type constructable?
495 public function isShipTypeConstructable ($shipType) {
496 // The type must be a string!
497 $shipType = (string) $shipType;
500 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.",
503 $this->getCompanyName(),
507 // First everthing is failed...
510 // Iterate through all shipyards
511 for ($idx = $this->shipyardList->getIterator(); $idx->valid(); $idx->next()) {
512 // Get current Shipyard instance
513 $shipyard = $idx->current();
515 // Is this a shipyard?
516 if (is_null($shipyard)) {
518 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
519 } elseif (!is_object($shipyard)) {
520 // Not an object! ;-(
521 throw new NoObjectException($shipyard, self::EXCEPTION_IS_NO_OBJECT);
522 } elseif (!$shipyard->isClass("Shipyard")) {
523 // Class is not a shipyard
524 throw new ClassMismatchException(array($shipyard->__toString(), "Shipyard"), self::EXCEPTION_CLASSES_NOT_MATCHING);
527 // Validate if the first found shipyard can construct the requested type
528 $result = $shipyard->isShipTypeConstructable($shipType);
530 // Does this shipyard construct the requested ship type?
531 if ($result) break; // Then abort the search!
535 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.",
538 $this->getCompanyName(),
546 // As a customer the shipping company can add new contracts
547 public function addNewWorksContract (SignableContract $contractInstance) {
548 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>.",
551 $this->getCompanyName(),
552 $contractInstance->getShipInstance()->getObjectDescription(),
553 $contractInstance->getShipInstance()->getShipName()
555 $this->contractList->append($contractInstance);
558 // As a customer the shippng company can withdraw from a contract
559 public function withdrawFromContract (SignableContract $contractInstance) {
560 ApplicationEntryPoint::app_die("WITHDRAW:<pre>".print_r($contractInstance, true)."</pre>");
563 // Get latest added contract instance
564 public final function getLastContractInstance () {
566 $iter = $this->contractList->getIterator();
568 // Get latest entry (total - 1)
569 $iter->seek($iter->count() - 1);
572 return $iter->current();
575 // Sign a contract with an other party which must also implement Customer
576 public function signContract (SignableContract $contractInstance, ContractPartner $partnerInstance) {
577 // Check wether the other party is our contract partner
578 if (!$partnerInstance->isContractPartner($contractInstance)) {
579 // Invalid contract partner!
580 throw new InvalidContractPartnerException($partnerInstance, self::EXCEPTION_CONTRACT_PARTNER_INVALID);
583 // Determine if company "signs" own contract (must be done) or with an other party
584 if ($this->equals($partnerInstance)) {
586 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>".",
589 $this->getCompanyName(),
590 $contractInstance->getShipInstance()->getObjectDescription(),
591 $contractInstance->getShipInstance()->getShipName()
594 // Other external company
595 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>.",
598 $this->getCompanyName(),
599 $contractInstance->getShipInstance()->getObjectDescription(),
600 $contractInstance->getShipInstance()->getShipName(),
601 $partnerInstance->getCompanyName()
606 $contractInstance->signContract($this, $partnerInstance);
609 * @todo Maybe do something more here...
613 // Is this the right contract partner?
614 public function isContractPartner (SignableContract $contractInstance) {
615 // Get contract partner instance and compare it with $this contract partner
616 return ($this->equals($contractInstance->getContractPartner()));
619 // Setter for merchant instance
620 public final function setMerchantInstance (Merchant $merchantInstance) {
622 $contractInstance = $this->getLastContractInstance();
624 if (is_null($contractInstance)) {
625 // Opps! Empty contract instance?
626 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
627 } elseif (!is_object($contractInstance)) {
628 // Not an object! ;-(
629 throw new NoObjectException($contractInstance, self::EXCEPTION_IS_NO_OBJECT);
630 } elseif (!$contractInstance->isClass('WorksContract')) {
632 throw new ClassMismatchException(array($contractInstance->__toString(), "WorksContract"), self::EXCEPTION_CLASSES_NOT_MATCHING);
635 // Set the merchant in the contract (for getting prices)
636 $contractInstance->setMerchantInstance($merchantInstance);