5 * @author Roland Haeder <webmaster@ship-simu.org>
7 * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 Hub 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 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;
33 private $listGroups = array();
38 private $listEntries = array();
43 private $listIndex = array();
46 * Protected constructor
48 * @param $className Name of the class
51 protected function __construct ($className) {
52 // Call parent constructor
53 parent::__construct($className);
55 // Remove some attributes
56 $this->removeNumberFormaters();
57 $this->removeSystemArray();
61 * Getter for iterator instance from this list
63 * @return $iteratorInstance An instance of a Iterator class
65 public function getIterator () {
66 // Prepare a default iterator
67 $iteratorInstance = ObjectFactory::createObjectByConfiguredName('default_iterator_class');
70 return $iteratorInstance;
74 * Checks wether the given group is set
76 * @param $groupName Group to check if found in list
77 * @return $isset Wether the group is valid
79 public function isGroupSet ($groupName) {
80 //* DEBUG: */ $this->debugOutput(__METHOD__.': '.$groupName);
81 return isset($this->listGroups[$groupName]);
85 * Adds the given group or if already added issues a ListGroupAlreadyAddedException
87 * @param $groupName Group to add
89 * @throws ListGroupAlreadyAddedException If the given group is already added
91 public function addGroup ($groupName) {
92 //* DEBUG: */ $this->debugOutput(__METHOD__.': '.$groupName . ' - START');
93 // Is the group already added?
94 if ($this->isGroupSet($groupName)) {
95 // Throw the exception here
96 throw new ListGroupAlreadyAddedException(array($this, $groupName), self::EXCEPTION_GROUP_ALREADY_ADDED);
99 // Add the group which is a simple array
100 $this->listGroups[$groupName] = ObjectFactory::createObjectByConfiguredName('list_group_class');
101 //* DEBUG: */ $this->debugOutput(__METHOD__.': '.$groupName . ' - FINISHED');
105 * Adds the given instance to list group and sub group
107 * @param $groupName Group to add instance to
108 * @param $subGroup Sub group to add instance to
109 * @param $instance An instance of Visitable
111 * @throws NoListGroupException If the given group is not found
113 public function addInstance ($groupName, $subGroup, Visitable $instance) {
114 //* DEBUG: */ $this->debugOutput(__METHOD__.': '.$groupName . '/' . $subGroup . ' - START');
115 // Is the group there?
116 if (!$this->isGroupSet($groupName)) {
117 // Throw the exception here
118 throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND);
121 // Is the sub group there?
122 if (!$this->listGroups[$groupName]->isGroupSet($subGroup)) {
123 // Automatically add it
124 $this->listGroups[$groupName]->addGroup($subGroup);
128 $hash = $this->generateHash($groupName, $subGroup, $instance);
130 // Now add it to the group list and hash it
131 $this->listGroups[$groupName]->addEntry($subGroup, $hash);
133 // Add the hash to the index
134 $this->listIndex[] = $hash;
136 // Add the instance itself to the list
137 $this->listEntries[$hash] = $instance;
138 //* DEBUG: */ $this->debugOutput(__METHOD__.': '.$groupName . '/' . $subGroup . ' - START');
142 * Gets an array from given list
144 * @param $list The requested list
145 * @return $array The requested array
146 * @throws NoListGroupException If the given group is not found
148 public final function getArrayFromList ($list) {
149 // Is the group there?
150 if ((!is_null($list)) && (!$this->isGroupSet($list))) {
151 // Throw the exception here
152 throw new NoListGroupException(array($this, $list), self::EXCEPTION_GROUP_NOT_FOUND);
158 // Is there another list?
159 if (!is_null($list)) {
160 // Then get it as well
161 $array = $this->listGroups[$list]->getArrayFromList(null);
164 // Walk through all entries
165 foreach ($this->listIndex as $hash) {
166 //* DEBUG: */ print __METHOD__.':hash='.$hash."\n";
167 // Is the list entry set?
168 if ($this->isHashValid($hash)) {
170 $array[] = $this->listEntries[$hash];
171 //* DEBUG: */ print __METHOD__.": ADDED!\n";
180 * Adds the given entry to list group
182 * @param $groupName Group to add instance to
183 * @param $entry An entry of any type
185 * @throws NoListGroupException If the given group is not found
187 public function addEntry ($groupName, $entry) {
188 //* DEBUG: */ $this->debugOutput(__METHOD__.'('.$this->__toString().'): '.$groupName . ' - START');
189 // Is the group already added?
190 if (!$this->isGroupSet($groupName)) {
191 // Throw the exception here
192 throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND);
196 $hash = $this->generateHash($groupName, $groupName, $entry);
197 //* DEBUG: */ $this->debugOutput(__METHOD__.'('.$this->__toString().'): hash='.$hash.'');
199 // Add the hash to the index
200 $this->listIndex[] = $hash;
201 //* DEBUG: */ print $groupName.'/'.count($this->listIndex)."\n";
203 // Now add the entry to the list
204 $this->listEntries[$hash] = $entry;
205 //* DEBUG: */ print $groupName.'/'.count($this->listEntries)."\n";
206 //* DEBUG: */ $this->debugOutput(__METHOD__.'('.$this->__toString().'): '.$groupName . ' - FINISHED');
210 * Generates a hash from given group, sub group and entry
212 * @param $groupName Group to add instance to
213 * @param $subGroup Sub group to add instance to
214 * @param $entry An entry of any type
215 * @return $hash The generated
217 private function generateHash ($groupName, $subGroup, $entry) {
218 // Created entry, 'null' is default
221 // Determine type of entry
222 if (is_null($entry)) {
224 } elseif ($entry instanceof FrameworkInterface) {
225 // Own instance detected
226 $entry2 = $entry->hashCode();
227 } elseif ((is_int($entry)) || (is_float($entry)) || (is_resource($entry))) {
228 // Integer/float/resource detected
229 $entry2 = gettype($entry) . ':' . $entry;
230 } elseif (is_string($entry)) {
232 $entry2 = crc32($entry) . ':' . strlen($entry);
234 // Unsupported type detected
235 $this->debugOutut(__METHOD__ . ': entry type ' . gettype($entry) . ' is unsupported.');
237 // @TODO Extend this somehow?
238 $entry2 = gettype($entry);
241 // Construct string which we shall hash
242 $hashString = $groupName . ':' . $subGroup . ':' . $entry2;
244 // Hash it with fastest hasher
245 $hash = crc32($hashString);
252 * Counts all entries in this list
254 * @return $count All entries in this list
256 public final function count () {
257 return count($this->listIndex);
261 * Checks wether the given hash is valid
263 * @param $hash The hash we should validate
264 * @return $isValid Wether the given hash is valid
266 public final function isHashValid ($hash) {
268 $isValid = ((in_array($hash, $this->listIndex)) && (isset($this->listEntries[$hash])));
275 * Gets an entry from given hash index
277 * @param $hashIndex The hash index to resolve the mapped entry
278 * @return $entry Solved entry from list
279 * @throws InvalidListHashException If the solved hash index is invalid
281 public function getEntry ($hashIndex) {
282 // Get the hash value
283 $hash = $this->listIndex[$hashIndex];
285 // Is the hash valid?
286 if (!$this->isHashValid($hash)) {
287 // Throw an exception here
288 throw new InvalidListHashException(array($this, $hash, $hashIndex), self::EXCEPTION_INVALID_HASH);
291 // Now copy the entry
292 $entry = $this->listEntries[$hash];