/* CookieJar ADT, Mutable Object-Oriented Version
   Using Scala HashMaps  (CookieJarMap)
   CSci 556: Multiparadigm Programming, Spring 2012
   CSci 555: Functional Programming, Spring 2016
   H. Conrad Cunningham, Professor
   Computer and Information Science
   University of Mississippi

1234567890123456789012345678901234567890123456789012345678901234567890

2010-Spring: Developed from mutable Ruby version
2012-Spring: Minor updates
2016-03-09:  Some cleanup of Scala code and comments
2022-04-18:  Scala 3 compatibility check, added Unit to procedures

*/

import scala.collection.mutable.HashMap

/* Class CookieJarMap implements the CookieJar ADT using Scala's
    HashMap to implement the jar (mathematical bag) of cookies.  The
    keys of the HashMap 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)  <=> (
         (i > 0  => jar(c) = i) && (i == 0 => !jar.contains(c))) )
*/

class CookieJarMap[CookieType] extends CookieJar[CookieType] {

  // CookieJar's bag model is implemented by Map jar.
  private val jar = new HashMap[CookieType,Int]()
 
  def putIn(cookie: CookieType): Unit = { 
    if (jar.contains(cookie)) 
      jar(cookie) += 1
    else 
      jar(cookie) = 1
  }
 
  def eat(cookie: CookieType): Unit = {
    if (jar.contains(cookie)) {
      if (jar(cookie) > 1)
        jar(cookie) -= 1
      else
        jar -= cookie
    }
    else 
      throw 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 "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 ((k,c) <- jar.toList; i <- 1 to c) yield k 

}

