-- Match2Core

Match2Core = {}

Match2Core.pool = {}
Match2Core.fly_pool = {}

Match2Core.selection = nil

Match2Core.animatedCards = {}

Match2Core.close_callback = nil

----------------------------------------------------------------------------------------------------
function Match2Core:setCloseCallback(func)
	Match2Core.close_callback = func
end

----------------------------------------------------------------------------------------------------
function Match2Core:isCardEnabled(name)

    if Match2Core.mCards[name] == nil then
        return false
    end

    local overlaps = Match2Core.mCards[name].overlaps;

    for i = 1, #overlaps do
        if Match2Core.mCards[overlaps[i]].on_field then
            return false
        end
    end

    return true
end

----------------------------------------------------------------------------------------------------
function Match2Core:onShow()
    addUpdateListener(Match2Core)
    Match2Core.mDisplay:set_element_eh("btn_skip_view",
        function() Match2Core:exitAction(true) end)

    Match2Core.mDisplay:play_clip('match2_remark', {frame_begin = 0, frame_end = 0})
    Match2Core.mDisplay:get_element('match2_remark'):setActive(true)
    Match2Core.mDisplay:get_element('stamp_lost_text'):setVisible(true)
    Match2Core.mDisplay:get_element('stamp_lost_text_02'):setVisible(true)
end

----------------------------------------------------------------------------------------------------
function Match2Core:exitAction(skip)
	if Match2Core.close_callback then Match2Core.close_callback(skip) end
    if Match2.ExitLevel ~= "" then
        local level = Match2.ExitLevel
        Match2.ExitLevel = ""
        level_mgr:switch_to_level(level) fade_panel:fade_out()
    else
        level_mgr:switch_to_level('Map') fade_panel:fade_out() 
    end
end

----------------------------------------------------------------------------------------------------
function Match2Core:onHide()
    removeUpdateListener(Match2Core)
    stop_all_effects()
end

----------------------------------------------------------------------------------------------------
function Match2Core:onCardOver(name)
    if not Match2Core:isCardEnabled(name) or name == Match2Core.selection then
        return
    end
    Match2Core.pool[name].hover:setVisible(true)
end

----------------------------------------------------------------------------------------------------
function Match2Core:onCardOut(name)
    if not Match2Core:isCardEnabled(name) or name == Match2Core.selection then
        return
    end
    Match2Core.pool[name].hover:setVisible(false)
end

----------------------------------------------------------------------------------------------------
function Match2Core:isMatchable(a, b)
    local type_diff = math.abs(a - b)
    return ((type_diff == 0 or type_diff == 8) and a ~= 0 and b ~= 0)
end

----------------------------------------------------------------------------------------------------
function Match2Core:onCardClick(name)
    if not Match2Core:isCardEnabled(name) then
        return
    end

    if name == Match2Core.goal then
        --start_effect_at("crystall", Vec2(512, 384))
        MinigameWin:show(4,function() Match2Core:exitAction(false) end)
        Media:soundEvent('match2.crystall')
    end

    if Match2Core.selection == nil then
        Match2Core.selection = name

        Match2Core.pool[name].light:setVisible(true)
        Match2Core.pool[name].hover:setVisible(false)

        Media:soundEvent('match2.first')

    elseif Match2Core.selection ~= name then
        --local type_diff = math.abs(Match2Core.mCards[name].type - Match2Core.mCards[Match2Core.selection].type)

        if Match2Core:isMatchable(Match2Core.mCards[name].type, Match2Core.mCards[Match2Core.selection].type) then
            Match2Core.pool[name].click:setActive(false)
            Match2Core.pool[Match2Core.selection].click:setActive(false)

            Match2Core.mCards[name].on_field = false
            Match2Core.mCards[Match2Core.selection].on_field = false

            Match2Core:match(Match2Core.pool[name].card, Match2Core.pool[Match2Core.selection].card)

            Media:soundEvent('match2.second')

            Match2Core.selection = nil
            
            Match2Core:updateGrays()
            
            if not Match2Core:checkPassage() then
                Bubble:show('ids_match2_shuffle', 412, 309, 200, 150, Bubble.TYPE_NORMAL, true, Match2Core.shuffle)
            end
        else
            Match2Core.pool[Match2Core.selection].light:setVisible(false)
            Match2Core.pool[Match2Core.selection].hover:setVisible(false)
            
            Match2Core.pool[name].light:setVisible(true)
            Match2Core.pool[name].hover:setVisible(false)

            Match2Core.selection = name

            Media:soundEvent('match2.first')

        end
    else
        Match2Core.pool[name].light:setVisible(false)
        Match2Core.pool[name].hover:setVisible(true)
        Match2Core.selection = nil
    end
