import cocos
import random
from math import sqrt
from cocos.actions import *

class Policeman:

    def __init__(self, map, item_layer, player):

        self.pos = None

        self.map = map
        self.item_layer = item_layer

        self.sprites = {}
        self.sprites['hat'] = cocos.sprite.Sprite('img/hat.png')
        self.sprites['torso'] = cocos.sprite.Sprite('img/torso.png')
        self.sprites['legs'] = cocos.sprite.Sprite('img/legs.png')
        self.sprites['head'] = cocos.sprite.Sprite('img/head.png')


        self.shapes = { 'hat':'_policeman',\
                        'torso':'_policeman',\
                        'legs':''}

        self.colors = { 'hat':'_black',\
                        'torso':'_black',\
                        'legs':'_black'}

        self.current = {'hat':['',''],\
                        'torso':['',''],\
                        'legs':['','']}


        self.chasing = False
        self.alert = False

        self.player = player

    def reveal_shape(self, what, criteria):
        if what in self.sprites and self.shapes[what] == criteria:
          self.current[what][0] = self.shapes[what]
          self.remove_from_layer(self.item_layer)
          self.sprites[what] = cocos.sprite.Sprite('img/'+what+self.current[what][0]+self.current[what][1]+'.png')
          self.sprites[what].visible = self.sprites['head'].visible
          self.add_to_layer(self.item_layer)

    def reveal_color(self, what, criteria):
        if what in self.sprites and self.colors[what] == criteria:
          self.current[what][1] = self.colors[what]
          self.remove_from_layer(self.item_layer)
          self.sprites[what] = cocos.sprite.Sprite('img/'+what+self.current[what][0]+self.current[what][1]+'.png')
          self.sprites[what].visible = self.sprites['head'].visible
          self.add_to_layer(self.item_layer)


    def reveal(self, what):
        if what in self.sprites:
            self.sprites[what].color = self.colors[what]

    def set_pos(self, i, j, force=False):
        self.pos = i,j
        for s in self.sprites:
            if force:
                self.sprites[s].position = i*32+16, j*32+16
            else:
                self.sprites[s].do(MoveTo((i*32+16, j*32+16), duration=0.2))


    def astar(self, start, end):
      if start == end:
        return end
      done = []
      queue = [start]
      came_from = {}
      g_score = {start:0}
      f_score = {start:g_score[start] + sqrt((start[0]-end[0])**2 + (start[1]-end[1])**2) }

      while len(queue) > 0:
        current = queue[0]
        for q in queue:
          if f_score[q] < f_score[current]:
            current = q

        if current == end:
          return came_from[current]

        queue.remove(current)
        done.append(current)

        directions = [(-1,0),(1,0),(0,-1),(0,1)]
        directions = random.sample(directions, 4)
        for d in directions:
          if current[0]+d[0] > 0 and current[0]+d[0] < self.map.map_size[0] and \
             current[1]+d[1] > 0 and current[1]+d[1] < self.map.map_size[1] and \
             (current[0]+d[0], current[1]+d[1]) not in done: 

             neighbor = (current[0]+d[0], current[1]+d[1])
             if self.map.get_cell(neighbor[0], neighbor[1])['passable']:
                tentative_g_score = g_score[current] + 1
             else:
                tentative_g_score = 1e12

             if neighbor not in queue or tentative_g_score <= g_score[neighbor]:
                came_from[neighbor] = current
                g_score[neighbor] = tentative_g_score
                f_score[neighbor] = g_score[neighbor] + sqrt((neighbor[0]-end[0])**2 + (neighbor[1]-end[1])**2) 
                if neighbor not in queue:
                  queue.append(neighbor)

      return (-1,-1)


    def update(self):

        if self.pos is not None:

            if self.chasing:
                skip = random.randint(0,8)
                if skip == 0:
                    return

                new_pos = self.astar((self.player.pos[0],self.player.pos[1]),(self.pos[0], self.pos[1]))
            else:
                directions = [(-1,0),(1,0),(0,-1),(0,1)]
                direction = directions[random.randint(0,3)]
                new_pos = self.pos[0]+direction[0], self.pos[1]+direction[1]
            if self.map.is_passable(*new_pos):
                self.item_layer.items[new_pos[0]][new_pos[1]].append(self)
                self.item_layer.items[self.pos[0]][self.pos[1]].remove(self)
                self.set_pos(*new_pos)


            for s in self.sprites:
                self.sprites[s].position = self.pos[0]*32+16, self.pos[1]*32+16

            if self.chasing:
                px = self.player.pos[0]
                py = self.player.pos[1]
                if px == self.pos[0] and py == self.pos[1]:
                    self.item_layer.lose()

                self.chasing = False

    def update_visibility(self, value):

        for s in self.sprites:
            self.sprites[s].visible = value

    def add_to_layer(self, layer):
        layer.add(self.sprites['head'], z=10)
        layer.add(self.sprites['legs'], z=11)
        layer.add(self.sprites['torso'], z=12)
        layer.add(self.sprites['hat'], z=13)
        self.set_pos(*self.pos, force=True)

    def remove_from_layer(self, layer):
        for s in self.sprites:
            layer.remove(self.sprites[s])