function InitPhotoZone(obj_name, obj_text, photo_name, photo_action, tool_target, apply_action, keep_tool)
    if obj_name and obj_name ~= '' then
        local task_exist = play_field:GetLevelScreen():GetTaskByAlias(obj_text)
        if task_exist then
            task_exist:AddObject(obj_name)
            play_field:GetLevelScreen():AddTask(task_exist)
        else
            local task = CreateTask(obj_text, obj_text, obj_name)
            task:SetUse(true)
            play_field:GetLevelScreen():AddTaskSafe(task)
        end
    end
    
    if tool_target == '' then
        tool_target = nil
    end
    
    if not game_state.photo_objects then
        game_state.photo_objects = {}
    end
    
    local zone = {}
    AssignPhotoMethods(zone)
    zone.highlight = {}

    local info = {}
    info.zone = zone; zone.info = info;
    info.obj_name = obj_name
    info.obj_text = obj_text
    info.tool_name = obj_name
    info.photo_name = photo_name
    info.photo_action = photo_action
    info.tool_target = nil
    info.apply_action = apply_action
    info.remove_immediately = not keep_tool
    info.hint_comics = nil
    info.hint_comics_name = nil
    info.photo = false -- Признак того, что сделали фото
    table.insert(game_state.photo_objects, info)

    if obj_name and obj_name ~= '' then
        custom_cursors[obj_name] = GetCursorPhoto()
        locked_objects[obj_name] = true
    end
  
    ActivatePhotoZone(info, tool_target)
    return info
end

function CreatePhotoZone(obj_name, obj_text, photo_name, photo_action, tool_target, apply_action, keep_tool)
    local info = InitPhotoZone(obj_name, obj_text, photo_name, photo_action, tool_target, apply_action, keep_tool)
    CheckPhotoGameState(info)
    
    return info
end

function CreatePhotoZoneEx(obj_name, tool_name, obj_text, photo_name, photo_action, tool_target, apply_action, keep_tool)
    local info = InitPhotoZone(obj_name, obj_text, photo_name, photo_action, tool_target, apply_action, keep_tool)
    info.tool_name = tool_name
    info.obj_name = obj_name
    CheckPhotoGameState(info)
    
    return info
end

function ActivatePhotoZone(info, tool_target)
    if tool_target then
        if info.tool_target then
            for i, v in pairs(info.tool_target) do
                info.zone.ClearHighlight(v)
            end
        end
        info.zone.highlight = {}
        info.tool_target = {}
        if type(tool_target) == 'string' then
            table.insert(info.tool_target, tool_target)
        elseif type(tool_target) == 'table' then
            info.tool_target = tool_target
        end
        
        for i, target in ipairs(info.tool_target) do
            info.zone.AddHighlight(target)
            custom_cursors[target] = GetCursorMech()
        end
        
        CheckPhotoGameStateApply(info)
    end -- if tool_target then
end

function SetApplyActionPhotoZone(info, tool_target, apply_action)
    info.apply_action = apply_action
    ActivatePhotoZone(info, tool_target)
end

function SetHintComicsPhotoZoneEx(info, comics)
    info.hint_comics = comics
    info.hint_comics.bRepeat = true
    info.hint_comics.played = false
end

function CheckPhotoGameState(info)
    local pf = play_field
    local state_value = game_state.scene_path.."("..info.tool_name..")"
    if HasGameState('OnToolFound', state_value) then
        if info.obj_name then
            local task = pf:GetLevelScreen():GetTask(info.obj_name)
            if task:GetNumberOfObjects() ~= 0 then
                RemoveFromTask(info.obj_name)
            end
            
            pf:GetObject(info.obj_name):SetOpacity(0)
            pf:GetObject(info.obj_name):SetMaxOpacity(0)
        end
        
        local tool_obj = pf:GetObject(info.tool_name)
        if pf:GetLevelScreen():GetPhone():HasTool(tool_obj)  == false then
            pf:OnToolFound(tool_obj, pf:GetObject(info.photo_name))
        end
        pf:GetObject(info.tool_name):SetOpacity(0)
        pf:GetObject(info.tool_name):SetMaxOpacity(0)
        if HasGameState('PhotoAction', state_value) == false and info.photo_action then
            info.photo_action(true)
            info.photo_action = nil
        end
        
        pf:GetLevelScreen():GetPhone():SetTaskListVisible(true)
        info.photo = true
    end
  
    CheckPhotoGameStateApply(info)
