# CookieJar ADT: Python Unordered List Implementation (Standard Mutable)
#
# 345678901234567890123456789012345678901234567890123456789012345678901234567890
#
# 2018-10-10: Unordered List version adapted from Dict version
# 2018-10-11: Corrected/improved statement of invariant
# 2022-04-20: Improved comments. Reformatted with black.

from typing import List, Generic, TypeVar
from dataclasses import dataclass, field  # 3.7

from cookiejar import CookieJarABC, CookieType

# Class CookieJarList implements the CookieJar ADT using a Python List data
# type to implement the jar (mathematical bag) of cookies.  The list elements
# are the cookie types with one occurrence for each occurrence in the cookie
# jar. The list is not required to be arranged in a particular order (i.e.,
# "unordered").
#
#   IMPLEMENTATION INVARIANT:
#     (ForAll c : c IN CookieType :: OCCURRENCES(c,Bag(self))  == jar.count(c))

# The @dataclass decorator generates default __init__ and __repr__ methods for
# the CookieJarList class. Setting the intial value of jar to
# field(default_factory=List) causes the initial value to be an empty list.


@dataclass
class CookieJarList(CookieJarABC, Generic[CookieType]):
    jar: List[CookieType] = field(default_factory=list)

    def put_in(self, cookie: CookieType) -> None:
        """Insert "cookie" into this cookie jar"""
        self.jar.append(cookie)

    def eat(self, cookie: CookieType) -> None:
        """Remove "cookie" from this cookie jar"""
        if cookie in self.jar:
            self.jar.remove(cookie)
        else:
            print(f"Error: No cookie of type {cookie} in jar to eat")

    def is_empty(self) -> bool:
        """Is this cookie jar empty?"""
        return len(self.jar) == 0

    def has(self, cookie: CookieType) -> bool:
        """Is "cookie" in this cookie jar?"""
        return cookie in self.jar
