viewport= require("viewport")
require "abad"
require "cacau"
require "llibre"
require "gorro"
require "peu"
require "premiere"
require "elalien"
require "bol"
require "gota"
require "invisible"
require "caco"
require "zombie"
require "score"
-- require "switches"
require "trigger"
require "imp3"
require "fireball"
require "bar_meter"

require "stage1"
require "remote_view"
require "dialeg"
require "trigger_event"

require "batman"
require "health_potion"
require "tiles_layer2"
require "batvio"
-- require "live_scene"
require "copter"

local DEBUG = false

local tile_w = arcade_config.tiles_width
local tile_h = arcade_config.tiles_height
local res_w  = arcade_config.resolucion.width
local res_h  = arcade_config.resolucion.height

local view_tile_id = false
local view_checking_tile = false
local stage= 1
local stage_loaded = 0
stage_update      = nil
stage_draw_back   = nil
stage_draw_middle = nil
stage_draw_front  = nil

viewp = viewport.new(arcade_config.resolucion.width, arcade_config.resolucion.height)
viewp:position(0,0)

function foo()
    print("foo")
end

function actor_warp_draw(actor) 
    local shrink_w = actor.w*actor.shrink
    local shrink_h = actor.h*actor.shrink
    local offset_x = math.floor((actor.w-shrink_w)/2)
    local offset_y = math.floor((actor.h-shrink_h)/2)
    local scr_x, scr_y = viewp:screen_coords( actor.x+offset_x, actor.y+offset_y )
    shrink_w = math.floor(shrink_w)
    shrink_h = math.floor(shrink_h)

    if shrink_w>0 and shrink_h>0 then
        draw.surfrot((actor.frame&7)*cw, (actor.frame>>cxr2)*ch, 
                    cw, ch, 
                    scr_x, scr_y, 
                    actor.angle,
                    shrink_w, shrink_h,
                    actor.flip)
    end
end

