dofile('data/Scripts/ho/HiddenObjectIndicator.lua')
-------------------------------------------------------------------------------
class 'HiddenObjectLogic' (HiddenBaseLogic)
-------------------------------------------------------------------------------

function HiddenObjectLogic:__init()
    HiddenBaseLogic.__init(self)
    
    self.indicator = HiddenObjectIndicator()
    self.keyPrefix = ""
end
-------------------------------------------------------------------------------



--------------------------------------------------------------------------------
-- INTERFACE METHODS -----------------------------------------------------------
--------------------------------------------------------------------------------

function HiddenObjectLogic:RegisterTasks(keyPrefix, randomObjectsName, actionTasksObjectsName, ...)
    self.keyPrefix = (keyPrefix) and keyPrefix or self.keyPrefix
    ---------
    
    local dealsObjects  = {...}
    local taskTemplates = {}
    ---------
    
    table.insert(taskTemplates, self:_uniteObjectsToTaskTemplates(randomObjectsName))
    for i, objects in ipairs(dealsObjects) do
        table.insert(taskTemplates, self:_uniteObjectsToTaskTemplates(objects))
    end
    
    for i=2, #taskTemplates do
        self:_moveIdenticalTaskTemplates(taskTemplates[1], taskTemplates[i])
    end
    ---------
    
    local tasks = {}
    
    for i, templates in ipairs(taskTemplates) do
        tasks[i] = {}
        
        for text, template in pairs(templates) do
            assert(#template > 0)
            
            local textKey = self:_getKey(template[1])
            local newTask = self:_createTask(textKey, template)
            
            self:_setActionObjects(newTask, template, actionTasksObjectsName)
            tasks[i][text] = newTask
        end
    end
    ---------
    
    local has_generated_tasks = false
    local dealTasks = tasks[self.dealIndex + 1]
    
    if dealTasks == nil or table.size(dealTasks) == 0 then
        for text, task in pairs(tasks[1]) do
            if IsActiveTask(task) then
                has_generated_tasks = true
                break
            end
        end
    else
        for text, task in pairs(dealTasks) do
            if IsActiveTask(task) then
                has_generated_tasks = true
            end
            
            self:_addTask(task)
        end
    end
    ---------
    
    local random_tasks = {}

    for text, task in pairs(tasks[1]) do
		if (not has_generated_tasks and task:GetNumberOfObjects() > 0)
            or IsActiveTask(task)
		then
            table.insert(random_tasks, task)
			play_field:IgnoreTaskObjectsOnTestPoint(task)
        end
    end
    
    table.shuffle(random_tasks)
    local n = #random_tasks
	
	if not IsDebugLocalization() then
		if n > ACTIVE_TASKS_NUMBER - play_field:GetLevelScreen():GetNTasks() then
			n = ACTIVE_TASKS_NUMBER - play_field:GetLevelScreen():GetNTasks()
		end
	end

    local level_screen = play_field:GetLevelScreen()
    for i = 1, n do
		local task = random_tasks[i]
        self:_addTask(task)
		play_field:DoNotIgnoreTaskObjectsOnTestPoint(task)
    end
end
--------------------------------------------------------------------------------

function HiddenObjectLogic:CreateFlyAnim(object)
    local delay  = 1.1
    local time   = 0.7
    local anchor = self.indicator:GetAnchor()
    
	object:SetLayer(anchor:GetLayer())
	object:SetScrZ (anchor:GetScrZ() + 3)

    do
        local scaleX = object:GetScaleX()
        local scaleY = object:GetScaleY()
        
        local task      = GetTask(object:GetName())
        local startPos  = Vector(object:GetScrX(), object:GetScrY())
        local finishPos = self.indicator:GetTaskPos(task)
        
	    local maxDeltaPos   = 256
	    local desappearTime = 0.3
        
        local mover = CreateAnimationEffector()
        mover:AttachTo(object)

        mover:SetKey(_TRACK_SX, 0,				scaleX * 1)
        mover:SetKey(_TRACK_SX, delay * 0.25,	scaleX * 1.5)
        mover:SetKey(_TRACK_SX, delay * 0.5,	scaleX * 1)
        mover:SetKey(_TRACK_SX, delay * 0.75,	scaleX * 1.5)
        mover:SetKey(_TRACK_SX, delay,			scaleX * 1)
        mover:SetKey(_TRACK_SX, delay + time,	scaleX * 0.3)

        mover:SetKey(_TRACK_SY, 0,				scaleY * 1)
        mover:SetKey(_TRACK_SY, delay * 0.25,	scaleY * 1.5)
        mover:SetKey(_TRACK_SY, delay * 0.5,	scaleY * 1)
        mover:SetKey(_TRACK_SY, delay * 0.75,	scaleY * 1.5)
        mover:SetKey(_TRACK_SY, delay,			scaleY * 1)
        mover:SetKey(_TRACK_SY, delay + time,	scaleY * 0.3)
        
        mover:SetKey(_TRACK_O, delay + time, object:GetOpacity())
        mover:SetKey(_TRACK_O, delay + time + desappearTime,	0)
        
	    MakePositionKeysBySpline(mover,
                                 startPos,
                                 startPos + Vector(RandomFloat(-maxDeltaPos, maxDeltaPos),
                                                   RandomFloat(-maxDeltaPos, maxDeltaPos)),
                                 finishPos,
                                 finishPos + Vector(RandomFloat(-maxDeltaPos, maxDeltaPos), -200),
                                 20,
                                 time,
                                 delay)
    
	    mover:Play()
    end
    
    self:InitSounds()
    self:PlayFoundSound()
    
    GetCurrentLevel().timer:Add(function()
                                    self:PlayFlyingSound()
                                    object:AddParticleSystem('data/ParticleSystem/ObjectMoveTail.psi',
                                                             'ZoneHighlightParticle',
                                                             true)
                                end, delay)
    return (delay + time)
end
--------------------------------------------------------------------------------

function HiddenObjectLogic:CheckTaskObjectMouseDown(objectName)
    if play_field:GetLevelScreen():IsTaskObject(objectName) then
        SetTaskObjectFound(objectName)
        
        local object = play_field:GetObject(objectName)
        play_field:OnObjectFound(object)
        play_field:IgnoreOnTestPoint(objectName)
        return true
    end
    
    return false
end
--------------------------------------------------------------------------------

function HiddenObjectLogic:OnObjectReachPanel(object)
    HiddenBaseLogic.OnObjectReachPanel(self, object)
    
    local task = GetTask(object:GetName())
    self.indicator:UpdateCaption(task, false)
end
--------------------------------------------------------------------------------


--------------------------------------------------------------------------------
-- PRIVATE METHODS -------------------------------------------------------------
--------------------------------------------------------------------------------

function HiddenObjectLogic:_getKey(objectName)
    return self.keyPrefix..string.upper(objectName)
end
--------------------------------------------------------------------------------

function HiddenObjectLogic:_uniteObjectsToTaskTemplates(objects)
    local result      = {}
    local objectsType = type(objects)
    
    if objectsType == 'table' then
        for _, objectName in ipairs(objects) do
            local key    = self:_getKey(objectName)
            local value  = GetString(key)
            local bAdded = false
            
            for existValue, objs in pairs(result) do
                if value == existValue then
                    table.insert(objs, objectName)
                    bAdded = true
                    break
                end
            end
            
            if not bAdded then
                result[value] = {}
                table.insert(result[value], objectName)
            end
        end
        
    elseif objectsType == 'string' then
        local key    = getKey(objects)
        local value  = GetString(key)
        
        result[value] = {}
        table.insert(result[value], objects)
    end
    
    return result
end
--------------------------------------------------------------------------------

function HiddenObjectLogic:_moveIdenticalTaskTemplates(source, target)
    for tValue, tGroup in pairs(target) do
        for sValue, sGroup in pairs(source) do
            if tValue == sValue then
                for i, objectName in ipairs(sGroup) do
                    table.insert(tGroup, objectName)
                end
                
                source[sValue] = nil
                break
            end
        end
    end
end
--------------------------------------------------------------------------------

function HiddenObjectLogic:_isTemplateContainObject(template, objectName)
    for _, tmplObjectName in ipairs(template) do
        if objectName == tmplObjectName then
            return true
        end
    end
    
    return false
end
--------------------------------------------------------------------------------

function HiddenObjectLogic:_setActionObjects(task, template, actionTasksObjects) 
    if actionTasksObjects == nil then
        return false
    end
    
    for _, objectName in ipairs(template) do
        if task:HasObject(objectName) and
           self:_isTemplateContainObject(actionTasksObjects, objectName)
        then
            task:SetActionObject(objectName, true)
        end
    end
end
--------------------------------------------------------------------------------

function HiddenObjectLogic:_createTask(textKey, objects)
    local level = GetCurrentLevel()
   	local task  = CTask(textKey)
   	
    for i, objectName in ipairs(objects) do
        if play_field:HasObject(objectName) then
            if IsTaskObjectFound(objectName) then
                local obj = play_field:GetObject(objectName)
                obj:SetOpacity(0)
                obj:SetVisible(false)
                obj:Hide()
            else
                task:AddObject(objectName)
            end
            
            table.insert(self.createdTaskObjects, objectName)
        end
    end

    assert(not play_field:GetLevelScreen():HasTask(textKey))
    return task
end
--------------------------------------------------------------------------------

function HiddenObjectLogic:_addTask(task)
    play_field:GetLevelScreen():AddTask(task)
    SetActiveTaskState(task)
end
--------------------------------------------------------------------------------