import agents as ag
import envgui as gui 
import random

# ______________________________________________________________________________

loc_A, loc_B = (1, 1), (2, 1)  # The two locations for the Vacuum world


def RandomVacuumAgent():
    "Randomly choose one of the actions from the vacuum environment."
    p = ag.RandomAgentProgram(['Right', 'Left', 'Up', 'Down', 'Suck', 'NoOp'])
    return ag.Agent(p)

#needed comment
def TableDrivenVacuumAgent():
    "[Figure 2.3]"
    table = {((loc_A, 'Clean'),): 'Right',
             ((loc_A, 'Dirty'),): 'Suck',
             ((loc_B, 'Clean'),): 'Left',
             ((loc_B, 'Dirty'),): 'Suck',
             ((loc_A, 'Clean'), (loc_A, 'Clean')): 'Right',
             ((loc_A, 'Clean'), (loc_A, 'Dirty')): 'Suck',
             # ...
             ((loc_A, 'Clean'), (loc_A, 'Clean'), (loc_A, 'Clean')): 'Right',
             ((loc_A, 'Clean'), (loc_A, 'Clean'), (loc_A, 'Dirty')): 'Suck',
             # ...
             }
    p = ag.TableDrivenAgentProgram(table)
    return ag.Agent()


def ReflexVacuumAgent():
    "A reflex agent for the two-state vacuum environment. [Figure 2.8]"
    def program(percept):
        location, status = percept
        if status == 'Dirty':
            return 'Suck'
        elif location == loc_A:
            return 'Right'
        elif location == loc_B:
            return 'Left'
    return ag.Agent(program)


def ModelBasedVacuumAgent() -> object:
    "An agent that keeps track of what locations are clean or dirty."
    model = {loc_A: None, loc_B: None}

    def program(percept):
        "Same as ReflexVacuumAgent, except if everything is clean, do NoOp."
        location, status = percept
        model[location] = status  # Update the model here
        if model[loc_A] == model[loc_B] == 'Clean':
            return 'NoOp'
        elif status == 'Dirty':
            return 'Suck'
        elif location == loc_A:
            return 'Right'
        elif location == loc_B:
            return 'Left'
    return ag.Agent(program)

# ______________________________________________________________________________
# Vacuum environment

class Dirt(ag.Thing):
    pass

# class Floor(ag.Thing):
#     pass


class VacuumEnvironment(ag.XYEnvironment):

    """The environment of [Ex. 2.12]. Agent perceives dirty or clean,
    and bump (into obstacle) or not; 2D discrete world of unknown size;
    performance measure is 100 for each dirt cleaned, and -1 for
    each turn taken."""

    def __init__(self, width=4, height=3):
        super(VacuumEnvironment, self).__init__(width, height)
        self.add_walls()

    def thing_classes(self):
        return [ag.Wall, Dirt, ReflexVacuumAgent, RandomVacuumAgent,
                TableDrivenVacuumAgent, ModelBasedVacuumAgent]

    def percept(self, agent):
        """The percept is a tuple of ('Dirty' or 'Clean', 'Bump' or 'None').
        Unlike the TrivialVacuumEnvironment, location is NOT perceived."""
        status = ('Dirty' if self.some_things_at(
            agent.location, Dirt) else 'Clean')
        bump = ('Bump' if agent.bump else'None')
        return (bump, status)

    def execute_action(self, agent, action):
        if action == 'Suck':
            dirt_list = self.list_things_at(agent.location, Dirt)
            if dirt_list != []:
                dirt = dirt_list[0]
                agent.performance += 100
                self.delete_thing(dirt)
        else:
            super(VacuumEnvironment, self).execute_action(agent, action)

        if action != 'NoOp':
            agent.performance -= 1


class TrivialVacuumEnvironment(VacuumEnvironment):

    """This environment has two locations, A and B. Each can be Dirty
    or Clean.  The agent perceives its location and the location's
    status. This serves as an example of how to implement a simple
    Environment."""

    def __init__(self):
        super(TrivialVacuumEnvironment, self).__init__()
        choice = random.randint(0, 3)
        if choice % 2:  # 1 or 3
            self.add_thing(Dirt(), loc_A)
        if choice > 1:  # 2 or 3
            self.add_thing(Dirt(), loc_B)

    def percept(self, agent):
        "Returns the agent's location, and the location status (Dirty/Clean)."
        status = ('Dirty' if self.some_things_at(
            agent.location, Dirt) else 'Clean')
        return (agent.location, status)
    #
    # def execute_action(self, agent, action):
    #     """Change agent's location and/or location's status; track performance.
    #     Score 10 for each dirt cleaned; -1 for each move."""
    #     if action == 'Right':
    #         agent.location = loc_B
    #         agent.performance -= 1
    #     elif action == 'Left':
    #         agent.location = loc_A
    #         agent.performance -= 1
    #     elif action == 'Suck':
    #         if self.status[agent.location] == 'Dirty':
    #             agent.performance += 10
    #         self.status[agent.location] = 'Clean'
    #
    def add_agent(self, a):
        "Agents start in either location at random."
        super().add_thing(a, random.choice([loc_A, loc_B]))


# _________________________________________________________________________

# >>> a = ReflexVacuumAgent()
# >>> a.program((loc_A, 'Clean'))
# 'Right'
# >>> a.program((loc_B, 'Clean'))
# 'Left'
# >>> a.program((loc_A, 'Dirty'))
# 'Suck'
# >>> a.program((loc_A, 'Dirty'))
# 'Suck'
#
# >>> e = TrivialVacuumEnvironment()
# >>> e.add_thing(ModelBasedVacuumAgent())
# >>> e.run(5)

# Produces text-based status output
# v = TrivialVacuumEnvironment()
# a = ModelBasedVacuumAgent()
# a = ag.TraceAgent(a)
# v.add_agent(a)
# v.run(10)

# Launch GUI of Trivial Environment
# v = TrivialVacuumEnvironment()
# a = RandomVacuumAgent()
# a = ag.TraceAgent(a)
# v.add_agent(a)
# g = gui.EnvGUI(v, 'Vaccuum')
# c = g.getCanvas()
# c.mapImageNames({
#     Dirt: 'images/dirt.png',
#     ag.Wall: 'images/wall.jpg',
#     # Floor: 'images/floor.png',
#     ag.Agent: 'images/vacuum.png',
# })
# c.update()
# g.mainloop()

# Launch GUI of more complex environment
v = VacuumEnvironment(5, 4)
#a = ModelBasedVacuumAgent()
a = RandomVacuumAgent()
a = ag.TraceAgent(a)
loc = v.random_location_inbounds()
v.add_thing(a, location=loc)
v.scatter_things(Dirt)
g = gui.EnvGUI(v, 'Vaccuum')
c = g.getCanvas()
c.mapImageNames({
    ag.Wall: 'submissions/Gutierrez/grass.jpg',
    # Floor: 'images/floor.png',
    Dirt: 'submissions/Gutierrez/dirt.png',
    ag.Agent: 'submissions/Gutierrez/shovel.jpg',
})
c.update()
g.mainloop()