function actor_warp_update(actor)
    -- warp, wait, respawn
    if actor.warping then
        if actor.step<actor.death_time then
            actor.shrink=actor.shrink-actor.d_shrink
            actor.angle=actor.angle+actor.d_angle
            if actor.angle>=360 then actor.angle = actor.angle % 360 end
            if actor.shrink<=0 then 
                actor.shrink=1
                actor.d_shrink=1
                actor.angle=0
                actor.d_angle=1
                actor.warping = false
                actor.frame = -1
                actor.step = 0
                if actor.energy~=nil then
                    actor.energy = actor.max_energy
                end
            end
        end
    elseif actor.step<actor.death_time/2 then
        actor.frame = -1
    elseif actor.step<actor.death_time then
        if actor.step%2==0 then
            actor.frame=actor.anim[#actor.anim]
        else
            actor.frame=-1
        end
    elseif actor.step>=actor.death_time then
        actor.frame=actor.anim[1]
        actor.step=0
        actor.wait=0
        if actor.name=="caco" then
            actor.update=caco.update_normal
        elseif actor.name=="zombie" then
            actor.update=zombie.update_normal
        end
        actor.dying = false
    end
end

actors={}

function game_exit()
    -- mapa_restore_backup()
    actors={}
    -- cameras={}
end

function game_init(menu)
    stage= 1
    stage_loaded = 0
-- print("GAME INIT")
    actors={}
    
    abad_init()
    table.insert(actors,abad)
    
    score.create()
	-- game_update=update_game
    states:next()
end


function render_map( sf_map, sf_tiles, x, y, target )
    target = target or 0
    map.surf(sf_map)
    map.cell(16, 16)
    surf.source(sf_tiles)
    surf.target(target)
    view.origin(-x,-y)
    map.draw()
    view.origin(0,0)
end


function load_stage()
    local stage_init = stages["stage"..stage.."_init"]
    if stage_init then
        stage_init()
        stage_loaded = stage
        print("Stage "..stage.." loaded")
    else
        print("No se ha cargado la fase "..stage)
    end
end


function load_boss_stage()
    --local stage_boss = stages["stage"..stage.."_boss"]
    -- if stage_boss and not scene_running and not stages.loaded_boss then
        stage_update      = stages["stage"..stage.."_boss_update"]
        stage_draw_back   = stages["stage"..stage.."_boss_draw_back"]
        stage_draw_middle = stages["stage"..stage.."_boss_draw_middle"]
        stage_draw_front  = stages["stage"..stage.."_boss_draw_front"]
        -- stage_boss_end    = stages["stage"..stage.."_boss_end"]
        -- stage_boss()
        print("Stage "..stage.." Boss loaded")
    -- else
    --     print("No se ha cargado la fase "..stage)
    -- end
end

function unload_boss_stage()
    -- stage_boss_end()
    stage_update      = nil
    stage_draw_back   = nil
    stage_draw_middle = nil
    stage_draw_front  = nil
    -- stage_boss_end    = nil
end

function viewport_update()
    -- Moure el viewport
    local vp_x = viewp.x
    local vp_y = viewp.y
    
    local vp_center_offset_x = (viewp.width >> 1)
    local vp_center_offset_y = (viewp.height >> 1)
    
    vp_x = abad.x - vp_center_offset_x
    if vp_x < 0 then vp_x = 0 end
    
    vp_y = abad.y - vp_center_offset_y
    if vp_y < 0 then vp_y = 0 end

    viewp:position(vp_x, vp_y)
end

function world_update()
    -- Actualitzar moviment del mapa (ex: tiles animats)
    arc_mapa_update()
    tiles_layer2.update()
    
    -- Moure a tots
    for key,actor in pairs(actors) do
        actor:update()

        -- Comprovar dispars contra "monstres"
        if viewp:inside(actor.x, actor.y, actor.w, actor.h) and actor~=abad then
            for _, cacau_shot in pairs(cacau.shots()) do
                -- if collision(actor,cacau_shot) then print("COLLISION") end
                -- if actor.enabled then print(actor.name) else print("NOT "..actor.name) end
                -- if cacau_shot.alive then print("CACAU") end
                if actor.enabled and cacau_shot.alive and collision(actor,cacau_shot) then
                    if actor.hit ~= nil and not actor.dying then
                        actor:hit()
                        if actor.can_warp then warp.open(actor) end
                        cacau:kill(cacau_shot)
                    end
                end
            end
        end
    end
    
    if stage_update then stage_update() end
    
    -- Actualizar el que queda
    cacau.update()

    -- switches.update()
    warp.update_all()
    
    trigger_event.update()
end

function world_draw()
    -- Pintar la finestra del mon
    render_map(sf_mapa, tiles, viewp.x, viewp.y)
    tiles_layer2.draw()
    
    if stage_draw_back then stage_draw_back() end
    
    -- pintar warps
    for key,warp in pairs(warp.warp_list) do
        if viewp:inside(warp.x, warp.y, warp.w, warp.h) then
            warp:draw()
        end
    end    
    
    --pintar actors
    for key,actor in pairs(actors) do
        if viewp:inside(actor.x, actor.y, actor.w, actor.h) and actor~=abad then
            actor:draw()
        end
    end
    abad:draw(); -- per a que estiga davant de tots
    
    dialeg.draw()
    
    if stage_draw_middle then stage_draw_middle() end
    
    cacau:draw()
    if stage_draw_front then stage_draw_front() end
    
    remote_view_draw()
end

function update_game()
    if stage~=stage_loaded then load_stage() end
       
    surf.target(0)
    surf.cls(16)

    world_update()
    
    viewport_update()
    
    world_draw()
    
    score.draw()
    
    if controller:check("ESC") then
        states:executar("pause", true)
    end
    
    if DEBUG then
        special_keys()
        debug_info()
    end
end

function pause()
    print("pause()")
    -- surf.source(0)
    -- surf.target(back)
    -- draw.surf(0,0,128,96,0,0)
    -- surf.target(0)
    -- surf.source(tiles)
    -- pausa_option=1
    -- pause_old_update=game_update
    -- game_update=update_pause
end

function update_pause()
    draw.rectf(16,16,97,65,16)
    draw.rect(16,16,97,65,15)
    draw.text("PAUSA",54,20,15)

    menu_count=menu_count+1
    local parpadeig=false
    if menu_count>=20 then
        parpadeig=true
        if menu_count>40 then menu_count=0 end
    end
    draw.rect(28,33+(10*(pausa_option-1)),73,9,14)
    if (not parpadeig) then draw.rect(28,33+(10*(pausa_option-1)),73,9,13) end

    --draw.rect(28,33+(10*(pausa_option-1)),73,9,13)

    draw.text("CONTINUAR",30,35,14)
    draw.text("MUSICA:",30,45,14)
    if music.enabled() then
        draw.text("SI",91,45,15)
    else
        draw.text("NO",91,45,15)
    end
    draw.text("SÓ:",30,55,14)
    if sound.enabled() then
        draw.text("SI",91,55,15)
    else
        draw.text("NO",91,55,15)
    end
    draw.text("EIXIR",30,65,14)

    if key.press(key.ESCAPE) then
        surf.source(back)
        draw.surf(0,0,128,96,0,0)
        surf.source(tiles)    
        game_update = pause_old_update
    elseif key.press(keyDown) or pad.press(btnDown) then
        pausa_option = pausa_option + 1
        if pausa_option == 5 then pausa_option = 1 end
    elseif key.press(keyUp) or pad.press(btnUp) then
        pausa_option = pausa_option - 1
        if pausa_option == 0 then pausa_option = 4 end
    elseif key.press(keyShoot) or pad.press(btnShoot) then
        if pausa_option==1 then
            surf.source(back)
            draw.surf(0,0,128,96,0,0)
            surf.source(tiles)    
            game_update = pause_old_update
        elseif pausa_option==2 then
            music.enabled(not music.enabled())
        elseif pausa_option==3 then
            sound.enabled(not sound.enabled())
        else
            game_exit()
            game_init(true)
        end
    end
end

function print_analisis_field ( field )
    local field_state=" "
    if boss.analisis[field] then field_state="X" end
    print(" [ "..field_state.." ] "..field)
end

function print_analisis()
    print("--------------------------------------------")
    print_analisis_field("can_chase_abad")
    print_analisis_field("can_climb")
    print_analisis_field("can_shot")
    print_analisis_field("can_super")
    print_analisis_field("can_go_altar")
    print_analisis_field("falling")
    print_analisis_field("going_to_fall")
    print_analisis_field("target_reached")
    print("X= "..boss.x..", OX= "..boss.x_old)
    print(" ")
end

function special_keys()
    if key.press(key.A) then
        boss.x_old = boss.x
        boss.x = boss.x-1
        print_analisis()
    end
    if key.press(key.S) then 
        boss.y_old = boss.y
        boss.y = boss.y+1 
        print_analisis()
    end
    if key.press(key.D) then 
        -- boss.x_old = boss.x
        -- boss.x = boss.x+1 
        -- print_analisis()
        dialeg.new( "Hola mundo!", abad  )
    end
    if key.press(key.F) then 
        -- boss.x_old = boss.x
        -- boss.x = boss.x+1 
        -- print_analisis()
        dialeg.new( "Ma cuando arribo a casa", premiere  )
    end
    if key.press(key.W) then 
        boss.y_old = boss.y
        boss.y = boss.y-1 
        print_analisis()
    end
    if key.press(key.W) then 
        boss.y_old = boss.y
        boss.y = boss.y-1 
        print_analisis()
    end    
    if key.press(key.F) then 
        boss._pause = not boss._pause
    end
    if key.press(key.N1) then
    -- abad prev room
        local hab = abad.hab-1
        if hab<0 then hab=0 end
        local hab_x = 4
        local hab_y = 3
        local abad_x, abad_y = coords.room_to_world ( hab, hab_x, hab_y)
        abad:move(abad_x, abad_y)
        local scr_ax, scr_ay = viewp:screen_coords(abad_x, abad_y)
    end
    if key.press(key.N2) then
    -- abad next room
        local hab = abad.hab+1
        if hab<0 then hab=0 end
        local hab_x = 4
        local hab_y = 3
        local abad_x, abad_y = coords.room_to_world ( hab, hab_x, hab_y)
        abad:move(abad_x, abad_y)
        local scr_ax, scr_ay = viewp:screen_coords(abad_x, abad_y)
    end
    if key.press(key.N8) then
        -- local abad_x, abad_y = coords.room_to_world ( 31, 8, 3 )
        -- print(abad_x..", "..abad_y)
        -- abad:move(abad_x, abad_y)
        -- local scr_ax, scr_ay = viewp:screen_coords(abad_x, abad_y)
        imp.mode="away"
        imp.mode_cooldown = 60000
        print("away")
    end
    if key.press(key.N9) then
        -- mapa_restore_backup()
        -- set_actors_enabled_by_room(true, "boss", 44, 55)
        -- viewp:free_move()
        imp.mode="chase"
        imp.mode_cooldown = 60000
        print("chase")
    end
    if key.press(key.N0) then
        -- abad go to room
        -- local abad_x, abad_y = coords.room_to_world ( 34, 3, 3 )
        -- print(abad_x..", "..abad_y)
        -- abad:move(abad_x, abad_y)
        -- local scr_ax, scr_ay = viewp:screen_coords(abad_x, abad_y)
        imp.init()
    end
end

function debug_info()
    -- fps_print()
    -- if true then return end
    font.current(font_default)
	-- viewp:print()
    -- msg_print(0,14,"ABAD= "..abad.x..", "..abad.y, true)
    -- msg_print(0,21,"VIEW= "..viewp.x..", "..viewp.y, true)
    local hab, xx, yy = coords.world_to_tile(abad.x, abad.y)
    msg_print(0,28,hab.." ( "..xx..", "..yy.." )", true)
    -- msg_print(0,35,hab.." ( "..xx..", "..yy.." )", true)
    -- msg_print(0,42," JH= "..abad.jump_height,true)
    
    -- view_coord(abad.x+8, abad.y+0, 16, 32, 6)
    -- view_coord(abad.x+abad.bb.x,  abad.y+abad.bb.h, 2, 2, 4)
    -- view_coord(abad.x+abad.bb.x+abad.bb.w, abad.y+abad.bb.h, 2, 2, 2)
    -- view_coord(abad.x, abad.y, 2, 2, 3)
    
    -- if key.press(key.T) then 
    --     view_tile_id = not view_tile_id 
    --     view_checking_tile = false
    -- end
    -- if key.press(key.C) then 
    --     view_checking_tile = not view_checking_tile 
    --     view_tile_id = false
    -- end
    -- 
    -- if view_tile_id then
    --     write_tile(abad.x, abad.y, 0, true, "R")
    --     write_tile(abad.x, abad.y+16, 0, true, "R")
    --     write_tile(abad.x, abad.y+32, 0, true, "R")
    --     
    --     write_tile(abad.x+16, abad.y+32, 0, true, "C")
    -- 
    --     write_tile(abad.x+32, abad.y, 0, true, "L")
    --     write_tile(abad.x+32, abad.y+16, 0, true, "L")
    --     write_tile(abad.x+32, abad.y+32, 0, true, "L")
    -- end
    -- 
    -- if view_checking_tile then
    --     local msg = "FLIP= true"
    --     if not abad.flip then 
    --         msg ="FLIP= false"
    --         view_coord(abad.x+abad.bb.w+abad.bb.x-1, abad.y+abad.bb.h-4, 2, 2, 2)
    --     else
    --         view_coord(abad.x+abad.bb.x-1, abad.y+abad.bb.h-4, 2, 2, 2)
    --     end
    --     msg_print(abad.x, abad.y-8,msg)
    -- end
    font.current(font_sf)
end

states:registrar("game", {game_init, update_game} )
