------------------------------------------------------------------------------
class 'ZoomZoneBase' (Node)
-------------------------------------------------------------------------------
function ZoomZoneBase:__init(name, mode, playfield)
	Node.__init(self, playfield:getMainEntity(), 'ZoomZone_'..name, 300)
	self.name       = name
	self.mode       = mode
	self.playfield  = playfield
	self.baseX      = 0
	self.baseY      = 0

	self.is_visible			= true
	self.bCloseOnClickFade	= true	-- Закрывать зум при клике по объекту затемнения

	self:setupTrigger()
	
	self.timer = self.playfield:getTimer()
	self.mouseBlocker = self.playfield:getMouseBlocker()
	
	-- Проверка не disabled ли зум зона уже?
	if HasGameState(ZOOM_DISABLED, self:getDisableState()) then
		self:disable()
	end

	-- Используется пустой объект, к которому потом крепятся РТТ, рамка и кнопка
	-- Это сделано для того, чтобы рамка всегда была выше РТТ
	self:getMainEntity():setXY(WORK_W/2, WORK_H/2)

	-- Создание объекта якоря, к которому непосредственно будут присоединяться все объекты, это делается для того, чтоб можна было ему задать смещение, и в дальнейшем присоединить к RTT-объекту    
	self.entity_anchor = CreateRenderedObject()
	self.entity_anchor:setName(name..'_entity_anchor')
	self.entity_anchor:attachTo(self:getMainEntity())
	self.entity_anchor:setXY(-WORK_W/2, -WORK_H/2)

	self:createContent()

	self.mode = mode or self:getZoomPrototypeMode()
	self:setMode(self.mode)
	
	if self.rtt_entity then
		self.entity_anchor:attachTo(self.rtt_entity)
	end
   
	if self.close_button then
		self.close_button.onPress:add(function()
										self:close()
									  end)
	end
	
	-- Прячем искусственно зум.
	self:hide(0)
	self.playfield.zones:Push(self)
end
-------------------------------------------------------------------------------

-- Загружать ресурсы при открытии или сразу?
function ZoomZoneBase:isLoadResourceOnOpen()
	return true
end
-------------------------------------------------------------------------------

 -- объект по которому идет открытие зум зоны
function ZoomZoneBase:setupTrigger()
	local triggerName = 'area_zoom_'..self.name

	if self.playfield:hasEntityNamed(triggerName) then
		local action = function()
			self:open()
		end

		self.trigger_object = self.playfield:getEntityNamed(triggerName)
		self.trigger_object:setCursorOverName('CursorGlass')
		self.trigger_object.onClickBegin:add(action)		-- Устанавливаем обработчик на открывание зум зоны
		self.trigger_object:setSendEventsToParent(false)	-- Для открытия зум зон с тулзой в руке (старый)

		self.node = path_manager:addZoom(self.name, triggerName)
	end
end
-------------------------------------------------------------------------------

function ZoomZoneBase:__finalize()
end
-------------------------------------------------------------------------------

function ZoomZoneBase:createContent()
	if self.CreateLoaderTable then
		local table_resource = self:CreateLoaderTable()
		self.load_resource = nil
		self.load_composition = nil

		local origCreateCompositionElement = nil
		local bLoadResourceOnOpen = self:isLoadResourceOnOpen()
		
		if bLoadResourceOnOpen then
			self.load_resource = {}
			for i, v in ipairs(table_resource) do 
				if v.name and v.texturePath and v.entityType == 'SpriteEntity' then
					local res		= {}
					res.name		= v.name
					res.texturePath	= v.texturePath
					res.width		= v.width
					res.height		= v.height
					table.insert(self.load_resource, res)

					v.texturePath = ''
				end
			end

			self.load_composition = {}

			CreatorCreateCompositionElement = function(path)
				local ext = ExtractFileExtention(path)
				if ext == "webm" then
					return origCreateCompositionElement(path)
				end

				local res = {}
				res.path = path
				res.anim = origCreateCompositionElement('')
				table.insert(self.load_composition, res)

				return res.anim
			end

			origCreateCompositionElement = CreateCompositionElement
			CreateCompositionElement = CreatorCreateCompositionElement
		end

		-- Don't load texure for disabled zoom zones.
		if self:isDisabled() then
			for i, v in ipairs(table_resource) do 
				v.texturePath = ''
			end
		end
		LoadScene( self.entity_anchor, table_resource )

		if bLoadResourceOnOpen then
			CreateCompositionElement = origCreateCompositionElement
		end
	end
