__author__ = 'Anselmo'

from PPlay.window import *
from PPlay.keyboard import *
from PPlay.gameimage import *
from PPlay.sprite import *

janela = Window(640,640)
janela.set_title("Andando")
janela.set_background_color((0,0,0))

teclado = Keyboard()

#animações
SR = 0
SL = 1
WR = 2
WL = 3

NULL = 0
HOR = 1
VER = 2

TIJOLO = 1

TAM_TILE_X = 64
TAM_TILE_Y = 64

METADE_TAM_TILE_X = TAM_TILE_X /2
METADE_TAM_TILE_Y = TAM_TILE_Y /2

#velocidade de caminhada
VEL_HEROI = 200
VEL_PULO = 2.5*VEL_HEROI

CHAO = 1
GRAMA = 2
TIJOLO = 3
PORTAINF = 4
PORTAMEIO = 5
PORTASUP = 6
ESCADA = 7
PAREDE = 8
CHAVE = 9

#tolerancia da distância ao chão
TOL_CHAO = 5

#gravidade
G  = -980


# Converte coordenadas em pixels em indices i e j na matriz
def coordToCellIndex(posX,posY):
    # a soma com 16 coloca as coordenadas no centro da figura
    # a divisão por 32 truncada informa o indice
    celX = int(posX / TAM_TILE_X)
    celY = int(posY / TAM_TILE_Y)

    return celX,celY

# Converte o indice da matriz em coordenadas em pixels
def celIndexToCoord(celX,celY):
    return celX*TAM_TILE_X,celY*TAM_TILE_Y

def valida(platforma,col,lin):
    return col>=0 and col<len(platforma[0]) and lin>=0 and lin<len(platforma)


def transformarCoordMundoParaJanela(xm,ym,camera):
    xj = xm - int(camera["posX"])
    yj = -(ym - int(camera["posY"]))

    return xj,yj

def estaNoChao(heroi):
    return heroi["noChao"]

def estaNaEscada(heroi):
    return heroi["naEscada"]

def ehCelulaColisao(celinfo):
    return celinfo["tile"]==TIJOLO or celinfo["tile"]==CHAO or celinfo["tile"]==GRAMA or celinfo["tile"]==ESCADA

def ehCelulaDeBloqueio(celinfo):
    return celinfo["tile"]==TIJOLO or celinfo["tile"]==CHAO or celinfo["tile"]==GRAMA

def ehCelulaEscada(celinfo):
    return celinfo["tile"]==ESCADA

def ehCelulaPiso(cel):
    return cel[2]=="BB" or cel[2]=="EBB" or cel[2]=="DBB"

def ehCelulaTeto(cel):
    return cel[2]=="C"

def ehCelulaEsquerda(cel):
    return cel[2]=="E" or cel[2]=="EB" or cel[2]=="EC"

def ehCelulaDireita(cel):
    return cel[2]=="D" or cel[2]=="DB" or cel[2]=="DC"

def lePlataforma(nomeArq):

    # Abre o arquivo que descreve a plataforma
    f = open(nomeArq,'r')

    # cria uma variável que receberá a matriz que descrever o conjunto de tijolos da plataforma
    plataforma = []

    # para cada linha no arquivo referenciado por f
    for linha in f:
        #cria uma linha vazia
        lin = []

        # para cada elemento na linha
        for value in linha.split():
            #insere valor convertido para inteiro
            lin.append(int(value))
        #insere linha na matriz
        plataforma.append(lin)


    #fechar arquivo
    f.close()

    print(plataforma)

    return plataforma

def posicionarTile(tile,i,j,camera):
    posX,posY = celIndexToCoord(j,i+1)
    xs,ys = transformarCoordMundoParaJanela(posX,posY,camera)
    tile.set_position(xs,ys)


def desenharTile(tile,i,j,camera):
    #desenha o tijolo
    posicionarTile(tile,i,j,camera)
    tile.draw()


