
if TextTwist == nil then
    TextTwist = {}
end

TextTwist.close_callback = nil
TextTwist.tutorial = false
exec_script("TextTwistLayout.lua")

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

function TextTwist:init()

    TextTwist.mCurrentDict = 1
    TextTwist.mNumWord = 24
    TextTwist.mLettersPersent = 0.3
    TextTwist.ChipSpeed = 350
    TextTwist.UsedDict = {}
    
    TextTwist.mDisplay = level_mgr:load_level("TextTwist")
    if TextTwist.ExitLevel == nil then
        TextTwist.ExitLevel = ""
    end

    TextTwist.mDisplay:set_element_eh('twist_remark', function() TextTwist:onRemarkClick() end)
    TextTwist.mDisplay:set_element_eh('twist_win', function() TextTwist:onWinClick() end)
end

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

----------------------------------------------------------------------------------------------------
function TextTwist:onWinClick()
    TextTwist.mDisplay:get_element('twist_win'):setActive(false)
    TextTwist.mDisplay:get_element('twist_win'):setVisible(false)

    TextTwist:exitAction(false)
end

----------------------------------------------------------------------------------------------------
function TextTwist:getRandomUnusedDict()
    for i = 1, #TextTwistDict do
        local dict = math.random(1,#TextTwistDict)
        local exist = false
        for j = 1, #TextTwist.UsedDict do
          if j == dict then exist = true end
        end
        
        if not exist then
            TextTwist.mCurrentDict = dict
            table.insert(TextTwist.UsedDict,TextTwist.mCurrentDict)
            return
        end
    end
    
    -- else all dictionary is used
    TextTwist.UsedDict = {}
    TextTwist.mCurrentDict = math.random(1,#TextTwistDict)
    table.insert(TextTwist.UsedDict,TextTwist.mCurrentDict)
end

function TextTwist:getStrongDict(word)
    TextTwist.mCurrentDict = 0 
    for i = 1, #TextTwistDict do
        if word == TextTwistDict[i][#TextTwistDict[i]] then
            TextTwist.mCurrentDict = i
            break
        end
    end
    table.insert(TextTwist.UsedDict,TextTwist.mCurrentDict)
end

----------------------------------------------------------------------------------------------------
function TextTwist:exitAction(skip)
	if TextTwist.close_callback then TextTwist.close_callback(skip) end
    if TextTwist.ExitLevel ~= "" then
        local level = TextTwist.ExitLevel
        TextTwist.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 TextTwist:onShow()

    TextTwist.mCursor = 1 -- место, куда вводим букву
    Media:switchBackgroundSet('TextTwist')
    Panel:show(false)
    Panel:showTimer(false)
    TextTwist.mDisplay:set_element_eh('enter_button', function() TextTwist:onPressEnter() end)
    TextTwist.mDisplay:set_element_eh('twist_button', function() TextTwist:onPressTwist() end)
    TextTwist.mDisplay:set_element_eh("btn_skip", function() TextTwist:exitAction(true) end)

    TextTwist.mChips = {}
    TextTwist.mPoints = {}
    TextTwist.mSymbols = {}
    TextTwist.mWordOk = {}
    TextTwist.mNumLetterOk = 0
    TextTwist.mNumLetterAll = 0
    TextTwist.mVolumes = {}
    for i = 1, #TextTwistPattern do
        TextTwist.mVolumes[i] = 0
    end
    
    for i = 1, 25 do
        TextTwist.mDisplay:get_element('bar'..i):setVisible(false)
    end
    
    if TextTwist.StrongWord == nil or TextTwist.StrongWord == '' then
        TextTwist:getRandomUnusedDict()
    else
        TextTwist:getStrongDict( TextTwist.StrongWord )
    end
    
    local main_word = TextTwist:charcode_split( TextTwistDict[TextTwist.mCurrentDict][#TextTwistDict[TextTwist.mCurrentDict]] ) 
    for i = 1, 7 do
        TextTwist.mDisplay:set_element_eh('chip'..i, function() TextTwist:onPressChip(i) end)
        local elem = TextTwist.mDisplay:get_element('chip'..i):findChild('char')
        elem:setUnicodeSumbols(main_word[i])
        TextTwist.mChips[i] = {state = 'base', point = i, symbol = main_word[i]}
        TextTwist.mPoints[i] = 'busy'
        TextTwist.mSymbols[i] = ''
    end
    
    TextTwist:setupWords()
    TextTwist:onPressTwist()
    addUpdateListener(TextTwist)

    TextTwist.mDisplay:play_clip('twist_remark', {frame_begin = 0, frame_end = 0})
    TextTwist.mDisplay:get_element('twist_remark'):setActive(true)
    TextTwist.mDisplay:get_element('access_denied_text'):setVisible(true)

    TextTwist.mDisplay:play_clip('twist_win', {frame_begin = 0, frame_end = 0})
    TextTwist.mDisplay:get_element('twist_win'):setActive(false)
    TextTwist.mDisplay:get_element('twist_win'):setVisible(false)
    TextTwist.mDisplay:get_element('access_granted_text'):setVisible(false)
    TextTwist.mDisplay:get_element('btn_skip'):setActive(false)
end

----------------------------------------------------------------------------------------------------
function TextTwist:start()
    TextTwist.mDisplay:get_element('twist_remark'):setVisible(false)
    TextTwist.mDisplay:get_element('access_denied_text'):setVisible(false)
    TextTwist.mDisplay:get_element('btn_skip'):setActive(true)

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

----------------------------------------------------------------------------------------------------
function TextTwist:onHide()
    if TextTwist.tutorial then
        Tutorial:leaveChapter()
    end
    removeUpdateListener(TextTwist)
--    Media:stopBackground('TextTwist')
end


----------------------------------------------------------------------------------------------------
function TextTwist:getNextPosFromVolume(volume)
     local pos = 0
     if TextTwistPattern[volume] > TextTwist.mVolumes[volume] then
             TextTwist.mVolumes[volume] = TextTwist.mVolumes[volume] + 1
             pos = TextTwist.mVolumes[volume]
     else
        return 0 
     end
     local count = 0
     for i = 1, #TextTwistPattern do
        if i == volume then
            count = count + pos
            return count
        else
            count = count + TextTwistPattern[i]
        end
     end
     return 0
end

function TextTwist:onPressEnter()
        
        local word_num = TextTwist:check_word(TextTwist.mSymbols)
        if word_num ~= 0 then
        
            if TextTwist.mWordOk[word_num] ~= nil or TextTwist.mWordOk[word_num] == true then
                -- already found
                Bubble:show("ids_texttwist_word_already_found", 180, 300, 650, 100, Bubble.TYPE_NORMAL, true)
                timer_mgr:add_timer( function() Bubble:hide(true)  end, 1, 1)
                TextTwist:revertLetters()
                return
            end
            TextTwist.mWordOk[word_num] = true
            
            local charcode_spl = TextTwist:charcode_split( TextTwistDict[TextTwist.mCurrentDict][word_num] )
            local letter_num = #charcode_spl
            local pos = TextTwist:getNextPosFromVolume(letter_num)
            if pos == 0 then
                -- no room
                Bubble:show("ids_texttwist_word_len_no_room", 180, 300, 650, 100, Bubble.TYPE_NORMAL, true)
                timer_mgr:add_timer( function() Bubble:hide(true)  end, 1, 1)
                TextTwist:revertLetters()
                return
            end
            
            local word_elem = TextTwist:getElemFromWordNum(pos)
            for j = 1, letter_num do
                local char = word_elem:findChild('let'..j):findChild('char')
                char:setVisible(true)
                char:setUnicodeSumbols(charcode_spl[j])
            end
            
            if letter_num == 7 then  TextTwist:Progress(TextTwist.mNumWord*7) end
            
            if TextTwist:Progress(letter_num) then
                -- ihhaa! game win
                --MinigameWin:show(2,function() 
                    --TextTwist:exitAction()
                --end)
                set_frame_listener(TextTwist.mDisplay:get_element('twist_win'), 'win_closed',
                    function()
                         TextTwist.mDisplay:get_element('twist_win'):setActive(true)
                    end)
                TextTwist.mDisplay:play_clip('twist_win', {frame_begin = 0, label_end = 'win_closed'})
                TextTwist.mDisplay:get_element('access_granted_text'):setVisible(true)
                TextTwist.mDisplay:get_element('btn_skip'):setActive(false)
            end
  
            TextTwist:revertLetters()
        else
            -- not found
            Bubble:show("ids_texttwist_word_not_found", 180, 300, 650, 100, Bubble.TYPE_NORMAL, true)
            timer_mgr:add_timer( function() Bubble:hide(true)  end, 1, 1)
            TextTwist:revertLetters()
        end

        if TextTwist.tutorial then
            Tutorial:sendMessage('ttwist.enter')
        end
        Media:soundEvent('ttwist.enter')
end

----------------------------------------------------------------------------------------------------
function TextTwist:getElemFromWordNum(word)
    local col = math.ceil( word/6 )
    local oct = word%6
    if col > 4 then col = 4 end
    if oct == 0 then oct = 6 end
    local elem = TextTwist.mDisplay:get_element('col'..col):findChild('word'..oct)
    return elem
end

----------------------------------------------------------------------------------------------------
function TextTwist:Progress(add_letter)
    TextTwist.mNumLetterOk = TextTwist.mNumLetterOk  + add_letter
    local persent = TextTwist.mNumLetterOk/TextTwist.mNumLetterAll
    local bar_num = math.ceil(25*persent)
      
    for i = 1, bar_num do
        if i > 25  then break end
        TextTwist.mDisplay:get_element('bar'..i):setVisible(true)
    end
    
    if bar_num >= 25 then return true end
    
    return false
end

----------------------------------------------------------------------------------------------------
function TextTwist:setupWords()
    local itr = 1
    for i = 1, #TextTwistPattern do
        for k = 1, TextTwistPattern[i] do
            TextTwist.mNumLetterAll = TextTwist.mNumLetterAll + TextTwistPattern[i]
            if itr > TextTwist.mNumWord then
                trace('PATTERN TextTwistPattern not valid!')
            end
            local elem_word = TextTwist:getElemFromWordNum(itr)
            itr = itr + 1
            for j = 1, 7 do
                local let = elem_word:findChild('let'..j)
                local char = let:findChild('char')
                char:setVisible(false)
                if j <= i then
                    let:setVisible(true)
                else
                    let:setVisible(false)
                end
            end
        end
    end
    TextTwist.mNumLetterAll = TextTwist.mNumLetterAll*TextTwist.mLettersPersent
end

----------------------------------------------------------------------------------------------------
function TextTwist:check_word(word)

    for i = 1, #TextTwistDict[TextTwist.mCurrentDict] do
        local current_word = TextTwist:charcode_split( TextTwistDict[TextTwist.mCurrentDict][i] )
        local is_true = i
        for j = 1, #current_word do
             if word[j] ~= current_word[j] or TextTwist.mCursor == j then 
                 is_true = 0 
                 break 
             end
         end
         if is_true ~= 0 and ( word[#current_word+1] == nil or (word[#current_word+1] ~= nil and word[#current_word+1] == "")) then
            return is_true 
         end
    end
    return 0
end

----------------------------------------------------------------------------------------------------
function TextTwist:charcode_split(s)
  local delimiter = 'u'
  local result = { }
  local from  = 1
  local delim_from, delim_to = string.find( s, delimiter, from  )
  while delim_from do
    table.insert( result, "u"..string.sub( s, from , delim_from-1 ) )
    from  = delim_to + 1
    delim_from, delim_to = string.find( s, delimiter, from  )
  end
  table.remove(result,1)
  table.insert( result, "u"..string.sub( s, from  ) )
  return result
end

----------------------------------------------------------------------------------------------------
function TextTwist:revertLetters()

        for i = 7, 1, -1 do
            if TextTwist.mChips[i].state == 'word' or TextTwist.mChips[i].state == 'fly' then
                local free_point = -1
                for j = 1, 7 do
                    if TextTwist.mPoints[j] == 'free' then
                        free_point = j
                        break
                    end
                end

                if free_point < 0 then
                    trace('WTF??!')
                    return
                end

                TextTwist.mChips[i].state = 'fly_back'
                local point = TextTwist.mDisplay:get_element('point'..free_point)
                TextTwist.mChips[i].target = Vec2(point:getPos(true).x, point:getPos(true).y)
                TextTwist.mChips[i].point = free_point
                TextTwist.mPoints[free_point] = 'busy'
                
            end
            TextTwist.mSymbols[i] = ""
        end
        TextTwist.mCursor = 1
end

----------------------------------------------------------------------------------------------------
function TextTwist:onPressTwist()
    local onBase = {}
    local freePoints = {}
    for i = 1, 7 do
        if TextTwist.mChips[i].state == 'base' then
            table.insert(onBase, i)
            --table.insert(freePoints, TextTwist.mChips[i].point)
            TextTwist.mPoints[TextTwist.mChips[i].point] = 'free'
        end
    end

    for i = 1, 7 do
        if TextTwist.mPoints[i] == 'free' then
            table.insert(freePoints, i)
        end
    end

    table.foreach(freePoints, function(key) trace(freePoints[key]) end)

    table.foreach(onBase,
        function(idx)
            local chipIdx = onBase[idx]
            --TextTwist.mPoints[TextTwist.mChips[chipIdx].point] = 'free'

            local rand = get_random(1, #freePoints + 1)
            local free_point = freePoints[rand]
            table.remove(freePoints, rand)

            TextTwist.mChips[chipIdx].state = 'fly_back'

            local point = TextTwist.mDisplay:get_element('point'..free_point)
            TextTwist.mChips[chipIdx].target = Vec2(point:getPos(true).x, point:getPos(true).y)

            TextTwist.mChips[chipIdx].point = free_point
            TextTwist.mPoints[free_point] = 'busy'
        end)

    if TextTwist.tutorial then
        Tutorial:sendMessage('ttwist.twist')
    end
    Media:soundEvent('ttwist.twist')
end


----------------------------------------------------------------------------------------------------
function TextTwist:onPressChip(chipIdx)
    
    local x = chipIdx
    if TextTwist.mChips[chipIdx].state == 'base' then
        TextTwist.mChips[chipIdx].state = 'fly'
        
        TextTwist.mSymbols[TextTwist.mCursor] = TextTwist.mChips[chipIdx].symbol
        
        local cursor = TextTwist.mDisplay:get_element('letter'..TextTwist.mCursor)
        TextTwist.mChips[chipIdx].target = Vec2(cursor:getPos(true).x, cursor:getPos(true).y)
        TextTwist.mChips[chipIdx].wordPos = TextTwist.mCursor

        TextTwist.mPoints[TextTwist.mChips[chipIdx].point] = 'free'
        
        TextTwist.mCursor = TextTwist.mCursor + 1
    elseif TextTwist.mChips[chipIdx].state == 'word' then
        if TextTwist.mChips[chipIdx].wordPos ~= TextTwist.mCursor - 1 then
            return
        end

        local free_point = -1
        for i = 7, 1, -1 do
            if TextTwist.mPoints[i] == 'free' then
                free_point = i
                break
            end
        end

        if free_point < 0 then
            trace('WTF??!??!!11')
            return
        end

        TextTwist.mChips[chipIdx].state = 'fly_back'

        local point = TextTwist.mDisplay:get_element('point'..free_point)
        TextTwist.mChips[chipIdx].target = Vec2(point:getPos(true).x, point:getPos(true).y)

        TextTwist.mChips[chipIdx].point = free_point
        TextTwist.mPoints[free_point] = 'busy'
        
        TextTwist.mCursor = TextTwist.mCursor - 1
        TextTwist.mSymbols[TextTwist.mCursor] = ""
    end

    if TextTwist.tutorial then
        Tutorial:sendMessage('ttwist.chipClick')
    end
    Media:soundEvent('ttwist.put')
end


----------------------------------------------------------------------------------------------------
function TextTwist:onLandChip(chipIdx)
    if TextTwist.mChips[chipIdx].state == 'fly' then
        TextTwist.mChips[chipIdx].state = 'word'
    elseif TextTwist.mChips[chipIdx].state == 'fly_back' then
        TextTwist.mChips[chipIdx].state = 'base'
    end
end

----------------------------------------------------------------------------------------------------
function TextTwist:update(aElapsed)
    table.foreach(TextTwist.mChips,
        function(chipIdx)
            if TextTwist.mChips[chipIdx].state == 'fly' or TextTwist.mChips[chipIdx].state == 'fly_back' then
                local elem = TextTwist.mDisplay:get_element('chip'..chipIdx)
                local curPos = elem:getPos(true)
                local newX = curPos.x + (TextTwist.mChips[chipIdx].target.x - curPos.x) / 5
                local newY = curPos.y + (TextTwist.mChips[chipIdx].target.y - curPos.y) / 5
                local dx = newX - TextTwist.mChips[chipIdx].target.x
                local dy = newY - TextTwist.mChips[chipIdx].target.y
                local distance = math.sqrt(dx * dx + dy * dy) * ( aElapsed * TextTwist.ChipSpeed )
                if distance < 1 then
                    elem:setPos(Vec2(TextTwist.mChips[chipIdx].target.x, TextTwist.mChips[chipIdx].target.y))
                    TextTwist:onLandChip(chipIdx)
                else
                    elem:setPos(Vec2(newX, newY))
                end
            end
        end)
end