end
-------------------------------------------------------------------------------

-- Get zoom prototype mode depending on the zoom objects sizes (width, length)
function ZoomZoneBase:getZoomPrototypeMode(objects)
	local modeSizeTable = self:getModeSizeTable()
	local objects		= self.entity_anchor:getChilds()

	for i = 0, objects:size() - 1 do
		local obj       = objects:get(i)
		local obj_name  = obj:getName()

		if obj.getSize then
			local width     = obj:getSize().x
			local height    = obj:getSize().y
		
			if obj:getAnimationFrameSize().x > 0 then
				width     = obj:getAnimationFrameSize().x
			end
			if obj:getAnimationFrameSize().y > 0 then
				height    = obj:getAnimationFrameSize().y
			end
			
			for mode, size in pairs(modeSizeTable) do
				if size.w == width and size.h == height then
					return mode
				end
			end
		end
	end 

	return ZOOM_TYPE_DISABLED
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getModeSizeTable()
	local modeSizeTable =
	{
		[ ZOOM_TYPE_FULLSCREEN		] = { w = WSCR_W, h = WSCR_H },
		[ ZOOM_TYPE_CIRCLE_BIG		] = { w = 300,	  h = 300	 },
		[ ZOOM_TYPE_RECT_VERTICAL	] = { w = 386,	  h = 512	 },
		[ ZOOM_TYPE_RECT_HORIZONTAL	] = { w = 640,	  h = 480	 },
		[ ZOOM_TYPE_NO_BORDER		] = { w = 0,	  h = 0		 },
		[ ZOOM_TYPE_DISABLED		] = { w = 8,	  h = 8		 }
	}
	return modeSizeTable
end
-------------------------------------------------------------------------------

function ZoomZoneBase:loading_resource()
	if self.load_resource then
		for i, v in ipairs(self.load_resource) do 
			local obj = self:getMainEntity():getEntityNamed(v.name)
			obj:setTextureInstant( v.texturePath )
			obj:setAnimationSize(v.width, v.height)
		end
		self.load_resource = nil
	end

	if self.load_composition then
		for i, v in ipairs(self.load_composition) do 
			v.anim:setTextureInstant(v.path)
		end
		self.load_composition = nil
	end
end
-------------------------------------------------------------------------------

--[[
 * Предназанчен для внутренних целей. Для открытия зума нужно использовать метод "open".
--]]
function ZoomZoneBase:show(time)
	if self:isVisible() == true then
		return
	end
	
	self:loading_resource()
	-- Console:pushText('ZoomZone:show '..tostring(time))

	self:getMainEntity():destroyEffectors()
	self:getMainEntity():show()
	
	if self.playfield:getActiveZones():GetTop() == nil then --if first opening zoom
		self.playfield:getZoomFade():destroyEffectors()
		self.playfield:getZoomFade():show()
		if time and time > 0 then
			self.playfield:getZoomFade():ChangeOpacity(0, 1, time):setDestroysOnEnd(false)
		else
			self.playfield:getZoomFade():setOpacity(1)
		end
	end
	self.playfield:getZoomFade():setOrder( self:getMainEntity():getOrder() - 1 )
	self:getMainEntity():setOpacity(1)
	self.is_visible = true

	if self.close_button then
		self.close_button:setRespondable(true)
	end

	self.playfield:hideBlackBar()
	
	if self.on_open then
		--on_open is deprecated and could be removed in future. Please use onOpen method instead!!!
		self:on_open()
	end
	
	self:setZoomZoneVisited()
end
-------------------------------------------------------------------------------

--[[
 * Предназанчен для внутренних целей. Для зактытия зума нужно использовать метод "close".
--]]
function ZoomZoneBase:hide(time)
	if self:isVisible() == false then
		return
	end
	
	local active_zone = self.playfield:getActiveZones():GetTop()
	if not active_zone then
		self.playfield:getZoomFade():destroyEffectors()
		self.playfield:getZoomFade():setRespondable(false)
		self.playfield:getZoomFade():ChangeOpacity(nil, 0, time):setDestroysOnEnd(false)
	else
		self.playfield:getZoomFade():setOrder( active_zone:getMainEntity():getOrder() - 1)
	end
		
	self:getMainEntity():destroyEffectors()
	if time and time > 0 then
		self:getMainEntity():setOpacity(0)
		self:getMainEntity():hide()
		self.playfield:getTimer():add(  function()
											self.is_visible = false
											self:getMainEntity():hide()
											local active_zone = self.playfield:getActiveZones():GetTop()
											if active_zone then
												self.playfield:getZoomFade():setRespondable(true)
											end
										end, time)
	else
		self:getMainEntity():setOpacity(0)
		self:getMainEntity():hide()
		if not active_zone then
			self.playfield:getZoomFade():hide()
		end

		self.is_visible = false
	end

	if self.close_button then
		self.close_button:setRespondable(false)
	end

	self.playfield:hideBlackBar()

	if self.on_close then
		--on_close is deprecated, called in init by mistake, and could be removed in future. Please use onClose method instead!!!
		self:on_close()
	end
