;===============================================================================
;
;                               S T R E A M
;
; Provide a sequential view of any ordered collection of objects (text files
; may be considered as an ordered collection of characters).
;===============================================================================

[{Class} new 'name 'MetaStream
	'superClass		{Class}
        'methods		'(
on ((aCollection)
	[super new 'collection 		aCollection 
	           'position  		-1
    		   'limitPosition      	(1- [aCollection size])])
)]

[{MetaStream} new 'name 'Stream
	'superClass		{Object}
	'instanceVariables	'(collection position limitPosition)
        'methods		'(
contents (()	
          ;; -----------------------------------------------------------
          ;; Answer the collection over which the receiver is streaming.
          ;; -----------------------------------------------------------
		#Icollection)

position ( arg
           ;; ----------------------------------------------------------
           ;; If no argument is provided, answer the current receiver
           ;; position else set its position to <arg> (between -1 and
           ;; #IlimitPosition).
           ;; ----------------------------------------------------------
           (if arg
               (let ( (newPosition   (car arg)) 
                      (limitPosition #IlimitPosition) )
                    (cond ( (> newPosition limitPosition)
                            (setf #Iposition limitPosition) )
                          ( (< newPosition -1)
                            (setf #Iposition -1) )
                          ( t
                            (setf #Iposition newPosition) )))
               ;;ELSE
               #Iposition))

atEnd (()	
       ;; -------------------------------------------------------------
       ;; Answer something true if the receiver is positioned at its
       ;; end else answer ().
       ;; -------------------------------------------------------------
	(equal #Iposition #IlimitPosition))

reset (()	
       ;; -------------------------------------------------------------
       ;; Position the receiver to its beginning.
       ;; -------------------------------------------------------------
	(setf #Iposition -1))

peek (()
      ;; -------------------------------------------------------------
      ;; Answer the next object in the receiver without advancing the
      ;; stream position. If the receiver is positioned at its end,
      ;; answer STREAMATEND.
      ;; -------------------------------------------------------------
	(let  ( (nextPosition (1+ #Iposition)) )
              (if (> nextPosition #IlimitPosition)
                  'STREAMATEND
                  ;;ELSE
                  [#Icollection at nextPosition])))

skipTo ((anObject)
        ;; -----------------------------------------------------------
        ;; Advance the receiver position to the next occurrence of
        ;; <anObject>, or if none to the end of stream. Answer t if
        ;; <anObject> occurred, else answer ().
        ;; -----------------------------------------------------------
	(let ( (collection    #Icollection)
               (nextPosition  #Iposition)
               (limitPosition #IlimitPosition) )
             (while (and (<= (incr nextPosition) limitPosition)
                         (nequal [collection at nextPosition] anObject)))
             (cond ( (> nextPosition limitPosition)
                     (setf #Iposition limitPosition)
                     () )
                   ( t
                     (setf #Iposition nextPosition)
                     t ))))

next ((aNumber)
      ;; -------------------------------------------------------------
      ;; Answer the next <aNumber> (or up to the end of stream) items
      ;; from the receiver, returned in a collection of the same 
      ;; species as the collection being streamed over.
      ;; -------------------------------------------------------------
	(let ( (collection    #Icollection)
               (nextPosition  #Iposition)
               (limitPosition #IlimitPosition)
               (items) )
             (while (and (> aNumber 0) (<= (incr nextPosition) limitPosition))
                    (newl items [collection at nextPosition])
                    (decr aNumber))
             (ifn items
                  'STREAMATEND
                  ;;ELSE
                  (setf #Iposition nextPosition)
                  [[collection class] new (nreverse items)])))
)]
 