def desenharPlataforma(plataforma,tileMap,camera):
    # numero de linhas da matriz
    numLin = len(plataforma)
    # numero de colunas da matriz
    numCol = len(plataforma[0])
    # para todos os elementos

    numCelXJanela = int(janela.width/TAM_TILE_X)
    numCelYJanela = int(janela.height/TAM_TILE_Y)
    celX,celY = coordToCellIndex(camera["posX"],camera["posY"])

    for i in range (celY-numCelYJanela-1,celY):
        for j in range (celX,celX+numCelXJanela+1):
            # obtem o tipo do tile na posição (lin,col) da matriz
            lin = numLin-i-1
            col = j
            if (valida(plataforma,col,lin)):
                tile = plataforma[lin][col]
                if (tile != 0):
                    #desenha o tijolo
                    desenharTile(tileMap[tile],i,j,camera)


def getHeroiCenterCell(heroi):
    hsprite = getAnimAtiva(heroi)
    posX = heroi["posX"]+hsprite.width/2
    posY = heroi["posY"]-hsprite.height/2
    celX, celY = coordToCellIndex(posX,posY)

    return celX,celY

def criarListaCelulasCandidatas(heroi):

    cels = []


    if (heroi["velX"]>0):
        cels = [(1,0,"D"),(1,1,"DC"),(1,-1,"DB")]
    elif (heroi["velX"]<0):
        cels = [(-1,0,"E"),(-1,1,"EC"),(-1,-1,"EB")]
    elif (heroi["velX"]==0):
        cels = [(0,0,"C"),(0,-1,"B"),(0,-2,"BB")]

    if (heroi["velY"]>0):
         cels.append((0,1,"C"))
    elif (heroi["velY"]<=0):
         cels.append((0,-2,"BB"))
         cels.append((-1,-2,"EBB"))
         cels.append((1,-2,"DBB"))


    return cels

def colisaoPlataforma(heroi,tileMap,plataforma):
    colisoes = []

    # numero de linhas da matriz
    numLin = len(plataforma)
    # numero de colunas da matriz
    numCol = len(plataforma[0])

    # para todos os elementos
    hcelX, hcelY = getHeroiCenterCell(heroi)
    hsprite = getAnimAtiva(heroi)
    celsCandidatas = criarListaCelulasCandidatas(heroi)

    for cel in celsCandidatas:
        celX = hcelX+cel[0]
        celY = hcelY+cel[1]
        lin = numLin-celY-1
        col = celX

        if (valida(plataforma,col,lin)):
            tile = plataforma[lin][col]
            if (tile == CHAO) or (tile == GRAMA) or (tile == TIJOLO) or (tile == ESCADA):
                posicionarTile(tileMap[tile],celY,celX,camera)
                #Tratar colisao do paredes
                if not ehCelulaPiso(cel):
                    if (hsprite.collided(tileMap[tile])):
                        celinfo = dict(cel = cel, tile = tile)
                        colisoes.append(celinfo)
                #Tratar colisao com o chao
                else:
                    if (hsprite.collided_perfect(tileMap[tile])):
                        celinfo = dict(cel = cel, tile = tile)
                        colisoes.append(celinfo)

    return colisoes

def tratarColisao(heroi,colisoes):
    heroi["noChao"] = False
    heroi["naEscada"] = False

    for celinfo in colisoes:

        if ehCelulaDeBloqueio(celinfo):
            if ehCelulaDireita(celinfo["cel"]):
                if (heroi["velX"]>0):
                    heroi["velX"] = 0
            elif ehCelulaEsquerda(celinfo["cel"]):
                if (heroi["velX"]<0):
                    heroi["velX"] = 0
            elif ehCelulaTeto(celinfo["cel"]):
                heroi["velY"] = 0

            if ehCelulaPiso(celinfo["cel"]):
                if (heroi["velY"] <= 0) and not estaNaEscada(heroi):
                    heroi["velY"] = 0
                    heroi["noChao"] = True

        if ehCelulaEscada(celinfo):
            heroi["naEscada"] = True


def criarHeroi():


    sh0 = Sprite("sr.png",1)
    sh0.set_sequence(0,1)
    sh0.set_total_duration(100)

    sh1 = Sprite("sl.png",1)
    sh1.set_sequence(0,1)
    sh1.set_total_duration(100)

    sh2 = Sprite("wr.png",6)
    sh2.set_sequence(0,6)
    sh2.set_total_duration(800)

    sh3 = Sprite("wl.png",6)
    sh3.set_sequence(0,6)
    sh3.set_total_duration(800)


    animacoes = [sh0,sh1,sh2,sh3]


    heroi = dict(anim = animacoes, animAtiva = SR,
                 posX = sh0.width, posY = 277 ,
                 velX = 0, velY = 0,
                 noChao = True,
                 naEscada = False)

    return heroi