end
-------------------------------------------------------------------------------

function ZoomZoneBase:open(time)
	if self:isVisible() then
		return
	end

	time = (time == nil) and ZOOM_ZONE_APPEARING_TIME or time
	local activeZone = self.playfield:getActiveZones():GetTop()
	
	if activeZone then
		local order = activeZone:getMainEntity():getOrder() + 10
		self:getMainEntity():setOrder(order)
	end
	self:show(time)
	
	if self.node and self.node.state ~= NodeState.TRIGGERED then
		self.node:trigger()
	end

	self.playfield:getActiveZones():Push(self)
	
	self:onOpen()
end
-------------------------------------------------------------------------------

function ZoomZoneBase:close(time)
	if not self:isVisible() then
		return
	end

	local active_zone = self.playfield:getActiveZones():GetTop()
	if active_zone == nil then
		WriteWarning("trying to close zoom "..self.name.." while zoom stack already empty")
		return
	elseif active_zone and active_zone.name ~= self.name then
		WriteWarning("trying to close zoom "..self.name.." while it is not on top if zoom stack")
		return
	end
	self.playfield:getActiveZones():Pop()

	time = (time == nil) and ZOOM_ZONE_APPEARING_TIME or time
	self:hide(time)
	
	self:onClose()
end
-------------------------------------------------------------------------------

function ZoomZoneBase:onOpen()
end
-------------------------------------------------------------------------------

function ZoomZoneBase:onClose()
end
-------------------------------------------------------------------------------

function ZoomZoneBase:isVisible()
	return self.is_visible
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getPlayField()
	return self.playfield
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getZoomEntity()
	return self:getMainEntity()
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getRTTEntity()
	return self.rtt_entity
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getCloseButton()
	return self.close_button
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getTimer()
	return self.playfield:getTimer()
end
-------------------------------------------------------------------------------

function ZoomZoneBase:setOrder(order)
	self:getMainEntity():setOrder(order)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getOrder(order)
	return self:getMainEntity():getOrder()
end
-------------------------------------------------------------------------------

function ZoomZoneBase:setZoomZoneVisited()
	local name_scene = current_scene:getPlayField():getName()
	local value = name_scene..'('..self.name..')'
	AddUniqueGameState(ZOOM_VISITED, value)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:isFirstVisited()
	return not isZoomZoneVisited(self.name, current_scene:getPlayField():getName()) 
end
-------------------------------------------------------------------------------

function isZoomZoneVisited(name_zoom, name_scene)
	name_scene = name_scene or current_scene:getPlayField():getName()
	local value = name_scene..'('..name_zoom..')'
	return HasGameState(ZOOM_VISITED, value)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:onDefaultSkipMiniGame()
	if self.skipMiniGame then
		self:skipMiniGame()
	end
end
-------------------------------------------------------------------------------

function ZoomZoneBase:disable()
	self.disabled = true
	
	if self.trigger_object then
		self.trigger_object:hide()
	end
		
	local value = self:getDisableState()
	AddUniqueGameState(ZOOM_DISABLED, value)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:enable()
	self.disabled = false
	
	if self.trigger_object then
		self.trigger_object:show()
	end
	
	local value = self:getDisableState()
	if HasGameState(ZOOM_DISABLED, value) then
		RemoveGameState(ZOOM_DISABLED, value)
	end
end
-------------------------------------------------------------------------------

function ZoomZoneBase:isDisabled()
	return self.disabled
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getDisableState()
	local sceneName = self.playfield:getName()
	return string.format('%s_%s_disable', sceneName, self.name)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:closeAndDisable()
	self:close(0)
	self:disable()
end
-------------------------------------------------------------------------------

