require "animations"
require "templates"

sprites = {
    hero = nil,
    list = {},
    pause_ia = false,
    --initial_pos = { x=28, y=4*13*8+79 }
    last_safe_room = 0 + 4 * 8,
    last_safe_pos = { x=28, y=4*13*8+79 }
}

function sprites.remove(sprite)
    for i,v in ipairs(sprites.list) do
        if v == sprite then
            table.remove(sprites.list, i)
            print("Sprite removed: "..sprite.type)
            return
        end
    end
end

function sprites.save_safe_pos()
    local room = rooms.current()
    --local hero_room = (sprites.hero.pos.x//160)*20 + ((sprites.hero.pos.y//104)*12) * 8
    --if room ~= hero_room then return end
    if room == sprites.last_safe_room then return end

    sprites.last_safe_room = room
    sprites.last_safe_pos = {x=sprites.hero.pos.x, y=sprites.hero.pos.y}
    --print("safepos: " .. sprites.last_safe_pos.x .. ", " .. sprites.last_safe_pos.y)
end

function sprites.add_from_room(rx,ry)
    sprites.list = {}
    map.surf(rooms.surf_items)
    for y = ry, ry+11 do
        for x = rx, rx+19 do
            if map.tile(x,y) ~= 0 then
                local room = (rx//20) + (ry//12) * 8
                local item = map.tile(x,y)
                local flip = item > 0x7f
                item = item & 0x7f
                io.write("crear "..items[item].name.." en hab "..room.." ("..x..","..y..")...\n")
                table.insert(sprites.list, templates.create(items[item].name, {pos={x=x*8, y=y*8},flipped=flip, room=room}))
            end
        end
    end
end

function sprites.init()
    sprites.hero = {
        type = "hero",
        pos = { x=28, y=4*13*8+79 },
        size= { w=16, h=17 },
        bbo = { left=3, top=2, right=3, bottom=0 },
        current_frame = 1,
        current_wait = 1,
        flipped = false,
        surf = surf.load("gfx/morcus.gif"),
        animation = "hero_stand",
        ia = ia.update_hero,
        state = templates.ALIVE,
        jumping = 0,
        light = 100,
        light_ox = 8,
        light_oy = 8,
        cooldown = 0,
        gun_cooldown = 0,
        jump_throttle = 0,
        lives = 4,
        keys = {},
        stairs = false,
        hit = ia.hero_hit,
        give_key = ia.hero_give_key
    }
end

function sprites.set_animation(sprite, animation)
    if sprite.animation ~= animation then
        sprite.animation_finished = nil
        sprite.animation = animation
        sprite.current_frame = 1
        local cycle = animations[sprite.animation].cycle[1]
        sprite.current_wait = animations[sprite.animation].frames[cycle].wait
    end
end

function sprites.update()
    --if not sys.beat() then return end
    if sys.chrono() < 0.02 then return end
    sys.chrono(0)

    sprites.update_sprite(sprites.hero)
    for i,v in ipairs(sprites.list) do
        sprites.update_sprite(v)
    end
    if not sprites.pause_ia then
        sprites.hero.ia()
        for i,v in ipairs(sprites.list) do
            v.ia(v)
        end
    end
end

function sprites.update_sprite(sprite)
    if sprite.animation_finished then return end

    sprite.current_wait = sprite.current_wait - 1
    if sprite.current_wait == 0 then
        if sprite.current_frame < #animations[sprite.animation].cycle then
            sprite.current_frame = sprite.current_frame + 1
        else
            if animations[sprite.animation].loop then
                sprite.current_frame = 1
            else
                sprite.animation_finished = true
            end
        end
        local cycle = animations[sprite.animation].cycle[sprite.current_frame]
        sprite.current_wait = animations[sprite.animation].frames[cycle].wait
    end
end

function sprites.lights_out()
    for i,spr in ipairs(sprites.list) do
        if spr.light then
            tweening.add(spr.light,0,0.5,easing.linear,
                function(value,n,finished)
                    spr.light = value
                    if finished then
                        spr.light = nil
                        --if sprites.hero.state == templates.DEAD then
                        --    game.restart()
                        --end
                    end
                end
            )
        end
    end
    tweening.add(sprites.hero.light,0,0.5,easing.linear,
        function(value,n,finished)
            sprites.hero.light = value
            if finished then
                sprites.hero.light = nil
                game.restart()
            end
        end
    )
end

function sprites.lights_in()
    for i,spr in ipairs(sprites.list) do
        if spr.light then
            tweening.add(0,spr.light,0.5,easing.linear,
                function(value,n,finished)
                    spr.light = value
                end
            )
        end
    end
--    tweening.add(sprites.hero.light,0,0.5,easing.linear,
--        function(value,n,finished)
--            sprites.hero.light = value
--            if finished then
--                sprites.hero.light = nil
--            end
--        end
--    )
end

function sprites.draw(ignore_selected)
    if app.update ~= editor.update then
        surf.target(game.circ_buf)
        surf.cls()
        surf.target(game.back_buf)
    end

    editor.item_hovered = nil
    local mx,my = mouse.pos()
    if (app.update == editor.update) and (editor.layer~=LAYER_ITEMS) then ignore_selected = true end
    for i,v in ipairs(sprites.list) do
        if not ignore_selected and app.update == editor.update and mx>=v.pos.x and mx<=v.pos.x+v.size.w and my>=v.pos.y and my<=v.pos.y+v.size.h then
            editor.item_hovered = i
            if editor.item_dragged == editor.item_hovered then
                draw.mode(draw.PATTERN)
                draw.pattern(editor.ants)
            end
            sprites.draw_sprite_selected(v)
            draw.mode(draw.NORMAL)
        else
            if (not ignore_selected) or (not v.no_shadow) or (app.update ~= game.update) then
                sprites.draw_sprite(v)
            end
        end
    end
    sprites.draw_sprite(sprites.hero)
end

function sprites.draw_sprite(sprite)
    local cycle = animations[sprite.animation].cycle[sprite.current_frame]
    local frame = animations[sprite.animation].frames[cycle]
    local ox, oy = 0, 0
    if frame.offset then
        if sprite.flipped then
            if frame.offset.flipped then ox,oy = frame.offset.flipped.x,frame.offset.flipped.y end
        else
            if frame.offset.normal then ox,oy = frame.offset.normal.x,frame.offset.normal.y end
        end
    end

    if not frame then
        print(sprite.current_frame)
    end
    local reversed = frame.reversed or false
    if not sprite.invisible then
        surf.source(sprite.surf)
        if sprite.pattern then draw.pattern(sprite.pattern) end
        if sprite.mode then draw.mode(sprite.mode) end
        draw.surf(frame.frame.x, frame.frame.y, frame.frame.w, frame.frame.h, sprite.pos.x+ox, sprite.pos.y+oy, frame.frame.w, frame.frame.h, (not reversed) ~= (not sprite.flipped))
        draw.pattern(0xffff)
        draw.mode(draw.NORMAL)
    end
    if cheats.showaabb then
        local x,y,w,h = util.aabb(sprite)
        draw.rect(x,y,w,h,8)
    end
    if (app.update ~= editor.update) and (sprite.light) then
        game.draw_light(sprite.pos.x+sprite.light_ox, sprite.pos.y+sprite.light_oy,sprite.light)
    end
end

function sprites.draw_sprite_selected(sprite)
    pal.subpal(1,32,28)

    local cycle = animations[sprite.animation].cycle[sprite.current_frame]
    local frame = animations[sprite.animation].frames[cycle]
    local reversed = frame.reversed or false
    local x, y, w, h, sx, sy, f = sprite.pos.x, sprite.pos.y, frame.frame.w, frame.frame.h, frame.frame.x, frame.frame.y, (not reversed) ~= (not sprite.flipped)
    surf.source(sprite.surf)
    draw.surf(sx, sy, w, h, x-1, y-1, w, h, f)
    draw.surf(sx, sy, w, h, x,   y-1, w, h, f)
    draw.surf(sx, sy, w, h, x+1, y-1, w, h, f)
    draw.surf(sx, sy, w, h, x-1, y,   w, h, f)
    draw.surf(sx, sy, w, h, x+1, y,   w, h, f)
    draw.surf(sx, sy, w, h, x-1, y+1, w, h, f)
    draw.surf(sx, sy, w, h, x,   y,   w, h, f)
    draw.surf(sx, sy, w, h, x+1, y+1, w, h, f)
    pal.subpal()
    draw.mode(draw.NORMAL)
    draw.surf(sx, sy, w, h, x, y, w, h, f)
end
