/* CookieJarTupleList implementation of the CookieJar ADT in Scala
   H. Conrad Cunningham
   Version #1:  22 March 2010

123456789012345678901234567890123456789012345678901234567890123456789012345678

*/


/* Class CookieJarTupleList implements the CookieJar ADT using a Scala
   List of pairs to represent the jar (mathematical bag) of cookies.
   The first component of a pair is the CookieType and the second is
   the nonzero count of cookies with that type in the jar.  Each
   CookieType appears at most once in the list of tuples.

   IMPLEMENTATION INVARIANT: 
     (ForAll c : c IN CookieType :: jar.filter(_ == (c,_)).length <= 1) &&
     (ForAll c, i :  c IN CookieType && i IN Int ::
        jar.filter(_ == (c,i)).length == 1 <=> i>0 && OCCURENCES(c,Bag) = i))

*/

class CookieJarTupleList[CookieType] extends CookieJar[CookieType] {

  // CookieJar's bag model is implemented by List of (Cookietype,Int) tuples
  private var jar = List[(CookieType,Int)]()
 
  def putIn(cookie: CookieType) { 
    jar.span(_._1 != cookie) match {
      case (l,(_,i)::r) => jar = l ++ ((cookie,i+1)::r)
      case _            => jar = (cookie,1) :: jar
    }
  }
 
  def eat(cookie: CookieType) {
    jar.span(_._1 != cookie) match {
      case (l,(_,i)::r) => jar = l ++ (if (i>1) (cookie,i-1)::r else r)
      case _        => throw new RuntimeException(
        "Attempt to eat cookie \"" + cookie + "\", which is not in the jar.")
    }
   }
      
  def isEmpty: Boolean                 = jar.isEmpty

  def has(cookie: CookieType): Boolean = !jar.filter(_._1 == cookie).isEmpty

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

  override def toString = "CookieJar(" + jarList.mkString(",") + ")"


  /* Private method jarList converts the map jar to a list with with
     appropriate duplicates.  
  */

  private def jarList: List[CookieType] = 
    for ((c,i) <- jar ; j <- 1 to i) yield c

}