function ZoomZoneBase:setCloseOnClickFade(bCloseOnClickFade)
	self.bCloseOnClickFade = bCloseOnClickFade
end
-------------------------------------------------------------------------------

function ZoomZoneBase:isCloseOnClickFade()
	return self.bCloseOnClickFade
end
-------------------------------------------------------------------------------

function ZoomZoneBase:setOffsetXY(offsetX, offsetY)
	local x = self.baseX + offsetX
	local y = self.baseY + offsetY
	
	self:getMainEntity():setXY(x, y)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:setMode(mode)
	local widthRTT
	local heightRTT
	local offsetX
	local offsetY

	if mode == ZOOM_TYPE_FULLSCREEN then
		-- Создание спрайта для закрывания зоны
		do
			local size	= Vector2f(WSCR_W, 140)
			local pos	= Vector2f(0, WORK_H/2 - size.y/2)
			local close = function(entity, screenFocus)
				if screenFocus then
					local active_zone = self.playfield:getActiveZones():GetTop()
					if active_zone then
						active_zone:close()
					end
				end
			end
		
			local closeFullScreenZone = CreateSpriteEntity('')
			closeFullScreenZone:setName				( 'closeFullScreenZone' )
			closeFullScreenZone:setCursorOverName	( 'CursorDown' )
			closeFullScreenZone:attachTo			( self:getMainEntity() )
			closeFullScreenZone:setAnimationSize	( size )
			closeFullScreenZone:setHotSpot			( size.x/2, size.y/2 )
			closeFullScreenZone:setPosition			( pos )
			closeFullScreenZone:setColor			( Colorf(1, 1, 1, 0.01) )
			closeFullScreenZone:setOrder			( 1500 )
			closeFullScreenZone.onClickBegin:add	( close )
		end
	elseif mode == ZOOM_TYPE_CIRCLE_BIG then
		local zoom_border = CreateSpriteEntity('Data/Textures/GUI/Zoom/zoom300.png')
		zoom_border:attachTo(self:getMainEntity())
		zoom_border:setName('ZoomZoneBorder'..self.name)
		zoom_border:setXY(0, -4)
		zoom_border:setOrder(3)
		zoom_border:setRespondable(false)
		self.object_border = zoom_border
		
		local bttn_close = CreateButtonEntity('Data/Textures/GUI/Zoom/close.png')
		bttn_close:attachTo(self:getMainEntity())
		bttn_close:setName('ZoomZoneClose'..self.name)
		bttn_close:setXY(109, -137)
		bttn_close:setOrder(2)
		bttn_close:setRespondable(false)
		self.close_button = bttn_close
		
		widthRTT    = 300
		heightRTT   = 300
		offsetX     = 0
		offsetY     = 0        
	elseif mode == ZOOM_TYPE_RECT_HORIZONTAL then
		local zoom_border = CreateSpriteEntity('Data/Textures/GUI/Zoom/zoom640.png')
		zoom_border:attachTo(self:getMainEntity())
		zoom_border:setName('ZoomZoneBorder'..self.name)
		zoom_border:setXY(0, 20)
		zoom_border:setOrder(3)
		zoom_border:setRespondable(false)
		self.object_border = zoom_border
		
		local bttn_close = CreateButtonEntity('Data/Textures/GUI/Zoom/close.png')
		bttn_close:attachTo(self:getMainEntity())
		bttn_close:setName('ZoomZoneClose'..self.name)
		bttn_close:setXY(315, -228)
		bttn_close:setOrder(2)
		bttn_close:setRespondable(false)
		self.close_button = bttn_close
		
		widthRTT    = 640
		heightRTT   = 480
		offsetX     = 0
		offsetY     = -60
	elseif mode == ZOOM_TYPE_RECT_VERTICAL then
		local zoom_border = CreateSpriteEntity('Data/Textures/GUI/Zoom/zoom432.png')
		zoom_border:attachTo(self:getMainEntity())
		zoom_border:setName('ZoomZoneBorder'..self.name)
		zoom_border:setXY(3, 29)
		zoom_border:setOrder(3)
		zoom_border:setRespondable(false)
		self.object_border = zoom_border
		
		local bttn_close = CreateButtonEntity('Data/Textures/GUI/Zoom/close.png')
		bttn_close:attachTo(self:getMainEntity())
		bttn_close:setName('ZoomZoneClose'..self.name)
		bttn_close:setXY(195, -279)
		bttn_close:setOrder(2)
		bttn_close:setRespondable(false)
		self.close_button = bttn_close
		
		widthRTT    = 386
		heightRTT   = 512
		offsetX     = 0
		offsetY     = -50
	elseif mode == ZOOM_TYPE_MINI_GAME then
		local zoom_border = CreateSpriteEntity('Data/Textures/GUI/Zoom/zoom_mg.png')
		zoom_border:attachTo(self:getMainEntity())
		zoom_border:setName('ZoomZoneBorder'..self.name)
		zoom_border:setXY(9, 7)
		zoom_border:setOrder(3)
		zoom_border:setRespondable(false)
		self.object_border = zoom_border
		
		local bttn_close = CreateButtonEntity('Data/Textures/GUI/Zoom/close.png')
		bttn_close:attachTo(self:getMainEntity())
		bttn_close:setName('ZoomZoneClose'..self.name)
		bttn_close:setXY(344, -257)
		bttn_close:setOrder(2)
		bttn_close:setRespondable(false)
		self.close_button = bttn_close
		
		widthRTT    = 640
		heightRTT   = 480
		offsetX     = 0
		offsetY     = -60
	end
	
	-- create RTTEntity
	if widthRTT and heightRTT then
		--entity = CreateRTTEntity(widthRTT, heightRTT)
		local entity = CreateRenderedObject()
		entity:attachTo(self:getMainEntity())
		entity:setName('ZoomZoneRTT'..self.name)
		entity:setOrder(1)
		self.rtt_entity = entity
		
		self:getMainEntity():setXY(self:getMainEntity():getX() + offsetX, self:getMainEntity():getY() + offsetY)
		
		local x = self:getMainEntity():getX() - offsetX
		local y = self:getMainEntity():getY() - offsetY
		self.entity_anchor:setScissorBox(x - widthRTT/2, y - heightRTT/2, x + widthRTT/2, y + heightRTT/2)
	end
	
	self.baseX = self:getMainEntity():getX()
	self.baseY = self:getMainEntity():getY()