end

----------------------------------------------------------------------------------------------------
function Match2Core:getFreeFly()
    for i = 1, #Match2Core.fly_pool do
        if not Match2Core.fly_pool[i].use then
            Match2Core.fly_pool[i].use = true
            return i
        end
    end

    return 0
end

----------------------------------------------------------------------------------------------------
function Match2Core:match(aCard1, aCard2)
    if Match2.tutorial then
        Tutorial:sendMessage('match2.match')
    end
    local type1 = Match2Core.mCards[aCard1:getName()].type
    local type2 = Match2Core.mCards[aCard2:getName()].type

    aCard1:setVisible(false)
    aCard2:setVisible(false)

    local fly1 = Match2Core:getFreeFly()
    local fly2 = Match2Core:getFreeFly()

    if fly1 == 0 or fly2 == 0 then
        return
    end

    local flyCard1 = Match2Core.fly_pool[fly1].card
    local flyCard2 = Match2Core.fly_pool[fly2].card

    flyCard1:setVisible(false)
    flyCard2:setVisible(false)

    play_clip(flyCard1:getCharacter(), {frame_begin = type1, frame_end = type1})
    play_clip(flyCard2:getCharacter(), {frame_begin = type2, frame_end = type2})

    local tPos1 = Vec2(aCard1:getPos(true).x, aCard1:getPos(true).y)
    local tPos2 = Vec2(aCard2:getPos(true).x, aCard2:getPos(true).y)

    local tCenter = Vec2(tPos2.x + (tPos1.x - tPos2.x) / 2, tPos2.y + (tPos1.y - tPos2.y) / 2)

	local tFXPpoint = Vec2(tCenter.x - 10, tCenter.y + 22)
    timer_mgr:add_timer(function() start_effect_at('match', tFXPpoint) end, 0.15, 1)
    
    table.insert(Match2Core.animatedCards, {index = fly1, startPos = tPos1, startAngle = aCard1:getAngle(),
        endPos = tCenter, endAngle = 0, time = 0.0})
    table.insert(Match2Core.animatedCards, {index = fly2, startPos = tPos2, startAngle = aCard2:getAngle(),
        endPos = tCenter, endAngle = 0, time = 0.0})
end

----------------------------------------------------------------------------------------------------
function Match2Core:checkPassage()
    local types = {}
    local found = false
    table.foreach(Match2Core.mCards,
        function(name)
            if found or not Match2Core.mCards[name].on_field or not Match2Core:isCardEnabled(name) then
                return
            end

            local type = Match2Core.mCards[name].type
            
            if type == 0 then
                found = true
                return
            end

            if type - 8 > 0 then
                type = type - 8
            end

            if types[type] ~= nil then
                found = true
            else
                types[type] = 1
            end
        end)

    return found
end

----------------------------------------------------------------------------------------------------
function Match2Core:shuffle()

    local card_pairs = {}
    table.foreach(Match2Core.mCards,
        function(name)
            if not Match2Core.mCards[name].on_field or Match2Core.mCards[name].type == 0 then
                return
            end

            local type = Match2Core.mCards[name].type
            local found = false
            for i = 1, #card_pairs do
                if #card_pairs[i] == 1 and Match2Core:isMatchable(card_pairs[i][1], type) then
                    card_pairs[i][2] = type
                    found = true
                    break
                end
            end

            if not found then
                table.insert(card_pairs, {type})
            end
        end)

    Match2Core:fill(card_pairs)
    
    if not Match2Core:checkPassage() then
        Bubble:show('ids_match2_cant_shuffle', 412, 309, 200, 150, Bubble.TYPE_NORMAL, true,
            function()
                level_mgr:switch_to_level('Match2')
                fade_panel:fade_out()
            end)
    end
end

----------------------------------------------------------------------------------------------------
function Match2Core:updateGrays()
    table.foreach(Match2Core.mCards,
        function(name)
            if not Match2Core.mCards[name].on_field then
                return
            end

            local enabled = true
            local overlaps = Match2Core.mCards[name].overlaps;
            for i = 1, #overlaps do
                if Match2Core.mCards[overlaps[i]].on_field then
                    enabled = false
                end
            end

            Match2Core.pool[name].grey:setVisible(not enabled)
        end)