end

function CheckPhotoGameStateApply(info)
    local pf = play_field
    if info.photo_action then
        return
    end
    
    if info.tool_target then
        for k, target in ipairs(info.tool_target) do 
            local state_value_apply = 'OnToolApply__'..game_state.scene_path
            if info.obj_name then
                state_value_apply = state_value_apply..'('..info.obj_name..')'
            end
            if HasGameState(state_value_apply, target) then
                if info.remove_immediately and pf:GetLevelScreen():GetPhone():HasTool(pf:GetObject(info.tool_name)) then
                    pf:GetLevelScreen():GetPhone():RemoveTool( pf:GetObject(info.tool_name) )
                end                    
   
                if HasGameState('ApplyAction', state_value) == false and info.apply_action then
                    info.apply_action(true, target)
                    info.zone.ClearHighlight(target)
                    if info.remove_immediately then
                        info.apply_action = nil
                    end
                    
                    if info.remove_immediately then
                        UnregisterPhotoZone(info.obj_name)
                    end
                end            
            end
        end
    end
end

function GetTextTool(tool)
    if game_state.photo_objects then
        local tool_name = tool:GetName()
        for i, info in ipairs(game_state.photo_objects) do
            if tool_name == info.tool_name then
                return info.obj_text
            end
        end
    end
    
    return ''
end

function AssignPhotoMethods(zone)
    zone.ClearHighlight = function(obj_name_target)
        if zone.info.tool_target then
            for k, target in ipairs(zone.info.tool_target) do
                if obj_name_target == target then
                    custom_cursors[target] = ''
                    break
                end
            end
        end
        
        if zone.highlight then
            for i, info in ipairs(zone.highlight) do
                if info.link_object == obj_name_target then
                    local name_target = info.obj_highlight:GetName()
                    play_field:GetObject(name_target):SetVisible(false)
                    table.remove(zone.highlight, i)
                    break
                end
            end
        end            
    end

    zone.AddHighlight = function(tool_target)
        local object_name_highlight = 'highlight__' .. tool_target
        local obj_highlight = nil
        if play_field:HasObject(object_name_highlight) then
            obj_highlight = play_field:GetObject(object_name_highlight)
            obj_highlight:SetOpacity(0)
            obj_highlight:SetVisible(true)
        else
            local anim = CreateAnimation('data/Texture/Effect/ObjectHighlight.png',0,0,47,47,1,0)
            anim:SetHotSpot(23.5,23.5)
            anim:SetBlendMode(2)
            anim:SetColor('0xFFFFFFFF')
            obj_highlight = play_field:CreateObject(object_name_highlight,anim,512,384,140,0,1,1)
            obj_highlight:SetOpacity(0)
            play_field:IgnoreOnTestPoint(object_name_highlight)
        end
        
        -- set parameter Highlight
        local obj_tool_target = play_field:GetObject(tool_target)
        local x_obj_tool_target = obj_tool_target:GetX()
        local y_obj_tool_target = obj_tool_target:GetY()
        local z_obj_tool_target = obj_tool_target:GetZ()
        obj_highlight:SetXY(x_obj_tool_target, y_obj_tool_target)
        obj_highlight:SetZ( z_obj_tool_target + 1)
        
        if zone.IsExistTargetOnAnotherPhotoZone(tool_target) == false then
            local info_highlight = {}
            info_highlight.link_object = tool_target
            info_highlight.obj_highlight = obj_highlight
            info_highlight.max_highlight_delay = 25
            info_highlight.highlight_delay = GetRandomFloat(1, info_highlight.max_highlight_delay)
            table.insert(zone.highlight, info_highlight)
        end
        
        custom_cursors[tool_target] = GetCursorMech()
    end
    
    zone.IsExistTargetOnAnotherPhotoZone = function(tool_target)
        if game_state.photo_objects then
            for i, info in ipairs(game_state.photo_objects) do
                if zone.info ~= info and info.tool_target then
                    for k, target in ipairs(info.tool_target) do
                        if target == tool_target then
                            return true
                        end
                    end
                end
            end
        end
    
        return false
    end
    
    zone.ClearSave = function()
        local state_value_apply = 'OnToolApply__'..game_state.scene_path
        if zone.info.obj_name then
            state_value_apply = state_value_apply..'('..zone.info.obj_name..')'
		end
		while(GameStateExists(state_value_apply)) do
            RemoveGameState(state_value_apply)
        end
        
    end

    zone.Update = function(dt)
        local info = zone.info
        local pf = play_field
        if zone.info.tool_target then
            for k, target in ipairs(zone.info.tool_target) do
                if  pf:GetObject(target):GetOpacity() > 0. and
                    pf:GetObject(target):IsVisible()
                then
                    for i, info in ipairs(zone.highlight) do
                        info.highlight_delay = info.highlight_delay - dt
                        if info.highlight_delay < 0 then
                            info.highlight_delay = info.max_highlight_delay
                            zone.Highlight(info.obj_highlight)
                        end
                    end
                end
            end
        end -- if zone.tool_target then
    end
    
    zone.SetOffsetHighlight = function(x, y)
        for i, info in ipairs(zone.highlight) do
            local obj_highlight = info.obj_highlight
            local old_x = obj_highlight:GetX()
            local old_y = obj_highlight:GetY()
            obj_highlight:SetXY(old_x + x, old_y + y)
        end
    end
    
    zone.Highlight = function(obj_highlight)
        local effect_time = 0.9
    
        local af = CreateAnimationEffector()
        af:AttachTo( obj_highlight )
        af:SetMode(_ANIM_NOLOOP)
        af:SetKey(_TRACK_O, effect_time * 0.,   0.)
        af:SetKey(_TRACK_A, effect_time * 0.,   0.)
        af:SetKey(_TRACK_S, effect_time * 0.,   0.3)
        af:SetKey(_TRACK_O, effect_time * 0.05, 1.)
        af:SetKey(_TRACK_S, effect_time * 0.25, 1.)
        af:SetKey(_TRACK_O, effect_time * 0.45, 1.)
        af:SetKey(_TRACK_A, effect_time * 0.45, 35. * M_PI / 180.)
        af:SetKey(_TRACK_S, effect_time * 0.45, 1.4)
        af:SetKey(_TRACK_O, effect_time * 0.70, 1.)
        af:SetKey(_TRACK_A, effect_time * 1.,   50. * M_PI / 180.)
        af:SetKey(_TRACK_S, effect_time * 1.,   1.)
        af:SetKey(_TRACK_O, effect_time * 1.,   0.)
        af:Play()
    end
    
    zone.SetPhotoMade = function()
        local state_value = game_state.scene_path.."("..zone.info.tool_name..")"
        if HasGameState('OnToolFound', state_value) == false then
            local pf = play_field
            AddGameState('OnToolFound', state_value)
            pf:OnToolFound(pf:GetObject(zone.info.tool_name), pf:GetObject(zone.info.photo_name))
            pf:GetLevelScreen():GetPhone():SetTaskListVisible(true)
            zone.info.photo = true
        end
    end
