__author__ = 'Anselmo'

from PPlay.window import *
from PPlay.gameimage import *
from PPlay.sound import *
from PPlay.sprite import *
import math

window = Window(800,600)
window.set_title("Hello World PPlay")
window.set_background_color((0,0,255))
window.update()

keyboard = window.get_keyboard()

SLOW_SPEED = 64
NORMAL_SPEED = 128
FAST_SPEED = 256

KEYBOARD_DELAY_TIME = 250

NEXT_ENEMY_SCORE_INC = 1000
TIME_SCORE_INC = 10

HERO_LEFT_BORDER = 64
HERO_RIGHT_BORDER = window.width-64
HERO_BOTTOM_BORDER = window.height-180

ANIMATION_DURATION = 2000
AUDIO_FADEOUT = 500
SHOT_DELAY_TIME = 500

ENTRANCE = 0
INITIALIZATION = 1
PLAYING = 2
ENDING = 3

STANDING_RIGHT = 0
WALKING_RIGHT = 1
STANDING_LEFT = 2
WALKING_LEFT = 3
JUMPING = 4

GRAVITY = 980

score = 0
lives = 3
level = 0
nextEnemyScore = 10000
beginningTime = 0
angle = -math.pi
lastKeyboardInput = window.delta_time()

background = GameImage("forestbackground.png")

gameLoopState = ENTRANCE

# Sprite from :
# http://atomicrobotdesign.com/blog/web-development/more-advanced-html5-canvas-sprite-sheet-walk-cycle-animation/

# audio = Sound("entrance.ogg")
# soundtrack = Sound("lenoverde.ogg")
# explosionHit = Sound("explosion-01.ogg")
# explosion = Sound("explosion-03.ogg")

def isHeroGrounded(hero):
    if (hero['sprite'].y >= HERO_BOTTOM_BORDER):
        return True
    else:
        return False

