function CreateMarker(screen, name, x, y, isActive)
    local obj;
	
	if isActive then
	    local anim = CreateAnimation('data/Texture/Scenes/00_Global_Map/markerActive.png',0,0,124,124,40,20)
        anim:SetHotSpot(62,62)
        anim:SetBlendMode(2)
        anim:SetColor('0xFFFFFFFF')
        obj = screen:CreateObject(name,anim,512,384,101,0,1,1)
    else
        local anim = CreateAnimation('data/Texture/Scenes/00_Global_Map/markerDone.png',0,0,110,110,1,0)
        anim:SetHotSpot(55,55)
        anim:SetBlendMode(2)
        anim:SetColor('0xFFFFFFFF')
        obj = screen:CreateObject(name,anim,242,290,101,0,1,1)
        
        play_field:IgnoreOnTestPoint(name);
    end
	
	obj:AttachTo( play_field:GetObject('background') );
	obj:SetXY(x, y);
	
	return obj;
end

function ShowMarker(marker_name)
    local obj  = play_field:GetObject(marker_name);
    local time = 1;
    local eff  = CreateAnimationEffector()
    
    eff:SetMode(_ANIM_FWD + _ANIM_NOLOOP);
    eff:AttachTo(obj);
    
    eff:SetKey(_TRACK_O, 0.0, 0.0);
    eff:SetKey(_TRACK_O, time, 1.0);
    
    eff:SetKey(_TRACK_S, 0.0,        0.);
    eff:SetKey(_TRACK_S, time * 0.8, 1.1);
    eff:SetKey(_TRACK_S, time,       1.);
    
    eff:Play();
    
    game_state.marker_showing = true;
    TimerDoString('game_state.marker_showing = false', time, play_field:GetTimer());
end

function OnMarkerClick(levelID)
    local info = game_state.levels[levelID];
    
    if info.completed then
        return;
    end
    
    if not info.path then
    end
    
    if not HasGameState('SceneVisited', info.path) or not HasGameState('BeforMapScreen')
    then
        SetCursor('CursorDefault');
        StartLevel(info.path);
    else
        SetCursor('CursorDefault');
        StartLevel(GetGameState('BeforMapScreen'):Get(0));
    end
end

function PushLevelInfo(levelName, firstPath, x, y)
    if game_state.levels == nil then
        game_state.levels = {};
    end
    
    local index = table.getn(game_state.levels) + 1;
    
     game_state.levels[index]           = {}
     game_state.levels[index].path      = firstPath;
     game_state.levels[index].name      = levelName;
     game_state.levels[index].x         = x;
     game_state.levels[index].y         = y;
     game_state.levels[index].completed = HasGameState('LevelCompleted', levelName);
end

function SetMapPosition(x, y)
    x, y = GetCorrectXY(x, y);
    play_field:GetObject('background'):SetXY(x, y);
end

function GetCorrectXY(x, y)
    local bg = play_field:GetObject('background');
    
    if (x > 0) then
        x = 0;
    elseif (x < 1024 - bg:GetAnimation():GetWidth())
        then x = 1024 - bg:GetAnimation():GetWidth();
    end
    
    if (y > 0) then
        y = 0;
    elseif (y < 768 - bg:GetAnimation():GetHeight()) then
        y = 768 - bg:GetAnimation():GetHeight();
    end
    
    return x, y;
end

function ScrollMapTo(x, y, speed, callback)
    if game_state.map_effector ~= nil then
        game_state.map_effector:Destroy();
    end
    
    x, y = GetCorrectXY(x, y);
    
    local map  = play_field:GetObject('background');
    local dx   = map:GetX() - x;
    local dy   = map:GetY() - y;
    local dist = math.sqrt(dx*dx + dy*dy);
    local time = dist / speed;
    
    game_state.map_effector = CreateAnimationEffector();
    game_state.map_effector:AttachTo( play_field:GetObject('background') )
    game_state.map_effector:SetMode(_ANIM_FWD + _ANIM_NOLOOP);
    
    game_state.map_effector:SetKey(_TRACK_X, 0.0,  map:GetX());
    game_state.map_effector:SetKey(_TRACK_X, time, x);
    
    game_state.map_effector:SetKey(_TRACK_Y, 0.0,  map:GetY());
    game_state.map_effector:SetKey(_TRACK_Y, time, y);
    
    game_state.map_effector:Play();
    
    game_state.scrolling = true;
    
    play_field.sawSound = MakeSoundEntity('MapMove');
    play_field.sawSound:Play(true);
    
    TimerDoString('OnStopScrollGlobalMap()', time, play_field:GetTimer());
    
    if callback ~= nil then
        TimerDoString(callback, time, play_field:GetTimer());
    end
