/* CookieJar ADT, Immutable Method-Chaining Functions
   Using Immutable Scala Lists
   CSci 555: Functional Programming, Spring 2016
   H. Conrad Cunningham, Professor
   Computer and Information Science
   University of Mississippi

1234567890123456789012345678901234567890123456789012345678901234567890

2016-03-09: Developed immutable Scala version from 2010-12
            mutable Scala version

Class ICookieJarList implements the ICookieJar ADT using Scala's
immutable List data structure to represent the jar (mathematical bag)
of cookies.  The cookies occur in the list the same number of times
they do in the cookie jar.

   IMPLEMENTATION INVARIANT: 
     (ForAll c : c IN CookieType ::
                 OCCURRENCES(c,Bag(this)) == jar.filter(_==c).length)

   Remember that an implementation invariant must be made true by a
   data type constructor and each public mutator and accessor method
   must preserve it.  It must hold for all instances of the data type,
   including both explicit and implicit arguments of a method and the
   return values. That is, it is both a precondition and postcondition
   on all methods. An implementation invariant relates the values of
   the concrete data structures to the values of the model.

   Also remember that the data type's operations (functions,
   procedures, methods) must preserve the interface invariant and the
   preconditions and postconditions of the trait ICookieJar to be a
   subtype.

*/

class ICookieJarList[CookieType]
  (private val jar: List[CookieType])
  extends ICookieJar[CookieType] {
 
  def putIn(cookie: CookieType): ICookieJar[CookieType] =
    new ICookieJarList(cookie :: jar)
 
  def eat(cookie: CookieType) : ICookieJar[CookieType] =
    jar.span(_ != cookie) match { // pair (not equal from head, rest)
      case (l,_::r) => new ICookieJarList(l ++ r)
      case _        => sys.error("Attempt to eat cookie \"" +
                         cookie + "\", which is not in the jar.")
    }
      
  def isEmpty: Boolean = jar.isEmpty

  def has(cookie: CookieType): Boolean = jar.contains(cookie)

  /* Redefine toString to return form "ICookieJar(e1,e2,e3,...,en)"
     with all elements of bag in arbitrary order.  */

  override def toString = "ICookieJar(" + jar.mkString(",") + ")"

}