end

----------------------------------------------------------------------------------------------------
function copy_table(dst, src)
    dst = {}
    table.foreach(src, function(elem)
        dst[elem] = src[elem]
    end)
end

----------------------------------------------------------------------------------------------------
function Match2Core:fill(card_pairs)

    local tTypeHelper = {} -- структура для раскидывания типов
    table.foreach(Match2Core.mCards,
        function(name)
            if not Match2Core.mCards[name].on_field or Match2Core.mCards[name].type == 0 then
                return
            end

            table.insert(tTypeHelper, {name = name, overlaps = {}})
            table.foreach(Match2Core.mCards[name].overlaps,
                function(elem)
                    local overlap_name = Match2Core.mCards[name].overlaps[elem]
                    if Match2Core.mCards[overlap_name].on_field then
                        table.insert(tTypeHelper[#tTypeHelper].overlaps, overlap_name)
                    end
                end)
        end)

    while #tTypeHelper > 0 do
        local cards = {}

        local selector = {}
        for i = 1, #tTypeHelper do
            for j = 1, #tTypeHelper[i].overlaps do
                if selector[tTypeHelper[i].overlaps[j]] == nil then
                    selector[tTypeHelper[i].overlaps[j]] = 1
                else
                    selector[tTypeHelper[i].overlaps[j]] = selector[tTypeHelper[i].overlaps[j]] + 1
                end
            end
        end

        local prev = -1
        for k = 1, 2 do
            local candidate = -1
            local score = 0

            for i = 1, #tTypeHelper do
                if #tTypeHelper[i].overlaps == 0 then
                    local card_score = selector[tTypeHelper[i].name]
                    if card_score == nil then
                        card_score = 0
                    end

                    if card_score >= score and i ~= prev then
                        score = card_score
                        candidate = i
                    end
                end
            end
            prev = candidate
            if candidate ~= -1 then
                table.insert(cards, candidate)
                
            end
        end

        if #cards < 2 then
            break
        end

        local types = {}

        if card_pairs == nil then
            rand = get_random(1, 17)
            types = {rand, rand}
        else
            types = card_pairs[1]
            table.remove(card_pairs, 1)
        end

        for i = 1, #cards do
            local tCardName = tTypeHelper[cards[i]].name

            for j = 1, #tTypeHelper do
                for k = 1, #tTypeHelper[j].overlaps do
                    if tTypeHelper[j].overlaps[k] == tCardName then
                        table.remove(tTypeHelper[j].overlaps, k)
                        break
                    end
                end
            end

            local tCard = Match2Core.pool[tCardName].card
            play_clip(tCard:getCharacter(), {frame_begin = types[i], frame_end = types[i]})

            Match2Core.mCards[tCardName].type = types[i]
        end

        if cards[1] > cards[2] then
            table.remove(tTypeHelper, cards[1])
            table.remove(tTypeHelper, cards[2])
        else
            table.remove(tTypeHelper, cards[2])
            table.remove(tTypeHelper, cards[1])
        end
    end
end

----------------------------------------------------------------------------------------------------
function Match2Core:new(aLayout)
    Match2Core.mCards = {}

    
    local cards_num = 0
    table.foreach(aLayout.cards, function() cards_num = cards_num + 1 end)

    table.foreach(aLayout.cards,
        function(aName)
            local tCard = Match2Core.pool[aName].card
            tCard:setVisible(true)
            tCard:setPos(Vec2(aLayout.cards[aName].x, aLayout.cards[aName].y))
            tCard:setAngle(aLayout.cards[aName].angle * math.pi / 180.0)

            Match2Core.pool[aName].click:setActive(true)
            Match2Core.pool[aName].light:setVisible(false)
            Match2Core.pool[aName].hover:setVisible(false)
            Match2Core.pool[aName].grey:setVisible(false)

            Match2Core.mCards[aName] = {on_field = true, overlaps = aLayout.cards[aName].overlaps}

            if aName == 'card'..(cards_num - 1) then
                play_clip(tCard:getCharacter(), {frame_begin = 0, frame_end = 0})
                Match2Core.mCards[aName].type = 0
                Match2Core.goal = aName
                return
            end
        end)

    Match2Core:fill()

    Match2Core:updateGrays()
end

----------------------------------------------------------------------------------------------------
function Match2Core:init()
    Match2Core.mDisplay = level_mgr:load_level("Match2")

    for i = 0, 54 do
        local tCard = Match2Core.mDisplay:get_element('card'..i)
        Match2Core.pool['card'..i] = {card = tCard}
        
        local size = Match2Core.mDisplay:get_element_count()
        for j = 0, size - 1 do

            local elem = Match2Core.mDisplay:get_element_at(j)

            if tCard:isParentOf(elem, true) then

                if elem:getName() == 'click' then

                    Match2Core.pool['card'..i].click = elem
                    Match2Core.mDisplay:_set_element_eh(elem, function() Match2Core:onCardOver('card'..i) end, {eh_type = eiRollOver})
                    Match2Core.mDisplay:_set_element_eh(elem, function() Match2Core:onCardOut('card'..i) end, {eh_type = eiRollOut})
                    Match2Core.mDisplay:_set_element_eh(elem, function() Match2Core:onCardClick('card'..i) end)
                    elem:setActive(false)

                elseif elem:getName() == 'light' then
                    Match2Core.pool['card'..i].light = elem
                    elem:setVisible(false)

                elseif elem:getName() == 'hover' then
                    Match2Core.pool['card'..i].hover = elem
                    elem:setVisible(false)

                elseif elem:getName() == 'grey' then
                    Match2Core.pool['card'..i].grey = elem
                    elem:setVisible(false)

                end
            end
        end
        
        tCard:setVisible(false)
    end
    
    for i = 1, 12 do
        local tCard = Match2Core.mDisplay:get_element('fly_card'..i)
        table.insert(Match2Core.fly_pool, {card = tCard, use = false})
    end

    Match2Core.mDisplay:set_element_eh('match2_remark', function() Match2Core:onRemarkClick() end)
end

----------------------------------------------------------------------------------------------------
function Match2Core:onRemarkClick()
    Match2Core.mDisplay:get_element('match2_remark'):setActive(false)
    set_frame_listener(Match2Core.mDisplay:get_element('match2_remark'), 'remark_closed', function() Match2Core:start() end)
    Match2Core.mDisplay:play_clip('match2_remark', {frame_begin = 0, label_end = 'remark_closed'})
end

----------------------------------------------------------------------------------------------------
function Match2Core:start()
    Match2Core.mDisplay:get_element('match2_remark'):setVisible(false)
    Match2Core.mDisplay:get_element('stamp_lost_text'):setVisible(false)
    Match2Core.mDisplay:get_element('stamp_lost_text_02'):setVisible(false)

    if Match2.tutorial then
        Tutorial:enterChapter('Match2')
    end
end

Match2Core.MATCH_ANIM_TIME = 0.3
Match2Core.COMMON_ANIM_TIME = 0.7

----------------------------------------------------------------------------------------------------
function Match2Core:update(aElapsed)

    table.foreach(Match2Core.animatedCards,
        function(key)
            Match2Core.animatedCards[key].time = Match2Core.animatedCards[key].time + aElapsed
            local time = Match2Core.animatedCards[key].time
            local index = Match2Core.animatedCards[key].index
            local card = Match2Core.fly_pool[index].card

            if time >= Match2Core.COMMON_ANIM_TIME then
                card:setAlpha(1.0)
                card:setVisible(false)
                card:setPos(Vec2(-1000, -1000))
                Match2Core.fly_pool[index].use = false
                Match2Core.animatedCards[key] = nil
                return
            end

            local finish = Match2Core.animatedCards[key].endPos;

            if time > Match2Core.MATCH_ANIM_TIME then
                card:setPos(finish);
                card:setAngle(Match2Core.animatedCards[key].endAngle);

                local alpha = 1.0 - (time - Match2Core.MATCH_ANIM_TIME) / (Match2Core.COMMON_ANIM_TIME - Match2Core.MATCH_ANIM_TIME);
                card:setAlpha(alpha)
                return
            end

            local start = Match2Core.animatedCards[key].startPos;
            local current = Vec2(start.x + (finish.x - start.x) * (time / Match2Core.MATCH_ANIM_TIME),
                start.y + (finish.y - start.y) * (time / Match2Core.MATCH_ANIM_TIME));

            card:setPos(current);
            card:setAngle(Match2Core.animatedCards[key].startAngle + (Match2Core.animatedCards[key].endAngle - Match2Core.animatedCards[key].startAngle) * (time / Match2Core.MATCH_ANIM_TIME));
        end)
end