end
-------------------------------------------------------------------------------

-- added for consistency
function ZoomZoneBase:playSound(sound_name, repeated)
	return self.playfield:playSound(sound_name, repeated)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:restartSound(sound_name)
	return self.playfield:restartSound(sound_name)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:stopSound(sound_name)
	return self.playfield:stopSound(sound_name)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:setSoundType(sound_name, sound_type)
	return self.playfield:setSoundType(sound_name, sound_type)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getSound(sound_name)
	return self.playfield:getSound(sound_name)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getName()
	return self.name
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getTriggerName()
	return self.trigger_object and self.trigger_object:getName()
								or nil
end
-------------------------------------------------------------------------------

function ZoomZoneBase:hasObject(object)
	if type(object) == 'string' then
		return self.entity_anchor:getEntityNamed(object) and true or false
	else
		return object:hasParent(self.entity_anchor)
	end
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getObjects()
	return self.entity_anchor:getChilds()
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getEntityAnchor()
	return self.entity_anchor
end
-------------------------------------------------------------------------------

function ZoomZoneBase:ShowMonolog(comicsName, textKey)
	self.playfield:showBlackBar(textKey)
end
-------------------------------------------------------------------------------

-- register functions
function ZoomZoneBase:registerActiveObject(...)
	return self.playfield:registerActiveObject(...)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:registerToolFindInfo(...)
	return self.playfield:registerToolFindInfo(...)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:registerToolApplyInfo(...)
	return self.playfield:registerToolApplyInfo(...)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:registerWrongApplyDialog(...)
	return self.playfield:registerWrongApplyDialog(...)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:registerWrongApplyAction(...)
	return self.playfield:registerWrongApplyAction(...)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:registerHintObject(...)
	return self.playfield:registerHintObject(...)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:registerBBT(...)
	return self.playfield:registerBBT(...)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:registerDragObject(...)
	return self.playfield:registerDragObject(...)
end
-------------------------------------------------------------------------------

-- several other functions from playfield
function ZoomZoneBase:findTool(...)
	return self.playfield:findTool(...)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:isObjectClicked(...)
	return self.playfield:isObjectClicked(...)
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getTimer()
	return self.timer
end
-------------------------------------------------------------------------------

function ZoomZoneBase:getMouseBlocker()
	return self.mouseBlocker
end
-------------------------------------------------------------------------------

function ZoomZoneBase:createComics(...)
	return self.playfield:createComics(...)
end
-------------------------------------------------------------------------------