end

function OnStopScrollGlobalMap()
    if play_field.sawSound then
        play_field.sawSound:StopSound();
        play_field.sawSound = nil;
    end
    
    game_state.scrolling = false
end

------------------------------------------------------------------------------------

function OnSceneLoad(screen)
    LoadData(screen)
    DefaultOnSceneLoad('data/Scenes/00_Global_Map.lua', 'map')
    
    game_state.draging        = false;
    game_state.scrolling      = false;
    game_state.marker_showing = false;
    game_state.scroll_speed   = 150;
    
    PushLevelInfo('DupensHouse', 'data/Scenes/01_Dupens_House_Entrance_Main.lua', 170, 310);
    PushLevelInfo('Bridge',      'data/Scenes/04_Bridge_Main.lua',                350, 550);
    PushLevelInfo('Bank',        'data/Scenes/08_Bank_Main.lua',                  1250, 540);
    PushLevelInfo('Gandarmery',  'data/Scenes/05_Gendarmery_Main.lua',            1156, 981);
    PushLevelInfo('Restaurant',  'data/Scenes/11_Restaurant_Main.lua',            1447, 610);
    PushLevelInfo('Laundry',     'data/Scenes/06_Laundry_Main.lua',               1256, 147);
    PushLevelInfo('Atelier',     'data/Scenes/07_Atelier_Main.lua',               1470, 930);
    PushLevelInfo('Mill',        'data/Scenes/19_Mill_Outside_Main.lua',          360,  830);
    PushLevelInfo('Port',        'data/Scenes/22_RiverPort_Main.lua',             900,  340);
    
    local already_found = false;
    local info          = nil;
    local level_count   = table.getn(game_state.levels);
    
    for i=level_count, 1, -1
    do
        info = game_state.levels[i];
        
        if already_found
        then
            CreateMarker(screen, info.name, info.x, info.y, false);
        elseif info.completed
        then
            CreateMarker(screen, info.name, info.x, info.y, false);
            
            local next_info = (i ~= level_count) and game_state.levels[i+1] or nil;
            
            if next_info ~= nil then
                local marker = CreateMarker(screen, next_info.name, next_info.x, next_info.y, true);
                
                if HasGameState('SceneVisited', next_info.path) then
                    SetMapPosition(512 - next_info.x, 384 - next_info.y);
                else
                    marker:SetOpacity(0.0);
                    
                    SetMapPosition(512 - info.x, 384 - info.y);
                    ScrollMapTo(512 - next_info.x, 384 - next_info.y, game_state.scroll_speed, 'ShowMarker(\''..next_info.name..'\')');
                end
            end
            
            already_found = true
        elseif (info.path ~= nil and HasGameState('SceneVisited', info.path)) or (i == 1)
        then
            CreateMarker(screen, info.name, info.x, info.y, true);
            SetMapPosition(512 - info.x, 384 - info.y);
            
            already_found = true
        end
    end
    
    --[[
    for i, info in ipairs(game_state.levels) do
        if info.completed then
            CreateMarker(screen, info.name, info.x, info.y, false);
        else
            local marker = CreateMarker(screen, info.name, info.x, info.y, true);
            
            if HasGameState('SceneVisited', info.path) or (i == 1) then
                SetMapPosition(512 - info.x, 384 - info.y);
            else
                marker:SetOpacity(0.0);
                
                local prev_info = game_state.levels[i - 1];
                SetMapPosition(512 - prev_info.x, 384 - prev_info.y);
                ScrollMapTo(512 - info.x, 384 - info.y, game_state.scroll_speed, 'ShowMarker(\''..info.name..'\')');
            end
            break;
        end
    end
    --]]
    
    play_field:IgnoreOnTestPoint('area_ps');
    play_field:GetObject('area_ps'):AddParticleSystem('data/ParticleSystem/GlobalMapHighlight.psi',
                                                         'GlobalMapParticle',
                                                         true);
