import cocos
import random
import pyglet

class MapLayer(cocos.tiles.RectMapLayer):

    def __init__(self):

        # Create tileset
        self.ground_tile = pyglet.image.load('img/ground.png')
        self.wall_tile = pyglet.image.load('img/wall.png')
        self.pavement_tile = pyglet.image.load('img/pavement.png')
        self.floor_tile = pyglet.image.load('img/floor.png')

        self.map_size = 1,1

        self.tileset = cocos.tiles.TileSet(0, None)
        self.tileset.add( {'passable':True,  'transparent':True  } , self.ground_tile, 'ground')
        self.tileset.add( {'passable':False, 'transparent':False } , self.wall_tile, 'wall')
        self.tileset.add( {'passable':True,  'transparent':True  } , self.pavement_tile, 'pavement')
        self.tileset.add( {'passable':True,  'transparent':True  } , self.floor_tile, 'floor')


        self.clear()

        self.apply_tileset()

        super(MapLayer, self).__init__('map', 32, 32, self.cells)

    def apply_tileset(self):
        for i in range(self.map_size[0]):
            for j in range(self.map_size[1]):
                self.cells[i][j] = cocos.tiles.RectCell(i,j,32,32,{},self.tileset[self.cells[i][j]])
        


    def clear(self):
        self.streets = []
        self.cells = []
        for i in range(self.map_size[0]):
            col = []
            for j in range(self.map_size[1]):
                col.append('wall')
            self.cells.append(col)

    def center_view(self, i, j):
        self.set_view(min(self.map_size[0]*32-600,max(i*32+16-300,0)),\
                      min(self.map_size[1]*32-600,max(j*32+16-300,0)),\
                      600,600)


    def generate_world(self, map_w, map_h):

        self.map_size = map_w, map_h
        self.clear()

        street_x = random.randint(7,self.map_size[0]-8)
        street_y = random.randint(7,self.map_size[1]-8)


        self.make_road(self.cells, street_x, 0, (0,1), self.map_size[1])
        self.streets.append([street_x, 0, (0,1), self.map_size[1], 3, 3])

        self.make_road(self.cells, 0, street_y, (1,0), self.map_size[0], 5, 2)
        self.streets.append([0, street_y, (1,0), self.map_size[0], 5, 2])

        street_y = random.randint(5,self.map_size[0]-6)

        self.make_road(self.cells, street_x, street_y, (1,0), min(self.map_size[0]-street_x-1, 30), 1, 0)
        self.streets.append([street_x, street_y, (1,0), min(self.map_size[0]-street_x-1, 30),1,0])

        for b in range(20):
            self.make_building(self.cells)

        self.apply_tileset()

    def make_road(self, cells, start_x, start_y, direction, length, width=3, pavement_width=3):

        for step in range(length):

            cur_x = start_x + step*direction[0]
            cur_y = start_y + step*direction[1]

            for k in range(pavement_width):
                cx = cur_x - (k+width/2+1) * abs(direction[1])
                cy = cur_y - (k+width/2+1) * abs(direction[0])
                if cells[cx][cy] == 'wall':
                    cells[cx][cy] = 'pavement'

                cx = cur_x + (k+width/2+1) * abs(direction[1])
                cy = cur_y + (k+width/2+1) * abs(direction[0])
                if cells[cx][cy] == 'wall':
                    cells[cx][cy] = 'pavement'

            for k in range(width):
                cx = cur_x + (k - width/2) * abs(direction[1])
                cy = cur_y + (k - width/2) * abs(direction[0])
                cells[cx][cy] = 'ground'

    def make_building(self, cells):
        road = self.streets[random.randint(0,len(self.streets)-1)]

        side = random.randint(0,1)*2 -1
        along = random.randint(3,road[3]-4)

        rdir = road[2]

        if abs(rdir[0] == 0):
            door_x = road[0]+side*(road[4]/2+road[5]+1)
            door_y = along + road[1]
        else:
            door_x = along + road[0]
            door_y = road[1]+side*(road[4]/2+road[5]+1)

        if cells[door_x][door_y] == 'wall':
            cells[door_x][door_y] = 'floor'

            max_size = random.randint(2,8)
            queue = []
            done = []

            if cells[door_x+side*abs(rdir[1])][door_y+side*abs(rdir[0])] == 'wall':
                queue.append((door_x+side*abs(rdir[1]),door_y+side*abs(rdir[0])))

            directions = [(-1,0),(1,0),(0,-1),(0,1)]

            while len(queue) > 0:
                to_remove = []

                cur = queue[0]
                #print queue
                #print max_size
                for d in directions:

                    if min(cur[0]+2*d[0], cur[0]+2*d[0]) >= 0 and \
                       cur[0]+2*d[0] < self.map_size[0] and \
                       cur[1]+2*d[1] < self.map_size[1] and \
                       d[0]*(cur[0]+d[0]) <= d[0]*(door_x+max_size*d[0]) and\
                       d[1]*(cur[1]+d[1]) <= d[1]*(door_y+max_size*d[1]) and\
                       cells[cur[0]+d[0]][cur[1]+d[1]] == 'wall' and \
                       cells[cur[0]+2*d[0]][cur[1]+2*d[1]] == 'wall':

                       newcell = (cur[0]+d[0],cur[1]+d[1])

                       if newcell not in queue and \
                          newcell not in done:
                            queue.append(newcell)
                    else:
                        pass#to_remove.append(d)
                for t in to_remove:
                    directions.remove(t)

                done.append(cur)
                queue.remove(cur)

            for d in done:
                cells[d[0]][d[1]] = 'floor'

    def get_free_position(self):
        x = random.randint(0,self.map_size[0]-1)
        y = random.randint(0,self.map_size[1]-1)
        while not self.get_cell(x,y)['passable']:
            x = random.randint(0,self.map_size[0]-1)
            y = random.randint(0,self.map_size[1]-1) 
        return x,y           

    def is_valid(self, i, j):
        return  i >= 0 and\
                i <  self.map_size[0] and\
                j >= 0 and\
                j <  self.map_size[1]

    def is_passable(self, i, j):
        return  self.is_valid(i, j) and\
                self.get_cell(i,j)['passable']