def isHeroOnPlatform(hero,platforms):
    collidedPlatforms = detectCollisionPlatform(hero,platforms)
    grounded = False
    posy = -1
    for platform in collidedPlatforms:
        heroPosxMin = hero['sprite'].x
        heroPosxMax = hero['sprite'].x+hero['sprite'].width
        heroPosyMin = hero['sprite'].y+hero['sprite'].height

        heroPosyMin = hero['sprite'].y+hero['sprite'].height
        platformPosxMin = platform['sprite'].x
        platformPosxMax = platform['sprite'].x+platform['sprite'].width
        platformPosyMax = platform['sprite'].y

        #print(hero['sprite'].y,heroPosyMin,platformPosyMax)
        if (heroPosyMin-platformPosyMax)>1 and (heroPosyMin-platformPosyMax)<10 \
                and (heroPosxMin>platformPosxMin-hero['sprite'].width//2)\
                and  (heroPosxMin<platformPosxMax-hero['sprite'].width//2)\
                and (hero['speedy']>=0):
            grounded, posy  = True, platformPosyMax

    return grounded, posy


def setAnimationSequenceHero(hero,sequence):
    hero['previousSequence'] = hero['sequence']
    hero['sequence'] = sequence
    if (sequence == WALKING_RIGHT):
        hero['sprite'].set_sequence(0,11);
        hero['speedx'] = NORMAL_SPEED
    elif (sequence == WALKING_LEFT):
        hero['sprite'].set_sequence(11,21);
        hero['speedx'] = -NORMAL_SPEED
    elif (sequence == STANDING_RIGHT):
        hero['sprite'].set_sequence(23,24);
        hero['speedx'] = 0
    elif (sequence == STANDING_LEFT):
        hero['sprite'].set_sequence(22,23);
        hero['speedx'] = 0
    elif (sequence == JUMPING):
        if (hero['previousSequence'] == WALKING_LEFT):
            hero['speedx'] = -NORMAL_SPEED
            hero['sprite'].set_sequence(22,23);
        elif (hero['previousSequence'] == WALKING_RIGHT):
            hero['speedx'] = NORMAL_SPEED
            hero['sprite'].set_sequence(23,24);
        hero['speedy'] = -3*NORMAL_SPEED

def keyBoardInput(hero,platforms):
    global lastKeyboardInput
    currentTick = window.last_time
    if (currentTick - lastKeyboardInput > 0):
        lastKeyboardInput = currentTick
        if (keyboard.key_pressed("ESC")):
            window.close()
        elif (keyboard.key_pressed("LEFT")):
            if hero['sequence']!= WALKING_LEFT:
                setAnimationSequenceHero(hero,WALKING_LEFT)
        elif (keyboard.key_pressed("RIGHT")):
            if hero['sequence']!= WALKING_RIGHT:
                setAnimationSequenceHero(hero,WALKING_RIGHT)
        else:
             if (hero['sequence'] == WALKING_LEFT):
                 setAnimationSequenceHero(hero,STANDING_LEFT)
             elif (hero['sequence'] == WALKING_RIGHT):
                 setAnimationSequenceHero(hero,STANDING_RIGHT)

        if (keyboard.key_pressed("SPACE")):
            heroOnPlatform, posy = isHeroOnPlatform(hero,platforms)
            if (heroOnPlatform or isHeroGrounded(hero)):
                setAnimationSequenceHero(hero,JUMPING)



def updateHeroPosition(hero):

    dt = window.delta_time()
    vx = hero['speedx']
    vy = hero['speedy']

    dx = vx*dt
    dy = vy*dt

    hero['sprite'].move_x(dx)
    hero['sprite'].move_y(dy)

    if (hero['sprite'].x>HERO_RIGHT_BORDER):
        hero['sprite'].x = HERO_RIGHT_BORDER
    if (hero['sprite'].x<HERO_LEFT_BORDER):
        hero['sprite'].x = HERO_LEFT_BORDER

    heroOnPlatform, posy = isHeroOnPlatform(hero,platforms)
    heroGrounded = isHeroGrounded(hero)

    if (not heroGrounded and not heroOnPlatform):
        hero['speedy'] += GRAVITY*dt
    elif (heroOnPlatform):
        print(hero['speedy'])
        if (hero['speedy']>600):
            gameState['lives'] -= 1
            gameState['heroDied'] = True
            gameState['heroDiedTime'] = window.last_time
            hero['deadSprite'].set_position(hero['sprite'].x,hero['sprite'].y)
        hero['speedy'] = 0
        hero['sprite'].y = posy-hero['sprite'].height+2
        if (hero['sequence'] == JUMPING):
            hero['speedx'] = 0
    elif (isHeroGrounded(hero)):
        print(hero['speedy'])
        if (hero['speedy']>600):
            gameState['lives'] -= 1
            gameState['heroDied'] = True
            gameState['heroDiedTime'] = window.last_time
            hero['deadSprite'].set_position(hero['sprite'].x,hero['sprite'].y)
        hero['speedy'] = 0
        hero['sprite'].y = HERO_BOTTOM_BORDER
        if (hero['sequence'] == JUMPING):
            hero['speedx'] = 0



def updatePlatformsPositions(platforms):
    for platform in platforms:
        platform['sprite'].move_x(platform['speedx']*window.delta_time())
        if (platform['sprite'].x<platform['minPosx']):
            platform['sprite'].x = platform['minPosx']
            platform['speedx'] = -platform['speedx']
        if (platform['sprite'].x>platform['maxPosx']):
            platform['sprite'].x = platform['maxPosx']
            platform['speedx'] = -platform['speedx']

def updateGoldPosition(gold):
    gold['appearancePos'] = (gold['appearancePos']+1)%3
    if (gold['appearancePos']==0):
        gold['sprite'].x = 720
        gold['sprite'].y = HERO_BOTTOM_BORDER+gold['sprite'].height
    elif (gold['appearancePos']==1):
        gold['sprite'].x = 75
        gold['sprite'].y = 92
    else:
        gold['sprite'].x = 575
        gold['sprite'].y = 92



def entrance(gameLoopState):

    window.set_background_color((0,0,255))
    window.draw_text("Press SPACE to start",230,230,40,(255,255,0),"Arial",True,True)
    window.draw_text("LabGames 2014-2",260,300,40,(255,255,0),"Helvetic",True,True)

    if (keyboard.key_pressed("SPACE")):
        gameLoopState = INITIALIZATION

    return gameLoopState


def setPlatform(platform,posx,posy,minPosx,maxPosx,speedx,speedy):
    platform['sprite'].set_position(posx,posy)
    platform['minPosx'] = minPosx
    platform['maxPosx'] = maxPosx
    platform['speedx'] = speedx
    platform['speedy'] = speedy

def initialization(gameLoopState):


    gameState = dict(score = 0, lives = 3, level = 0, time = 20000, beginningTime = window.last_time, heroDiedTime = 0, heroDied = False, nextEnemyScore = 10000)

    hero = dict( sprite = Sprite("heronew.png",24), deadSprite= Sprite("herodead.png",1), speedx = 0, speedy = 0, \
                 firstTimeSpawn = True,\
                 sequence = STANDING_LEFT,\
                 previousSequence = STANDING_LEFT)

    hero['sprite'].set_position(0,window.height - hero['sprite'].height)
    hero['sprite'].set_total_duration(ANIMATION_DURATION)
    hero['deadSprite'].set_total_duration(ANIMATION_DURATION)

    setAnimationSequenceHero(hero,hero['sequence'])

    house = Sprite("house.png")
    house.set_position(0,320)

    houseExternal = Sprite("houseexternal.png")
    houseExternal.set_position(0,320)

    platforms = []
    treasure = []

    for i in range(0,10):
        platform = dict(sprite = Sprite("platform.png",1), minPosx = 100, maxPosx = 100,
                        speedx = 100,speedy = 100, visible = True)
        platform['sprite'].set_total_duration(ANIMATION_DURATION)
        platforms.append(platform)

    setPlatform(platforms[0],500,470,420,600,80,10)
    setPlatform(platforms[1],580,420,480,680,-100,10)
    setPlatform(platforms[2],660,370,560,760,80,10)
    setPlatform(platforms[3],520,320,420,620,-120,10)
    setPlatform(platforms[4],370,270,270,470,180,10)
    setPlatform(platforms[5],220,220,150,320,0,10)
    setPlatform(platforms[6],90,220,0,190,0,10)
    setPlatform(platforms[7],50,150,0,120,0,10)
    setPlatform(platforms[8],590,220,490,690,0,10)
    setPlatform(platforms[9],550,150,450,650,0,10)

    gold = dict(sprite = Sprite("gold.png",2),points = 1000, appearancePos = 0)
    gold['sprite'].set_position(75 ,92)

    enemies = dict(list = [], shots = [], firstTimeSpawn = True )

    treasure.append(gold)

    window.delay(1000)
    gameLoopState = PLAYING

    return gameLoopState, gameState, platforms, hero, treasure, enemies, house, houseExternal


####################################################################################################


def detectCollisionPlatform(hero,platforms):
    collidedPlatforms = []
    for platform in platforms:
        if (hero['sprite'].collided(platform['sprite'])):
            collidedPlatforms.append(platform)
    return collidedPlatforms

def detectGoldCollision(hero,gold):
    if hero['sprite'].collided(gold['sprite']):
        updateGoldPosition(gold)
        return True
    else:
        return False

def gameStage(gameLoopState,gameState, platforms, hero, treasure, enemies, house, houseExtenal):

    background.draw()

    keyBoardInput(hero,platforms)

    updatePlatformsPositions(platforms)

    for platform in platforms:
        platform['sprite'].update()
        platform['sprite'].draw()

    house.draw()

    updateHeroPosition(hero)

    if (not gameState['heroDied']):
        hero['sprite'].update()
        hero['sprite'].draw()
    else:
        hero['deadSprite'].update()
        hero['deadSprite'].draw()
        if window.last_time-gameState['heroDiedTime']>2000:
            gameState['heroDied'] = False

    for gold in treasure:
        gold['sprite'].draw()

    houseExternal.draw()

    if (detectGoldCollision(hero,gold)):
        gameState['score'] += 1000

    window.draw_text("Score: "+str(int(gameState['score'])),5,5,30,(255,255,255),"Arial",True,False)
    window.draw_text("Time: "+str(int(gameState['time'])),300,5,30,(255,255,255),"Arial",True,False)
    window.draw_text("Lives: "+str(int(gameState['lives'])),670,5,30,(255,255,255),"Arial",True,False)

    gameState['time'] -= 1

    if (gameState['lives']<=0 or gameState['time']<0):
        gameLoopState = ENDING

    return gameLoopState, gameState, platforms, hero, treasure, enemies, house, houseExtenal

####################################################################################################

def ending(gameLoopState,gameState):

    window.draw_text("Your score was: "+str(int(gameState['score'])),280,230,32,(255,255,0),"Arial",True,False)
    window.draw_text("Continue(Y/N)",330,300,32,(255,255,0),"Arial",True,False)

    if keyboard.key_pressed("y"):
        gameLoopState = ENTRANCE
    elif keyboard.key_pressed("n"):
        window.close()
    return gameLoopState

gameLoopState = ENTRANCE

while True:
    if (gameLoopState == ENTRANCE):
        gameLoopState = entrance(gameLoopState)
    elif (gameLoopState == INITIALIZATION):
        gameLoopState, gameState, platforms, hero, treasure, enemies, house, houseExternal = initialization(gameLoopState)
    elif (gameLoopState == PLAYING):
        gameLoopState, gameState, platforms, hero, treasure, enemies, house, houseExternal = gameStage(gameLoopState,gameState, platforms,\
                                                                                 hero, treasure, enemies, house, houseExternal)
    else:
        gameLoopState = ending(gameLoopState,gameState)
    window.update()