def getAnimAtiva(heroi):
    animAtiva = heroi["animAtiva"]
    return heroi["anim"][animAtiva]

def setAnimAtiva(heroi,novaAnim):
    heroi["animAtiva"] = novaAnim

def desenharHeroi(heroi,camera):
    posx = heroi["posX"]
    posy = heroi["posY"]
    sprite = getAnimAtiva(heroi)
    sprite.update()
    xj,yj = transformarCoordMundoParaJanela(posx,posy,camera)
    sprite.set_position(xj,yj)
    sprite.draw()

def moverHeroi(heroi,camera):
    dt = janela.delta_time()
    heroi["posX"] += dt*heroi["velX"]
    heroi["posY"] += dt*heroi["velY"]

    camera["posX"] = heroi["posX"]-65
    camera["posY"] = heroi["posY"]+426

    if (not estaNoChao(heroi) and not estaNaEscada(heroi)):
        heroi["velY"] += G*dt
    else:
        heroi["velY"] = 0

def capturarEntrada(heroi):
    if (teclado.key_pressed("LEFT")):
        setAnimAtiva(heroi,WL)
        heroi["velX"] = -VEL_HEROI
    elif (teclado.key_pressed("RIGHT")):
        setAnimAtiva(heroi,WR)
        heroi["velX"] = VEL_HEROI
    elif (teclado.key_pressed("UP") and estaNaEscada(heroi)):
        heroi["velY"] = VEL_PULO/2
    elif (teclado.key_pressed("DOWN") and estaNaEscada(heroi)):
        heroi["velY"] = -VEL_PULO/2

    else:
        if (heroi["animAtiva"]==WR):
            setAnimAtiva(heroi,SR)
            heroi["velX"] = 0
        elif (heroi["animAtiva"]==WL):
            setAnimAtiva(heroi,SL)
            heroi["velX"] = 0

    if (teclado.key_pressed("SPACE") and estaNoChao(heroi) and not estaNaEscada(heroi)):
        heroi["noChao"] = False
        heroi["velY"] = VEL_PULO

def criarFundo():
    fundo = dict(sprite = GameImage("seamlessbackground.jpg"),posX = 0, posY = 640)
    return fundo


def desenharFundo(fundo,camera):

    #corrije posicao quando ultrapassar os limites do fundo
    if (camera["posX"]>=fundo["posX"]+fundo["sprite"].width):
         fundo["posX"] += fundo["sprite"].width
    elif (camera["posX"]<=fundo["posX"]):
         fundo["posX"] -= fundo["sprite"].width

    posx = fundo["posX"]
    posy = fundo["posY"]
    xj,yj = transformarCoordMundoParaJanela(posx,posy,camera)
    fundo["sprite"].set_position(xj,yj)
    fundo["sprite"].draw()

    #desenha novamente
    xj,yj = transformarCoordMundoParaJanela(posx+fundo["sprite"].width,posy,camera)
    fundo["sprite"].set_position(xj,yj)
    fundo["sprite"].draw()

def criarCamera():
    camera = dict(posX = 0, posY = janela.width)
    return camera

fundo = criarFundo()

heroi = criarHeroi()

camera = criarCamera()

plataforma = lePlataforma("platforma.txt")

tijolo = Sprite("beaten_brick_tiled.png")
chao1 = Sprite("ground1.png")
chao0 = Sprite("ground0.png")
porta0 = Sprite("door0a.png")
porta1 = Sprite("door1a.png")
porta2 = Sprite("door2a.png")
escada = Sprite("ladderb.png")
parede = Sprite("parede.png")
chave = Sprite("chave.png")

POS_CHAO = chao0.width + chao1.width + getAnimAtiva(heroi).height

tileMap = [NULL,chao0,chao1,tijolo,porta0,porta1,porta2,escada,parede,chave]

while True:
    janela.set_background_color((175,214,255))
    capturarEntrada(heroi)
    desenharFundo(fundo,camera)
    desenharPlataforma(plataforma,tileMap,camera)
    colisoes = colisaoPlataforma(heroi,tileMap,plataforma)
    #print(colisoes)
    tratarColisao(heroi,colisoes)
    moverHeroi(heroi,camera)
    desenharHeroi(heroi,camera)
    janela.update()