]> git.mxchange.org Git - hub.git/blob - application/hub/main/lists/class_BaseList.php
Renamed it as this class can be anything that implements Visitable
[hub.git] / application / hub / main / lists / class_BaseList.php
1 <?php
2 /**
3  * A general list class
4  *
5  * @author              Roland Haeder <webmaster@ship-simu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 Hub Developer Team
8  * @license             GNU GPL 3.0 or any newer version
9  * @link                http://www.ship-simu.org
10  *
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.
15  *
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.
20  *
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/>.
23  */
24 class BaseList extends BaseHubSystem implements IteratorAggregate, Countable {
25         // Exception constants
26         const EXCEPTION_GROUP_ALREADY_ADDED = 0xf20;
27         const EXCEPTION_GROUP_NOT_FOUND     = 0xf21;
28         const EXCEPTION_INVALID_HASH        = 0xf22;
29
30         /**
31          * List groups array
32          */
33         private $listGroups = array();
34
35         /**
36          * List entries array
37          */
38         private $listEntries = array();
39
40         /**
41          * List index array
42          */
43         private $listIndex = array();
44
45         /**
46          * Protected constructor
47          *
48          * @param       $className      Name of the class
49          * @return      void
50          */
51         protected function __construct ($className) {
52                 // Call parent constructor
53                 parent::__construct($className);
54         }
55
56         /**
57          * Getter for iterator instance from this list
58          *
59          * @return      $iteratorInstance       An instance of a Iterator class
60          */
61         public function getIterator () {
62                 // Get iterator from here
63                 $iteratorInstance = $this->getIteratorInstance();
64
65                 // Is the instance set?
66                 if (is_null($iteratorInstance)) {
67                         // Prepare a default iterator
68                         $iteratorInstance = ObjectFactory::createObjectByConfiguredName('default_iterator_class', array($this));
69
70                         // Set it here
71                         $this->setIteratorInstance($iteratorInstance);
72                 } // END - if
73
74                 // And return it
75                 return $iteratorInstance;
76         }
77
78         /**
79          * Checks whether the given group is set
80          *
81          * @param       $groupName      Group to check if found in list
82          * @return      $isset          Whether the group is valid
83          */
84         public function isGroupSet ($groupName) {
85                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(__METHOD__.': '.$groupName);
86                 return isset($this->listGroups[$groupName]);
87         }
88
89         /**
90          * Adds the given group or if already added issues a ListGroupAlreadyAddedException
91          *
92          * @param       $groupName      Group to add
93          * @return      void
94          * @throws      ListGroupAlreadyAddedException  If the given group is already added
95          */
96         public function addGroup ($groupName) {
97                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(__METHOD__.': '.$groupName . ' - START');
98                 // Is the group already added?
99                 if ($this->isGroupSet($groupName)) {
100                         // Throw the exception here
101                         throw new ListGroupAlreadyAddedException(array($this, $groupName), self::EXCEPTION_GROUP_ALREADY_ADDED);
102                 } // END - if
103
104                 // Add the group which is a simple array
105                 $this->listGroups[$groupName] = ObjectFactory::createObjectByConfiguredName('list_group_class');
106                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(__METHOD__.': '.$groupName . ' - FINISHED');
107         }
108
109         /**
110          * Adds the given instance to list group and sub group
111          *
112          * @param       $groupName                      Group to add instance to
113          * @param       $subGroup                       Sub group to add instance to
114          * @param       $visitableInstance      An instance of Visitable
115          * @return      void
116          * @throws      NoListGroupException    If the given group is not found
117          */
118         public function addInstance ($groupName, $subGroup, Visitable $visitableInstance) {
119                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(__METHOD__.': '.$groupName  . '/' . $subGroup . ' - START');
120                 // Is the group there?
121                 if (!$this->isGroupSet($groupName)) {
122                         // Throw the exception here
123                         throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND);
124                 } // END - if
125
126                 // Is the sub group there?
127                 if (!$this->listGroups[$groupName]->isGroupSet($subGroup)) {
128                         // Automatically add it
129                         $this->listGroups[$groupName]->addGroup($subGroup);
130                 } // END - if
131
132                 // Generate the hash
133                 $hash = $this->generateHash($groupName, $subGroup, $visitableInstance);
134
135                 // Now add it to the group list and hash it
136                 $this->listGroups[$groupName]->addEntry($subGroup, $hash);
137
138                 // Add the hash to the index
139                 array_push($this->listIndex, $hash);
140
141                 // Add the instance itself to the list
142                 $this->listEntries[$hash] = $visitableInstance;
143                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(__METHOD__.': '.$groupName  . '/' . $subGroup . ' - FINISHED');
144         }
145
146         /**
147          * Gets an array from given list
148          *
149          * @param       $list   The requested list
150          * @return      $array  The requested array
151          * @throws      NoListGroupException    If the given group is not found
152          */
153         public final function getArrayFromList ($list) {
154                 // Is the group there?
155                 if ((!is_null($list)) && (!$this->isGroupSet($list))) {
156                         // Throw the exception here
157                         throw new NoListGroupException(array($this, $list), self::EXCEPTION_GROUP_NOT_FOUND);
158                 } // END - if
159
160                 // Init array
161                 $array = array();
162
163                 // Is there another list?
164                 if (!is_null($list)) {
165                         // Then get it as well
166                         $array = $this->listGroups[$list]->getArrayFromList(NULL);
167                 } // END - if
168
169                 // Walk through all entries
170                 foreach ($this->listIndex as $hash) {
171                         //* DEBUG: */ print __METHOD__.':hash='.$hash.chr(10);
172                         // Is the list entry set?
173                         if ($this->isHashValid($hash)) {
174                                 // Add it
175                                 array_push($array, $this->listEntries[$hash]);
176                                 //* DEBUG: */ print __METHOD__.": ADDED!\n";
177                         } // END - if
178                 } // END - foreach
179
180                 // Return it
181                 return $array;
182         }
183
184         /**
185          * Adds the given entry to list group
186          *
187          * @param       $groupName      Group to add instance to
188          * @param       $entry          An entry of any type
189          * @return      void
190          * @throws      NoListGroupException    If the given group is not found
191          */
192         public function addEntry ($groupName, $entry) {
193                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(__METHOD__.'('.$this->__toString().'): '.$groupName . ' - START');
194                 // Is the group already added?
195                 if (!$this->isGroupSet($groupName)) {
196                         // Throw the exception here
197                         throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND);
198                 } // END - if
199
200                 // Generate hash
201                 $hash = $this->generateHash($groupName, $groupName, $entry);
202                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']:  groupName=' . $groupName . ', entry=' . $entry . ', hash=' . $hash);
203
204                 // Add the hash to the index
205                 array_push($this->listIndex, $hash);
206                 //* DEBUG: */ print $groupName.'/'.$this->count().chr(10);
207
208                 // Now add the entry to the list
209                 $this->listEntries[$hash] = $entry;
210                 //* DEBUG: */ print $groupName.'/'.count($this->listEntries).chr(10);
211                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(__METHOD__.'('.$this->__toString().'): '.$groupName . ' - FINISHED');
212         }
213
214         /**
215          * Removes given entry from the list group
216          *
217          * @param       $groupName      Group where we should remove the entry from
218          * @param       $entry          The entry we should remove
219          * @return      void
220          * @throws      NoListGroupException    If the given group is not found
221          */
222         public function removeEntry ($groupName, $entry) {
223                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(__METHOD__.'('.$this->__toString().'): '.$groupName . ' - START');
224                 // Is the group already added?
225                 if (!$this->isGroupSet($groupName)) {
226                         // Throw the exception here
227                         throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND);
228                 } // END - if
229
230                 // Generate hash
231                 $hash = $this->generateHash($groupName, $groupName, $entry);
232                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']:  groupName=' . $groupName . ', entry=' . $entry . ', hash=' . $hash);
233
234                 // Remove it from the list ...
235                 unset($this->listEntries[$hash]);
236
237                 // ... and hash list as well
238                 unset($this->listIndex[array_search($hash, $this->listIndex)]);
239                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(__METHOD__.'('.$this->__toString().'): '.$groupName . ' - FINISHED');
240         }
241
242         /**
243          * Generates a hash from given group, sub group and entry
244          *
245          * @param       $groupName      Group to add instance to
246          * @param       $subGroup       Sub group to add instance to
247          * @param       $entry          An entry of any type
248          * @return      $hash           The generated
249          */
250         private function generateHash ($groupName, $subGroup, $entry) {
251                 // Created entry, 'null' is default
252                 $entry2 = 'null';
253
254                 // Determine type of entry
255                 if (is_null($entry)) {
256                         // Ignore this
257                 } elseif ($entry instanceof FrameworkInterface) {
258                         // Own instance detected
259                         $entry2 = $entry->hashCode();
260                 } elseif ((is_int($entry)) || (is_float($entry)) || (is_resource($entry))) {
261                         // Integer/float/resource detected
262                         $entry2 = gettype($entry) . ':' . $entry;
263                 } elseif (is_string($entry)) {
264                         // String found
265                         $entry2 = crc32($entry) . ':' . strlen($entry);
266                 } elseif ((is_array($entry)) && (isset($entry['id']))) {
267                         // Supported array found
268                         $entry2 = crc32($entry['id']) . ':' . count($entry);
269                 } elseif ((is_array($entry)) && (isset($entry[BasePool::SOCKET_ARRAY_RESOURCE])) && (isset($entry[BasePool::SOCKET_ARRAY_CONN_TYPE]))) {
270                         // Is a socket resource array
271                         $entry2 = crc32($entry[BasePool::SOCKET_ARRAY_RESOURCE] . ':' . $entry[BasePool::SOCKET_ARRAY_CONN_TYPE]);
272                 } else {
273                         // Unsupported type detected
274                         self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: Entry type ' . gettype($entry) . ' is unsupported.');
275
276                         // @TODO Extend this somehow?
277                         $entry2 = gettype($entry);
278                 }
279
280                 // Construct string which we shall hash
281                 $hashString = $groupName . ':' . $subGroup . ':' . $entry2;
282
283                 // Hash it with fastest hasher
284                 $hash = crc32($hashString);
285
286                 // And return it
287                 return $hash;
288         }
289
290         /**
291          * Clears an array of groups, all are being checked for existence
292          *
293          * @param       $groupNames             An array with existing list groups
294          * @return      void
295          */
296         protected function clearGroups (array $groupNames) {
297                 // Walk through all groups
298                 foreach ($groupNames as $groupName) {
299                         // Clear this group
300                         $this->clearGroup($groupName);
301                 } // END - foreach
302         }
303
304         /**
305          * Clears a single group by resetting it to its initial state (empty array)
306          *
307          * @param       $groupName      Name of an existing group to clear
308          * @return      void
309          */
310         protected function clearGroup ($groupName) {
311                 // Does this group exist?
312                 if (!$this->isGroupSet($groupName)) {
313                         // Throw the exception here
314                         throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND);
315                 } // END - if
316
317                 // Then clear this group list
318                 $this->listGroups[$groupName]->clearList();
319
320                 // Clear this list
321                 $this->listIndex = array();
322                 $this->listEntries = array();
323         }
324         
325         /**
326          * Counts all entries in this list
327          *
328          * @return      $count  All entries in this list
329          */
330         public final function count () {
331                 return count($this->listIndex);
332         }
333
334         /**
335          * Checks whether the given hash is valid
336          *
337          * @param       $hash           The hash we should validate
338          * @return      $isValid        Whether the given hash is valid
339          */
340         public final function isHashValid ($hash) {
341                 // Check it
342                 $isValid = ((in_array($hash, $this->listIndex)) && (isset($this->listEntries[$hash])));
343
344                 // Return the result
345                 return $isValid;
346         }
347
348         /**
349          * Getter for hash from given hash index
350          *
351          * @param       $hashIndex      Index holding the hash
352          * @return      $hash           The hash
353          */
354         public final function getHash ($hashIndex) {
355                 // Get it ...
356                 $hash = $this->listIndex[$hashIndex];
357
358                 // ... and return it
359                 return $hash;
360         }
361
362         /**
363          * Gets an entry from given hash index
364          *
365          * @param       $hashIndex      The hash index to resolve the mapped entry
366          * @return      $entry          Solved entry from list
367          * @throws      InvalidListHashException        If the solved hash index is invalid
368          */
369         public function getEntry ($hashIndex) {
370                 // Get the hash value
371                 $hash = $this->getHash($hashIndex);
372
373                 // Is the hash valid?
374                 if (!$this->isHashValid($hash)) {
375                         // Throw an exception here
376                         throw new InvalidListHashException(array($this, $hash, $hashIndex), self::EXCEPTION_INVALID_HASH);
377                 } // END - if
378
379                 // Now copy the entry
380                 $entry = $this->listEntries[$hash];
381
382                 // Return it
383                 return $entry;
384         }
385
386         /**
387          * Gets a full array from given group name
388          *
389          * @param       $groupName      The group name to get a list for
390          * @return      $entries        The array with all entries
391          * @throws      NoListGroupException    If the specified group is invalid
392          */
393         public function getArrayFromGroup ($groupName) {
394                 // Is the group valid?
395                 if (!$this->isGroupSet($groupName)) {
396                         // Throw the exception here
397                         throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND);
398                 } // END - if
399
400                 // Init the entries' array
401                 $entries = array();
402
403                 // Get an iterator
404                 $iteratorInstance = $this->listGroups[$groupName]->getIterator();
405
406                 // Rewind the iterator for this round
407                 $iteratorInstance->rewind();
408
409                 // Go through all entries
410                 while ($iteratorInstance->valid()) {
411                         // Get key
412                         $entryIndex = $iteratorInstance->key();
413
414                         // ... and the final entry which is the stored instance
415                         $entry = $this->getEntry($entryIndex);
416
417                         // Debug message
418                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('LIST: Adding entry ' . $entry . ' ...');
419
420                         // Add it to the list
421                         $entries[$iteratorInstance->current()] = $entry;
422
423                         // Skip to next one
424                         $iteratorInstance->next();
425                 } // END - while
426
427                 // Return the list
428                 return $entries;
429         }
430
431         /**
432          * Updates the given entry by hash with given array
433          *
434          * @param       $hash           Hash for this entry
435          * @param       $entryArray     Array with entry we should update
436          * @return      void
437          * @throws      InvalidListHashException        If the solved hash index is invalid
438          */
439         public function updateCurrentEntryByHash ($hash, array $entryArray) {
440                 // Is the hash valid?
441                 if (!$this->isHashValid($hash)) {
442                         // Throw an exception here, hashIndex is unknown at this point
443                         throw new InvalidListHashException(array($this, $hash, -999), self::EXCEPTION_INVALID_HASH);
444                 } // END - if
445
446                 // Set the entry
447                 $this->listEntries[$hash] = $entryArray;
448         }
449 }
450
451 //
452 ?>