/* CookieJar ADT, Immutable Method-Chaining Functions
   Using Immutable Scala HashMaps
   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 ICookieJarMap implements the CookieJar ADT using Scala's
   immutable HashMap to represent the jar (mathematical bag) of
   cookies.  The keys of the Map are the cookie types and the value is
   the count of cookies of that type in the jar.  If the count is
   zero, then that key does not appear in the map.

   IMPLEMENTATION INVARIANT: 
     (ForAll c, i : c IN CookieType && i IN Int ::
       i == OCCURRENCES(c,Bag(this))  <=> (
         (i > 0  => jar(c) = i) && (i == 0 => !jar.contains(c))) )
*/

import scala.collection.immutable.HashMap

class ICookieJarMap[CookieType]
  (private val jar: HashMap[CookieType,Int])
  extends ICookieJar[CookieType] {
 
  def putIn(cookie: CookieType): ICookieJar[CookieType] =
    if (jar.contains(cookie))
      new ICookieJarMap(jar.updated(cookie,jar(cookie)+1))
    else 
      new ICookieJarMap(jar.updated(cookie,1))
 
  def eat(cookie: CookieType): ICookieJar[CookieType] =
    if (jar.contains(cookie)) {
      val nc = jar(cookie)
      if (nc > 1)
        new ICookieJarMap(jar.updated(cookie,nc-1))
      else
        new ICookieJarMap(jar-cookie)
    }
    else 
      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(" + jarList.mkString(",") + ")"


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

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

}

