#!/usr/bin/env python
# -*- coding: utf-8 -*-

from gym_minigrid.minigrid import *
from gym_minigrid.register import register


class FourRoomsEnv(MiniGridEnv):
    """
    Classic 4 rooms gridworld environment.
    Can specify agent and goal position, if not it set at random.
    """

    def __init__(self, agent_pos=None, goal_pos=None):
        self._agent_default_pos = agent_pos
        self._goal_default_pos = goal_pos
        super().__init__(grid_size=19, max_steps=300)

    def _gen_grid(self, width, height):
        # Create the grid
        self.grid = Grid(width, height)

        # Generate the surrounding walls
        self.grid.horz_wall(0, 0)
        self.grid.horz_wall(0, height - 1)
        self.grid.vert_wall(0, 0)
        self.grid.vert_wall(width - 1, 0)

        room_w = width // 2
        room_h = height // 2

        # For each row of rooms
        for j in range(0, 2):

            # For each column
            for i in range(0, 2):
                xL = i * room_w
                yT = j * room_h
                xR = xL + room_w
                yB = yT + room_h

                # Bottom wall and door
                if i + 1 < 2:
                    self.grid.vert_wall(xR, yT, room_h)
                    pos = (xR, self._rand_int(yT + 1, yB))
                    self.grid.set(*pos, None)

                # Bottom wall and door
                if j + 1 < 2:
                    self.grid.horz_wall(xL, yB, room_w)
                    pos = (self._rand_int(xL + 1, xR), yB)
                    self.grid.set(*pos, None)

        # Randomize the player start position and orientation
        if self._agent_default_pos is not None:
            self.agent_pos = self._agent_default_pos
            self.grid.set(*self._agent_default_pos, None)
            self.agent_dir = self._rand_int(0, 4)  # assuming random start direction
        else:
            self.place_agent()

        if self._goal_default_pos is not None:
            goal = Goal()
            self.put_obj(goal, *self._goal_default_pos)
            goal.init_pos, goal.cur_pos = self._goal_default_pos
        else:
            self.place_obj(Goal())

        self.mission = 'Reach the goal'

    def step(self, action):
        obs, reward, done, info = MiniGridEnv.step(self, action)
        return obs, reward, done, info

class FourRoomsEnv_(MiniGridEnv):
    """
    Classic 4 rooms gridworld environment.
    Can specify agent and goal position, if not it set at random.
    """

    def __init__(self, agent_pos=None, goal_pos=None, seeds=0):
        self.seeds = seeds
        self._agent_default_pos = agent_pos
        self._goal_default_pos = (11,11)
        super().__init__(grid_size=13, max_steps=3000)

    def _gen_grid(self, width, height):
        # Create the grid
        self.grid = Grid(width, height)

        # Generate the surrounding walls
        self.grid.horz_wall(0, 0)
        self.grid.horz_wall(0, height - 1)
        self.grid.vert_wall(0, 0)
        self.grid.vert_wall(width - 1, 0)

        room_w = width // 2
        room_h = height // 2

        # For each row of rooms
        for j in range(0, 2):

            # For each column
            for i in range(0, 2):
                xL = i * room_w
                yT = j * room_h
                xR = xL + room_w
                yB = yT + room_h

                # Bottom wall and door
                if i + 1 < 2:
                    self.grid.vert_wall(xR, yT, room_h)
                    pos = (xR, (yT + 1 + yB)//2)
                    self.grid.set(*pos, None)

                # Bottom wall and door
                if j + 1 < 2:
                    self.grid.horz_wall(xL, yB, room_w)
                    pos = ((xL + 1 + xR)//2, yB)
                    self.grid.set(*pos, None)

        # Randomize the player start position and orientation
        if self._agent_default_pos is not None:
            self.agent_pos = self._agent_default_pos
            self.grid.set(*self._agent_default_pos, None)
            self.agent_dir = self._rand_int(0, 4)  # assuming random start direction
        else:
            self.place_agent()

        if self._goal_default_pos is not None:
            goal = Goal()
            self.put_obj(goal, *self._goal_default_pos)
            goal.init_pos, goal.cur_pos = self._goal_default_pos
        else:
            self.place_obj(Goal())

        self.mission = 'Reach the goal'

    def step(self, action):
        obs, reward, done, info = MiniGridEnv.step(self, action)
        return obs, reward, done, info

    def reset(self):
        if type(self.seeds)==int:
            self.seed(self.seeds)
        else:
            self.seed(self.seeds[np.random.randint(0,len(self.seeds))])
        return super().reset()

class FourRoomsEnv_1(FourRoomsEnv_):
    def __init__(self, agent_pos=None, goal_pos=None):
        a = np.random.randint(1,5)
        b = np.random.randint(1,5)
        super().__init__(agent_pos=(a,b))

class FourRoomsEnv_2(FourRoomsEnv_):
    def __init__(self, agent_pos=None, goal_pos=None):
        a = np.random.randint(7,12)
        b = np.random.randint(1,5)
        super().__init__(agent_pos=(b,a))

class FourRoomsEnv_3(FourRoomsEnv_):
    def __init__(self, agent_pos=None, goal_pos=None):
        a = np.random.randint(7,12)
        b = np.random.randint(1,5)
        super().__init__(agent_pos=(a,b))

class FourRoomsEnv_4(FourRoomsEnv_):
    def __init__(self, agent_pos=None, goal_pos=None):
        a = np.random.randint(7,10)
        b = np.random.randint(7,10)
        super().__init__(agent_pos=(a,b))

register(
    id='MiniGrid-FourRooms-v0',
    entry_point='gym_minigrid.envs:FourRoomsEnv'
)

register(
    id='MiniGrid-FourRooms-v1',
    entry_point='gym_minigrid.envs:FourRoomsEnv_1'
)

register(
    id='MiniGrid-FourRooms-v2',
    entry_point='gym_minigrid.envs:FourRoomsEnv_2'
)

register(
    id='MiniGrid-FourRooms-v3',
    entry_point='gym_minigrid.envs:FourRoomsEnv_3'
)