end

function RegisterPhotoObject(zone, photo_action)
    if not game_state.photo_objects then
        game_state.photo_objects = {}
    end
    
    if zone.photo_action then
        return
    end
    zone.photo_action = photo_action
    
end

function UnregisterPhotoZone(object_name, index)	
	local info_zone = nil
	if not index then
		for i, info in ipairs(game_state.photo_objects) do
			if info.obj_name == object_name then
				index = i
				info_zone = info
				break
			end
		end
	else
		info_zone = game_state.photo_objects[index]
	end
	
	if not info_zone then
	    return
	end
	local phone = play_field:GetLevelScreen():GetPhone()
	local tool = play_field:GetObject(info_zone.tool_name)
	if tool and phone:HasTool(tool) then
	    phone:RemoveTool(tool)
	    play_field:SetTool(nil)
    end
	table.remove(game_state.photo_objects, index)
end

function IsUnregisterPhotoZone(zone)
    if game_state.photo_objects then
        for i, info in ipairs(game_state.photo_objects) do
            if info.obj_name == zone.info.obj_name then 
                return false
            end
        end
    end
    
    return true
end

function IsCanMakePhoto(zone)
    if game_state.locker:GetNReferences() == 0 then
        return true
    end

    if zone.info.obj_name then
        return HasObjectInZoomZones(zone.info.obj_name)
    end
    
    return true
end

function SetTextPlural(text_singular, text_plural)
    local task_exist = play_field:GetLevelScreen():GetTaskByAlias(text_singular)
    if task_exist then
        task_exist:SetTextPlural(text_plural)
    end
end

