Added missing setter.
[core.git] / inc / classes / main / stacker / file / class_BaseFileStack.php
1 <?php
2 /**
3  * A general file-based stack class
4  *
5  * @author              Roland Haeder <webmaster@ship-simu.org>
6  * @version             0.0.0
7  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2013 Core 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 BaseFileStack extends BaseStacker {
25         /**
26          * Magic for this stack
27          */
28         const STACK_MAGIC = 'STACKv0.1';
29
30         /**
31          * Separator for header data
32          */
33         const SEPARATOR_HEADER_DATA = 0x01;
34
35         /**
36          * Separator header->entries
37          */
38         const SEPARATOR_HEADER_ENTRIES = 0x02;
39
40         /**
41          * Separator hash->name
42          */
43         const SEPARATOR_HASH_NAME = 0x03;
44
45         /**
46          * Length of name
47          */
48         const LENGTH_NAME = 10;
49
50         /**
51          * Length of count
52          */
53         const LENGTH_COUNT = 20;
54
55         /**
56          * Length of position
57          */
58         const LENGTH_POSITION = 20;
59
60         /**
61          * Counter for total entries
62          */
63         private $totalEntries = 0;
64
65         /**
66          * Current seek position
67          */
68         private $seekPosition = 0;
69
70         /**
71          * Size of header
72          */
73         private $headerSize = 0;
74
75         /**
76          * File header
77          */
78         private $header = array();
79
80         /**
81          * Seek positions for gaps ("fragmentation")
82          */
83         private $gaps = array();
84
85         /**
86          * Seek positions for damaged entries (e.g. mismatching hash sum, ...)
87          */
88         private $damagedEntries = array();
89
90         /**
91          * Protected constructor
92          *
93          * @param       $className      Name of the class
94          * @return      void
95          */
96         protected function __construct ($className) {
97                 // Call parent constructor
98                 parent::__construct($className);
99
100                 // Calculate header size
101                 $this->headerSize = (
102                         strlen(self::STACK_MAGIC) +
103                         strlen(self::SEPARATOR_HEADER_DATA) +
104                         self::LENGTH_COUNT +
105                         strlen(self::SEPARATOR_HEADER_DATA) +
106                         self::LENGTH_POSITION +
107                         strlen(self::SEPARATOR_HEADER_ENTRIES)
108                 );
109
110                 // Init counters and gaps array
111                 $this->initCountersGapsArray();
112         }
113
114         /**
115          * Initializes counter for valid entries, arrays for damaged entries and
116          * an array for gap seek positions. If you call this method on your own,
117          * please re-analyze the file structure. So you are better to call
118          * analyzeStackFile() instead of this method.
119          *
120          * @return      void
121          */
122         private function initCountersGapsArray () {
123                 // Init counter and seek position
124                 $this->setCounter(0);
125                 $this->setSeekPosition(0);
126
127                 // Init arrays
128                 $this->gaps = array();
129                 $this->damagedEntries = array();
130         }
131
132         /**
133          * Getter for total entries
134          *
135          * @return      $totalEntries   Total entries in this stack
136          */
137         private final function getCounter () {
138                 // Get it
139                 return $this->totalEntries;
140         }
141
142         /**
143          * Setter for total entries
144          *
145          * @param       $totalEntries   Total entries in this stack
146          * @return      void
147          */
148         private final function setCounter ($counter) {
149                 // Set it
150                 $this->totalEntries = $counter;
151         }
152
153         /**
154          * Increment counter
155          *
156          * @return      void
157          */
158         private final function incrementCounter () {
159                 // Get it
160                 $this->totalEntries++;
161         }
162
163         /**
164          * Getter for seek position
165          *
166          * @return      $seekPosition   Current seek position (stored here in object)
167          */
168         private final function getSeekPosition () {
169                 // Get it
170                 return $this->seekPosition;
171         }
172
173         /**
174          * Setter for seek position
175          *
176          * @param       $seekPosition   Current seek position (stored here in object)
177          * @return      void
178          */
179         private final function setSeekPosition ($seekPosition) {
180                 // And set it
181                 $this->seekPosition = $seekPosition;
182         }
183
184         /**
185          * Updates seekPosition attribute from file to avoid to much access on file.
186          *
187          * @return      void
188          */
189         private function updateSeekPosition () {
190                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
191
192                 // Get key (= seek position)
193                 $seekPosition = $this->getIteratorInstance()->key();
194                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Setting seekPosition=%s', __METHOD__, __LINE__, $seekPosition));
195
196                 // And set it here
197                 $this->setSeekPosition($seekPosition);
198
199                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
200         }
201
202         /**
203          * Reads the file header
204          *
205          * @return      void
206          */
207         private function readFileHeader () {
208                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
209
210                 // First rewind to beginning as the header sits at the beginning ...
211                 $this->getIteratorInstance()->rewind();
212
213                 // Then read it (see constructor for calculation)
214                 $data = $this->getIteratorInstance()->read($this->headerSize);
215                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Read %d bytes (%d wanted).', __METHOD__, __LINE__, strlen($data), $this->headerSize));
216
217                 // Have all requested bytes been read?
218                 assert(strlen($data) == $this->headerSize);
219                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
220
221                 // Last character must be the separator
222                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] data(-1)=%s', __METHOD__, __LINE__, dechex(ord(substr($data, -1, 1)))));
223                 assert(substr($data, -1, 1) == chr(self::SEPARATOR_HEADER_ENTRIES));
224                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
225
226                 // Okay, then remove it
227                 $data = substr($data, 0, -1);
228
229                 // And update seek position
230                 $this->updateSeekPosition();
231
232                 /*
233                  * Now split it:
234                  *
235                  * 0 => Magic
236                  * 1 => Total entries
237                  * 2 => Current seek position
238                  */
239                 $this->header = explode(chr(self::SEPARATOR_HEADER_DATA), $data);
240
241                 // Check if the array has only 3 elements
242                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] header(%d)=%s', __METHOD__, __LINE__, count($this->header), print_r($this->header, TRUE)));
243                 assert(count($this->header) == 3);
244                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
245
246                 // Check magic
247                 assert($this->header[0] == self::STACK_MAGIC);
248                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
249
250                 // Check length of count and seek position
251                 assert(strlen($this->header[1]) == self::LENGTH_COUNT);
252                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
253                 assert(strlen($this->header[2]) == self::LENGTH_POSITION);
254                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Passed assert().', __METHOD__, __LINE__));
255
256                 // Decode count and seek position
257                 $this->header[1] = hex2bin($this->header[1]);
258                 $this->header[2] = hex2bin($this->header[2]);
259
260                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
261         }
262
263         /**
264          * Checks whether the file header is initialized
265          *
266          * @return      $isInitialized  Whether the file header is initialized
267          */
268         private function isFileHeaderInitialized () {
269                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
270                 // Default is not initialized
271                 $isInitialized = FALSE;
272
273                 // Is the file initialized?
274                 if ($this->isFileInitialized()) {
275                         // Some bytes has been written, so rewind to start of it.
276                         $rewindStatus = $this->getIteratorInstance()->rewind();
277                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] rewindStatus=%s', __METHOD__, __LINE__, $rewindStatus));
278
279                         // Is the rewind() call successfull?
280                         if ($rewindStatus != 1) {
281                                 // Something bad happened
282                                 self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Could not rewind().', __METHOD__, __LINE__));
283                         } // END - if
284
285                         // Read file header
286                         $this->readFileHeader();
287
288                         // The above method does already check the header
289                         $isInitialized = TRUE;
290                 } // END - if
291
292                 // Return result
293                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] isInitialized=%d - EXIT!', __METHOD__, __LINE__, intval($isInitialized)));
294                 return $isInitialized;
295         }
296
297         /**
298          * Checks whether the file-based stack has been initialized
299          *
300          * @return      $isInitialized          Whether the file's size is zero
301          */
302         private function isFileInitialized () {
303                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
304
305                 // Get it from iterator which holds the pointer instance. If FALSE is returned
306                 $fileSize = $this->getIteratorInstance()->size();
307                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] fileSize=%s', __METHOD__, __LINE__, $fileSize));
308
309                 /*
310                  * The returned file size should not be FALSE or NULL as this means
311                  * that the pointer class does not work correctly.
312                  */
313                 assert(is_int($fileSize));
314
315                 // Is more than 0 returned?
316                 $isInitialized = ($fileSize > 0);
317
318                 // Return result
319                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] isInitialized=%d - EXIT!', __METHOD__, __LINE__, intval($isInitialized)));
320                 return $isInitialized;
321         }
322
323         /**
324          * Creates the file-stack's header
325          *
326          * @return      void
327          */
328         private function createFileHeader () {
329                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
330                 // The file's header should not be initialized here
331                 assert(!$this->isFileHeaderInitialized());
332
333                 // Simple flush file header which will create it.
334                 $this->flushFileHeader();
335
336                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!!', __METHOD__, __LINE__));
337         }
338
339         /**
340          * Flushes the file header
341          *
342          * @return      void
343          */
344         private function flushFileHeader () {
345                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
346
347                 // Put all informations together
348                 $header = sprintf('%s%s%s%s%s%s',
349                         // Magic
350                         self::STACK_MAGIC,
351
352                         // Separator magic<->count
353                         chr(self::SEPARATOR_HEADER_DATA),
354
355                         // Total entries (will be zero) and pad it to 20 chars
356                         str_pad($this->dec2hex($this->getCounter()), self::LENGTH_COUNT, '0', STR_PAD_LEFT),
357
358                         // Separator count<->seek position
359                         chr(self::SEPARATOR_HEADER_DATA),
360
361                         // Position (will be zero)
362                         str_pad($this->dec2hex($this->getSeekPosition(), 2), self::LENGTH_POSITION, '0', STR_PAD_LEFT),
363
364                         // Separator position<->entries
365                         chr(self::SEPARATOR_HEADER_ENTRIES)
366                 );
367
368                 // Write it to disk (header is always at seek position 0)
369                 $this->writeData(0, $header);
370
371                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
372         }
373
374         /**
375          * Writes data at given position
376          *
377          * @param       $seekPosition   Seek position
378          * @param       $data                   Data to be written
379          * @return      void
380          */
381         private function writeData ($seekPosition, $data) {
382                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] seekPosition=%s,data()=%s - CALLED!', __METHOD__, __LINE__, $seekPosition, strlen($data)));
383
384                 // Write data at given position
385                 $this->getIteratorInstance()->writeAtPosition($seekPosition, $data);
386
387                 // Update seek position
388                 $this->updateSeekPosition();
389
390                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
391         }
392
393         /**
394          * Pre-allocates file (if enabled) with some space for later faster write access.
395          *
396          * @return      void
397          */
398         private function preAllocateFile () {
399                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
400
401                 // Is it enabled?
402                 if ($this->getConfigInstance()->getConfigEntry('file_stack_pre_allocate_enabled') != 'Y') {
403                         // Not enabled
404                         self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Not pre-allocating stack file.', __METHOD__, __LINE__));
405
406                         // Don't continue here.
407                         return;
408                 } // END - if
409
410                 // Message to user
411                 self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Pre-allocating stack file ...', __METHOD__, __LINE__));
412
413                 /*
414                  * Calculate minimum length for one entry:
415                  * minimum length = hash length + separator + name + minimum entry size = ?? + 1 + 10 + 1 = ??
416                  */
417                 $minLengthEntry = self::getHashLength() + strlen(self::SEPARATOR_HASH_NAME) + self::LENGTH_NAME + 1;
418                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] minLengthEntry=%s', __METHOD__, __LINE__, $minLengthEntry));
419
420                 // Calulcate seek position
421                 $seekPosition = $minLengthEntry * $this->getConfigInstance()->getConfigEntry('file_stack_pre_allocate_count');
422                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] seekPosition=%s', __METHOD__, __LINE__, $seekPosition));
423
424                 // Now simply write a NUL there. This will pre-allocate the file.
425                 $this->writeData($seekPosition, chr(0));
426
427                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
428         }
429
430         /**
431          * Analyzes entries in stack file. This will count all found (and valid)
432          * entries, mark invalid as damaged and count gaps ("fragmentation"). If
433          * only gaps are found, the file is considered as "virgin" (no entries).
434          *
435          * @return      void
436          */
437         private function analyzeStackFile () {
438                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] CALLED!', __METHOD__, __LINE__));
439
440                 // Make sure the file is initialized
441                 assert($this->isFileInitialized());
442
443                 // Init counters and gaps array
444                 $this->initCountersGapsArray();
445
446                 // Output message (as this may take some time)
447                 self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] Analyzing file structure ... (this may take some time)', __METHOD__, __LINE__));
448
449                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(sprintf('[%s:%d:] EXIT!', __METHOD__, __LINE__));
450         }
451
452         /**
453          * Initializes this file-based stack.
454          *
455          * @param       $fileName       File name of this stack
456          * @param       $type           Type of this stack (e.g. url_source for URL sources)
457          * @return      void
458          */
459         protected function initFileStack ($fileName, $type) {
460                 // Get a file i/o pointer instance for stack file
461                 $pointerInstance = ObjectFactory::createObjectByConfiguredName('file_raw_input_output_class', array($fileName));
462
463                 // Get iterator instance
464                 $iteratorInstance = ObjectFactory::createObjectByConfiguredName('file_io_iterator_class', array($pointerInstance));
465
466                 // Is the instance implementing the right interface?
467                 assert($iteratorInstance instanceof SeekableWritableFileIterator);
468
469                 // Set iterator here
470                 $this->setIteratorInstance($iteratorInstance);
471
472                 // Is the file's header initialized?
473                 if (!$this->isFileHeaderInitialized()) {
474                         // No, then create it (which may pre-allocate the stack)
475                         $this->createFileHeader();
476
477                         // And pre-allocate a bit
478                         $this->preAllocateFile();
479                 } // END - if
480
481                 // Load the file header
482                 $this->readFileHeader();
483
484                 // Count all entries in file
485                 $this->analyzeStackFile();
486
487                 /*
488                  * Get stack index instance. This can be used for faster
489                  * "defragmentation" and startup.
490                  */
491                 $indexInstance = FileStackIndexFactory::createFileStackIndexInstance($fileName, $type);
492
493                 // And set it here
494                 $this->setIndexInstance($indexInstance);
495         }
496
497         /**
498          * Adds a value to given stack
499          *
500          * @param       $stackerName    Name of the stack
501          * @param       $value                  Value to add to this stacker
502          * @return      void
503          * @throws      FullStackerException    If the stack is full
504          */
505         protected function addValue ($stackerName, $value) {
506                 // Do some tests
507                 if ($this->isStackFull($stackerName)) {
508                         // Stacker is full
509                         throw new FullStackerException(array($this, $stackerName, $value), self::EXCEPTION_STACKER_IS_FULL);
510                 } // END - if
511
512                 // Now add the value to the stack
513                 $this->partialStub('stackerName=' . $stackerName . ',value[]=' . gettype($value));
514         }
515
516         /**
517          * Get last value from named stacker
518          *
519          * @param       $stackerName    Name of the stack
520          * @return      $value                  Value of last added value
521          * @throws      EmptyStackerException   If the stack is empty
522          */
523         protected function getLastValue ($stackerName) {
524                 // Is the stack not yet initialized or full?
525                 if ($this->isStackEmpty($stackerName)) {
526                         // Throw an exception
527                         throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
528                 } // END - if
529
530                 // Now get the last value
531                 $this->partialStub('stackerName=' . $stackerName);
532                 $value = NULL;
533
534                 // Return it
535                 return $value;
536         }
537
538         /**
539          * Get first value from named stacker
540          *
541          * @param       $stackerName    Name of the stack
542          * @return      $value                  Value of last added value
543          * @throws      EmptyStackerException   If the stack is empty
544          */
545         protected function getFirstValue ($stackerName) {
546                 // Is the stack not yet initialized or full?
547                 if ($this->isStackEmpty($stackerName)) {
548                         // Throw an exception
549                         throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
550                 } // END - if
551
552                 // Now get the first value
553                 $this->partialStub('stackerName=' . $stackerName);
554                 $value = NULL;
555
556                 // Return it
557                 return $value;
558         }
559
560         /**
561          * "Pops" last entry from stack
562          *
563          * @param       $stackerName    Name of the stack
564          * @return      $value                  Value "poped" from array
565          * @throws      EmptyStackerException   If the stack is empty
566          */
567         protected function popLast ($stackerName) {
568                 // Is the stack not yet initialized or full?
569                 if ($this->isStackEmpty($stackerName)) {
570                         // Throw an exception
571                         throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
572                 } // END - if
573
574                 // Now, remove the last entry, we don't care about the return value here, see elseif() block above
575                 $this->partialStub('stackerName=' . $stackerName);
576                 return NULL;
577         }
578
579         /**
580          * "Pops" first entry from stack
581          *
582          * @param       $stackerName    Name of the stack
583          * @return      $value                  Value "shifted" from array
584          * @throws      EmptyStackerException   If the named stacker is empty
585          */
586         protected function popFirst ($stackerName) {
587                 // Is the stack not yet initialized or full?
588                 if ($this->isStackEmpty($stackerName)) {
589                         // Throw an exception
590                         throw new EmptyStackerException(array($this, $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
591                 } // END - if
592
593                 // Now, remove the last entry, we don't care about the return value here, see elseif() block above
594                 $this->partialStub('stackerName=' . $stackerName);
595                 return NULL;
596         }
597
598         /**
599          * Checks whether the given stack is full
600          *
601          * @param       $stackerName    Name of the stack
602          * @return      $isFull                 Whether the stack is full
603          */
604         protected function isStackFull ($stackerName) {
605                 // File-based stacks will only run full if the disk space is low.
606                 // @TODO Please implement this, returning FALSE
607                 $isFull = FALSE;
608
609                 // Return result
610                 return $isFull;
611         }
612
613         /**
614          * Checks whether the given stack is empty
615          *
616          * @param       $stackerName            Name of the stack
617          * @return      $isEmpty                        Whether the stack is empty
618          * @throws      NoStackerException      If given stack is missing
619          */
620         public function isStackEmpty ($stackerName) {
621                 // So, is the stack empty?
622                 $isEmpty = (($this->getStackCount($stackerName)) == 0);
623
624                 // Return result
625                 return $isEmpty;
626         }
627
628         /**
629          * Initializes given stacker
630          *
631          * @param       $stackerName    Name of the stack
632          * @param       $forceReInit    Force re-initialization
633          * @return      void
634          * @throws      UnsupportedOperationException   This method is not (and maybe never will be) supported
635          */
636         public function initStack ($stackerName, $forceReInit = FALSE) {
637                 throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION);
638         }
639
640         /**
641          * Initializes all stacks
642          *
643          * @return      void
644          * @throws      UnsupportedOperationException   This method is not (and maybe never will be) supported
645          */
646         public function initStacks (array $stacks, $forceReInit = FALSE) {
647                 throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION);
648         }
649
650         /**
651          * Checks whether the given stack is initialized (set in array $stackers)
652          *
653          * @param       $stackerName    Name of the stack
654          * @return      $isInitialized  Whether the stack is initialized
655          * @throws      UnsupportedOperationException   This method is not (and maybe never will be) supported
656          */
657         public function isStackInitialized ($stackerName) {
658                 throw new UnsupportedOperationException(array($this, __FUNCTION__, $this->getIteratorInstance()->getPointerInstance()), self::EXCEPTION_UNSPPORTED_OPERATION);
659         }
660
661         /**
662          * Getter for size of given stack (array count)
663          *
664          * @param       $stackerName    Name of the stack
665          * @return      $count                  Size of stack (array count)
666          */
667         public function getStackCount ($stackerName) {
668                 // Now, simply return the found count value, this must be up-to-date then!
669                 return $this->getCounter();
670         }
671 }
672
673 // [EOF]
674 ?>