"""Assignment 1 - Grocery Store Events (Task 2)

This file should contain all of the classes necessary to model the different
kinds of events in the simulation.
"""
# Feel free to import classes and functions from
# *your other files*, but remember not to import any external libraries.

from store import *





class Event:
    """An event.

    Events have an ordering based on the event timestamp in non-ascending
    order. Events with older timestamps are less than those with newer
    timestamps.

    This class is abstract; subclasses must implement do().

    You may, if you wish, change the API of this class to add
    extra public methods or attributes. Make sure that anything
    you add makes sense for ALL events, and not just a particular
    event type.

    Document any such changes carefully!

    === Attributes ===
    @type timestamp: int
        A timestamp for this event.
    """
    def __init__(self, timestamp):
        """Initialize an Event with a given timestamp.

        @type self: Event
        @type timestamp: int
            A timestamp for this event.
            Precondition: must be a non-negative integer.
        @rtype: None

        >>> Event(7).timestamp
        7
        """
        self.timestamp = timestamp

    # The following six 'magic methods' are overridden to allow for easy
    # comparison of Event instances. All comparisons simply perform the
    # same comparison on the 'timestamp' attribute of the two events.
    def __eq__(self, other):
        """Return whether this Event is equal to <other>.

        Two events are equal if they have the same timestamp.

        @type self: Event
        @type other: Event
        @rtype: bool

        >>> first = Event(1)
        >>> second = Event(2)
        >>> first == second
        False
        >>> second.timestamp = first.timestamp
        >>> first == second
        True
        """
        return self.timestamp == other.timestamp

    def __ne__(self, other):
        """Return True iff this Event is not equal to <other>.

        @type self: Event
        @type other: Event
        @rtype: bool

        >>> first = Event(1)
        >>> second = Event(2)
        >>> first != second
        True
        >>> second.timestamp = first.timestamp
        >>> first != second
        False
        """
        return not self.__eq__(other)

    def __lt__(self, other):
        """Return True iff this Event is less than <other>.

        @type self: Event
        @type other: Event
        @rtype: bool

        >>> first = Event(1)
        >>> second = Event(2)
        >>> first < second
        True
        >>> second < first
        False
        """
        return self.timestamp < other.timestamp

    def __le__(self, other):
        """Return True iff this Event is less than or equal to <other>.

        @type self: Event
        @type other: Event
        @rtype: bool

        >>> first = Event(1)
        >>> second = Event(2)
        >>> first <= first
        True
        >>> first <= second
        True
        >>> second <= first
        False
        """
        return self.timestamp <= other.timestamp

    def __gt__(self, other):
        """Return True iff this Event is greater than <other>.

        @type self: Event
        @type other: Event
        @rtype: bool

        >>> first = Event(1)
        >>> second = Event(2)
        >>> first > second
        False
        >>> second > first
        True
        """
        return not self.__le__(other)

    def __ge__(self, other):
        """Return True iff this Event is greater than or equal to <other>.

        @type self: Event
        @type other: Event
        @rtype: bool

        >>> first = Event(1)
        >>> second = Event(2)
        >>> first >= first
        True
        >>> first >= second
        False
        >>> second >= first
        True
        """
        return not self.__lt__(other)

    def do(self, store):
        """Perform this Event.

        Call methods on <store> to update its state according to the
        meaning of the event. Note: the "business logic" of what actually
        happens inside a grocery store should be handled in the GroceryStore
        class, not in any Event classes.

        Return a list of new events spawned by this event (making sure the
        timestamps are correct).

        @type self: Event
        @type store: GroceryStore
        @rtype: list[Event]
            A list of events generated by performing this event.
        """
        raise NotImplementedError


# TODO: Create subclasses for the different types of events below.


class EventJoin(Event):
    """A subclass of  Event.
    This is a event when a new customer joins a checkout line
    
    === Attributes ===
    @type timestamp: int
        A timestamp for this event.
    @type customer: Customer
        A customer
    """
    def __init__(self,timestamp,customer):
        super().__init__(timestamp)
        self.timestamp = timestamp
        self.customer = customer

    def do(self, store, customer):
        """a new checking out event is added when join an empty line"""
        new_event = []
        line = store.assign_customer(self.customer)
        if line.people_in_line == 0:
            new_event.append[EventBegin(self.timestamp, customer)
            return new_event
        return None


class EventBegin(Event):
    """A subclass of  Event.
    This is a event when a customer begins checking out
    
    === Attributes ===
    @type timestamp: int
        A timestamp for this event.
    @type customer: Customer
        A customer
    """

    def __init__(self, timestamp, customer):
        super().__init__(timestamp)
        self.timestamp = timestamp
        self.customer = customer



    def do(self,store,customer):
        """ if a customer begins checking out, a new"finish checking out" event is added
            with the stamp = "begin" timestamp + time spend on check out """
        new_event = []
        line = store._customer_to_line[customer]
        n = customer.number_of_items
        if isinstance(line, cashierline):
            checkout_time = store.get_cashier_time(n)
        elif isinstance(line, expressline):
            checkout_time = store.get_express_time(n)
        elif isinstance(line, selfserveline):
            checkout_time = store.get_self_serve_time(n)
        new_event = EventFinish(checkout_time+self.timestamp, customer)
        return new_event



class EventFinish(Event):
    """A subclass of  Event.
    A event when a customer finishes checking out    
    === Attributes ===
    @type timestamp: int
        A timestamp for this event.
    @type customer: Customer
        A customer
    """

    def __init__(self,timestamp):
        super().__init__(timestamp)

        self.timestamp = timestamp
        self.customer = customer

    def do(self,store,customer,file):
        """A customer finishes checking out , the next customer in the line(if there is one
           gets a "begin checking out " event with the same timestamp as the "finish" event"""
        line = store._customer_to_line[customer]
        line.people_in_line -= 1
        queue = store.get_event(file)
        next_customer = store.get_next_customer(queue, customer)
        if next_customer != None:
            new_event = EventBegin(customer.timestamp, next_customer)
            return new_event
        return None

class EventClose(Event):
    """A subclass of  Event.
    This is a event when a line closes.
    
    === Attributes ===
    @type timestamp: int
        A timestamp for this event.
    @type customer: Customer
        A customer
    """

    def __init__(self, timestamp):
        super().__init__(timestamp)
        self.timestamp = timestamp

    def __repr__(self):
        return "EventClose({})".format(repr(self.timestamp))

    def do(self,store):
        """ customer join other lines, timestamp updated"""







# TODO: Complete this function, which creates a list of events from a file.
def create_event_list(filename):
    """Return a list of Events based on raw list of events in <filename>.

    Precondition: the file stored at <filename> is in the format specified
    by the assignment handout.

    @param filename: str
        The name of a file that contains the list of events.
    @rtype: list[Event]
    """
    events = []
    with open(filename, 'r') as file:
        for line in file:

            # Create a list of words in the line, e.g.
            # ['60', 'Arrive', 'Bob', '5'].
            # Note that these are strings, and you'll need to convert some of
            # them to ints.

            tokens = line.split()
            if tokens[1] == 'Arrive':
                customer = Customer(tokens[2],int(tokens[-1]))
                events.append(EventJoin(int(tokens[0]),customer))
            else:
                events.append(EventClose(int(tokens[0])))

    return events


if __name__ == '__main__':
    import doctest
    doctest.testmod()