end

function OnSceneFree(screen)
    DefaultOnSceneFree()
    FreeData(screen)
end

function OnUpdate(dt)
    if not game_state.scrolling and not game_state.marker_showing then
        if game_state.draging then
            local mPos = GetMousePos();
            local x    = mPos.x + game_state.dx;
            local y    = mPos.y + game_state.dy;
            
            SetMapPosition(x, y);
        else
            local bg     = play_field:GetObject('background');
            local mPos   = GetMousePos();
            local offset = 20;
            local speed  = 100 * dt;
            
            local x = bg:GetX();
            local y = bg:GetY();
            
            if mPos.x < offset then
                x = x + speed;
            elseif mPos.x > (1024 - offset) then
                x = x - speed;
            end
            
            if mPos.y < offset then
                y = y + speed;
            elseif mPos.y > (768 - offset) then
                y = y - speed;
            end
            
            SetMapPosition(x, y);
        end
    end
    
    DefaultOnUpdate(dt)
end

function OnAllItemsFound()
    DefaultOnAllItemsFound()
end

function OnLose()
    DefaultOnLose()
end

function OnExit()
    DefaultOnExit()
end

function OnClose()
    DefaultOnClose()
end

function OnObjectMouseEnter(object)
    local obj_name = object:GetName();
    
    if not game_state.scrolling and not game_state.marker_showing then
        for i, info in ipairs(game_state.levels) do
            if obj_name == info.name
            then
                if not info.completed then
                    object:SetScale(1.1);
                end
                break;
            end
        end
    end
    
    DefaultOnObjectMouseEnter(object)
end

function OnObjectMouseLeave(object)
    local obj_name = object:GetName();
    
    for i, info in ipairs(game_state.levels) do
        if obj_name == info.name then
            object:SetScale(1.);
            break;
        end
    end
    
    DefaultOnObjectMouseLeave(object)
end

function OnObjectMouseDown(object)
    local obj_name = object:GetName()
    local pf       = play_field
    
    if not game_state.scrolling and not game_state.marker_showing then
        if obj_name == 'background' then
            local mPos = GetMousePos();
            
            game_state.dx       = object:GetX() - mPos.x;
            game_state.dy       = object:GetY() - mPos.y;
            game_state.draging  = true;
        end
        
        for i, info in ipairs(game_state.levels) do
            if obj_name == info.name then
                OnMarkerClick(i);
                break;
            end
        end
    end
end

function OnObjectMouseUp(object)
    if game_state.draging then
        game_state.draging = false;
    end
    
    DefaultOnObjectMouseUp(object)
end

function OnObjectFound(object)
    DefaultOnObjectFound(object)
end

function OnToolFound(tool)
    DefaultOnToolFound(tool)
end

function OnToolApply(tool, object)
    DefaultOnToolApply(tool, object)
end

function OnObjectReachPanel(object)
    DefaultOnObjectReachPanel(object)
end

function OnButtonPress(title)
    DefaultOnButtonPress(title)
end

function OnMouseMove(previous_pos, current_pos)
    DefaultOnMouseMove(previous_pos, current_pos)
end

function OnSetTool(tool)
    DefaultOnSetTool(tool)
end

function LevelLoaded(level)
end

function OnSceneDestroy(playfield)
    DefaultOnSceneDestroy(playfield)
end

--------------------------------------------------------------------------------
-- CLEAR_ON_SAVE_BEGIN
-- Do not edit code listed below (generated by the editor on each save)
function LoadData(screen)
	local anim = CreateAnimation('data/Texture/Scenes/00_Global_Map/background.jpg',0,0,1600,1200,1,0)
	anim:SetHotSpot(0,0)
	anim:SetBlendMode(2)
	anim:SetColor('0xFFFFFFFF')
	screen:CreateObject('background',anim,-352,-217,100,0,1,1)
	local anim = CreateAnimation('data/Texture/Scenes/Common/area.png',0,0,8,8,1,0)
	anim:SetHotSpot(4,4)
	anim:SetBlendMode(2)
	anim:SetColor('0x01FFFFFF')
	screen:CreateObject('area_ps',anim,512,384,150,0,128,96)
end

function FreeData(screen)
end
-- CLEAR_ON_SAVE_END
