-- ----------------------------------------------------------------------------
-- a stack that holds the order of opened layouts
-- layouts will be pushed and popped to it when show() or hide() is called.
layoutStack = {}
-- ----------------------------------------------------------------------------
gSelection = nil
-- ----------------------------------------------------------------------------
-- const variables
-- copied from Layout.h, make sure these are up to date always
Layout.kUnconstructed   = 0
Layout.kUninitialized 	= 1
Layout.kHidden			= 2
Layout.kInactive		= 3
Layout.kActive			= 4
-- ----------------------------------------------------------------------------
kMessageThought 	= 0
kMessageGoal    	= 1
-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------
-- overridden c++ functions
-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnConstruct = Layout.onConstruct
	function Layout:onConstruct()	
	
		if (self.mExits == nil) then self.mExits = {} end
		if (self.mPOIs == nil) then self.mPOIs = {} end
		if (self.mHOs == nil) then self.mHOs = {} end
		if (self.mIOs == nil) then self.mIOs = {} end
		if (self.mProps == nil) then self.mProps = {} end	
		if (self.mOrder == nil) then self.mOrder = {} end	
		if (self.mGroups == nil) then self.mGroups = {} end
		if (self.mButtons == nil) then self.mButtons = {} end
		if (self.mSprites == nil) then self.mSprites = {} end
		if (self.mFireflies == nil) then self.mFireflies = {} end
		if (self.mParticles == nil) then self.mParticles = {} end
		
		-- info
		print("constructing " .. self:getLayoutID() .. "...")		
	
		-- interactive objects _might_ have links
		-- the objects that are linked to it can be linked to multiple objects
		-- and thus need to be used multiple times.
		-- build those variables here.
		-- we need to built those here and not in onInitialize, since an object
		-- may be used in multiple places and onInitialize won't be called until
		-- this layout is shown and the object might already be gone by then!
		for object, props in pairs(self.mIOs) do
			if (props.links) then
				object.linked = {}			
				for i, link in ipairs(props.links) do
					if (link.timesLinkedCount == nil) then
						-- create the entries
						link.timesLinkedCount = 0
						link.timesUsedCount = 0
					end				
					
					-- increase the entry
					link.timesLinkedCount = link.timesLinkedCount + 1
					
					-- add it to the object linked map
					table.insert(object.linked, link)
				end
			end		
		end
		
		-- hidden objects need to start in the idle state!
		-- when we have a goal step to click a hidden object, that hint will send
		-- that user to that object even if he can't click it (it's locked). we could
		-- add 'state = kActive' to the step, but when goal has a chance to evaluate
		-- the click in _onClickObject, the state of the object is 'kFound', meaning
		-- the step won't be set to done! to fix this, make ho's start idle.
		for object, props in pairs(self.mHOs) do
			object:ss(kIdle)
			
			-- check if all HOs have an inventory image			
			if (not object:hasInventoryData()) then
				print("WARNING: hidden object is missing inventory data: " .. object:name())
			end			
		end
		
		local sources =
		{
		    self.mExits,
		    self.mPOIs,
		    self.mHOs,
		    self.mIOs,
		}
		
		-- check if an object wasn't inadvertedly moved from one layout to another.
		for i, source in ipairs(sources) do
    		for object, props in pairs(source) do
				if (object:getLayout() ~= self) then
   		    		print("ERROR: object is not in this layout!: " .. object:name() .. " in " .. self:name())
    		    end
    		end
    	end
		
		-- group objects have some lua member variables
		-- set them here
		for object, props in pairs(self.mGroups) do
			if (props.children) then
				print("created group: " .. object:name())
				object.groupChildren = props.children
				object.showAsGroupInInventory = props.inventory
				object.showAsGroupInShoppingList = props.shoppinglist
				
				-- if nil, set to false
				if (object.showAsGroupInInventory == nil) then 
					object.showAsGroupInInventory = false
				end
				if (object.showAsGroupInShoppingList == nil) then 
					object.showAsGroupInShoppingList = false
				end				
			
				-- reverse set the group id on all children
				for i, child in ipairs(props.children) do
					print("reverse set group id on: " .. child:name() .. " to " .. object:name())
					child.groupParent = object
				end
			end
		end
				
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnInitialize = Layout.onInitialize
	function Layout:onInitialize()
	
		-- info
		print("initializing " .. self:getLayoutID() .. "...")
		
		-- create a fade sprite
		-- it will be named "FADEOUT_"<layoutID>
		self.mFadeName = "FADEOUT_" .. self:getLayoutID()
		self.mFade = self:newChildSprite(
			{
				x = 0, 
			 	y = 0, 
			 	width = self:width(), 
			 	height = self:height(), 
			 	draw = "color", 
			 	color = 0, 
			 	alpha = 0, 
			 	visible = false,
			 	name = self.mFadeName
			}
		)
		
		print("created fadeout sprite sized: (" .. self:width() .. "x" .. self:height() .. ")")
		
		-- create exit highlight reference
		self.mHighlightedExit = nil
		
		-- generate new mirror entries
		local sources =
		{
			self.mExits,
			self.mPOIs,
			self.mIOs,
		}
		
		for i, source in ipairs(sources) do
			local generated = {}
			for object, props in pairs(source) do
				if (props.mirrors) then
					for j, mirror in ipairs(props.mirrors) do
						if (mirror ~= nil) then
							-- create new entry
							assert(generated[mirror] == nil)
							generated[mirror] = {}
							
							-- copy properties
							for key, val in pairs(props) do
								generated[mirror][key] = val
							end
	
							-- no mirrors
							-- if we copy over the mirrors element as well, we'll
							-- get in an endless loop!
							generated[mirror].mirrors = nil
							
							-- info
							print("generated mirror entry: " .. mirror:name())
						else
							print("WARNING: " .. self:name() .. " contains a nil mirror entry in " .. object:name())
						end
					end				
				end
			end		
			
			for object, props in pairs(generated) do
				assert(source[object] == nil)			
				source[object] = props
			end
		end
		
		-- merge the object sets in one map
		-- assumes no object can have multiple functionality (can't be
		-- both an exit and a poi for example). this seems to be true.
		local sources =
		{
		    self.mExits,
		    self.mPOIs,
		    self.mHOs,
		    self.mIOs,
		    self.mFireflies,
		    self.mButtons,
		}
		
		for i, source in ipairs(sources) do
    		for object, props in pairs(source) do
    		    if (self.mProps[object] ~= nil) then
    		        print("ERROR: object in multiple maps!: " .. object:name())
    		    else
    		        print("constructed new props entry: " .. object:name())
    		    end
    		    
    		    self.mProps[object] = props
    		end
    	end

	    for i = self:getObjectCount(),1,-1 do
    		-- create a order map
    		-- this is the z-order reversed (toppest object first)
    		-- only contains the interesting objects	    
	    	local object = self:getObjectByIdx(i-1)
	    	if (self.mProps[object]) then
				table.insert(self.mOrder, object)
			end
			
			-- all blurs initially done
			-- for now
			if (object:isBlur()) then
				object:ss(kDone)
				print("auto inactivated: " .. object:name())
			end
			
			-- all fireflies initially inactive
			if (object:isFirefly()) then
				object:ss(kInactive)
				print("auto inactivated: " .. object:name())
			end		
	    end
    
    	-- assign a default magnify cursor to all POIs
    	-- only if no specific exists
    	for object, props in pairs(self.mPOIs) do
    	    if (props.cursors == nil) then
    	        props.cursors = kCursorMagnify
    	    end
    	end
    	
    	-- assign a default arrow-up cursor to all Exits
    	-- only if no specific exists
    	for object, props in pairs(self.mExits) do
    	    if (props.cursors == nil) then
    	        props.cursors = kCursorArrow
    	    end
    	end  
    	
    	-- assign a default puzzle cursor to all IOs
    	-- only if no specific exists
    	for object, props in pairs(self.mIOs) do
    		if (props.cursors == nil) then
    	    	if (props.cursor == nil) then
    	        	props.cursor = kCursorPointer
    	    	end
    	    	if (props.dragcursor == nil) then
    	    		props.dragcursor = kCursorCombine
    	    	end
    	    end
    	end
    	
    	-- create some default variables for all buttons
    	for button, props in pairs(self.mButtons) do
    		button.over = false
    		button.pressed = false
    		button.enabled = true
    	end
    	
    	-- change states for siblings to their root
    	-- if we don't do this, the auto state change isn't applied 
    	-- in onObjectStateChanged.
    	for object, props in pairs(self.mProps) do
    		if (props.siblings) then
    			for i, sibling in ipairs(props.siblings) do
    				if (sibling:getLayout() ~= self) then
    					print("WARNING: sibling " .. sibling:name() .. " from " .. object:name() .. " is in different layout!")
    				end
    				sibling:ss(object:getState())
    			end
    		end
    	end
		
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnShow = Layout.onShow
	function Layout:onShow()
		
		if (self:isFullscreen()) then
			-- all layouts can be hidden
			-- note: watch the use of ripairs to iterate the stack in reverse!
			
			-- remove hint dialogs because it's not relevant anymore
			removeHelpDialog()

			for i, l in ripairs(layoutStack) do
				l:hide()
			end
			
		elseif (self:isPOI()) then
			-- show the blackout from what's currently 
			-- the top layout
		
			local topLayout = nil
			for i, l in ipairs(layoutStack) do
				topLayout = l
			end
			if (topLayout) then
				topLayout:setSuspended(true)
				topLayout.mFade:cancelAnimations()
				topLayout.mFade:animate("blackoutFadeIn",
					{ alpha = 0 },
					{ visible = true },
					{ alpha = 0.5, duration = 500 }
				)
			end		
		end

		-- check if user is quick playing this layout/puzzle
		-- call onQuickPlay to allow the layout/puzzle to do
		-- some extra initialization.
		if (self:isQuickPlay()) then
			self:onQuickPlay()
		end
		
		-- reset all button variables
		for button, props in pairs(self.mButtons) do
			button.over = false
			button.pressed = false
			button.enabled = true		
		end
		self:calcButtonVisuals()
		
		-- update layout stack
		table.insert(layoutStack, self)
		
		-- activates the layout
		oldLayoutOnShow(self)			
		
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnActivate = Layout.onActivate
	function Layout:onActivate()

		oldLayoutOnActivate(self)

		-- reset highlight variables
		self.mHighlightedExit = nil

		if (not self:isQuickPlay()) then
			-- dispatch to goalStack		
			goalStack:onLayoutShow(self)
			-- dispatch to fireFlies
			fireFlies:onLayoutShow(self)
		end
		
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnDeactivate = Layout.onDeactivate
	function Layout:onDeactivate()

		-- remove exit highlight
		if (self:isFullscreen()) then
			self:removeExitArrows()
			self:removeExitLabels()
		end
		self.mHighlightedExit = nil

		if (not self:isQuickPlay()) then		
			-- dispatch to goalStack
			goalStack:onLayoutHide(self)
			-- dispatch to fireFlies
			fireFlies:onLayoutHide(self)					
		end

		oldLayoutOnDeactivate(self)

		-- when a layout gets deactived, the C++ function:
		--  * suspends it
		--  * hides it 
		--  * disabled input
		--
		-- reset mFade
		self.mFade:setVisible(false)
		self.mFade:setAlpha(0)		
		
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnHide = Layout.onHide
	function Layout:onHide()

		local tablePosition = nil
		local previousLayout = nil
		for i, l in ipairs(layoutStack) do
			if (l == self) then
				tablePosition = i
				break
			end
			previousLayout = l
		end
		if (previousLayout) then
			-- there exists a previous layout
			-- it's currently blackened out
			-- fade its blackout sprite out
			previousLayout:setSuspended(false)
			previousLayout.mFade:cancelAnimations()
			previousLayout.mFade:animate("blackoutFadeOut",
				{ alpha = 0, duration = 500 },
				{ visible = false }
			)				
		end
		
		-- update layout stack
		if (tablePosition) then
			-- remove this layout from the stack
			table.remove(layoutStack, tablePosition)
		else
			-- error!
			assert(nil, "onHide was called on a Layout that's not in the stack. This shouldn't happen!")
		end
		
		oldLayoutOnHide(self)		
		
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnkeyDown = Layout._onKeyDown
	function Layout:_onKeyDown(key)
	
		handled = false
		
		if (not handled) then
			handled = self:onKeyDown(key)
		end
		
		return handled
	
	end

end
-- ----------------------------------------------------------------------------
function Layout:onKeyDown(key)
	-- no code here
	return false
end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnkeyUp = Layout._onKeyUp
	function Layout:_onKeyUp(key)
	
		handled = false
		
		if (not handled) then
			handled = self:onKeyUp(key)
		end
		
		return handled
	
	end

end
-- ----------------------------------------------------------------------------
function Layout:onKeyUp(key)
	-- no code here
	return false
end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnMouseDown = Layout._onMouseDown
	function Layout:_onMouseDown(x, y)

		assert(type(x) == "number")
		assert(type(y) == "number")
		
		-- remove help dialog on click
		removeHelpDialog()

		-- update gSelection
		-- do this here as well as in onMouseDown
		gSelection = getSelection()
		gSelectionID = getSelectionID()
		
		handled = false
		color = true
		selection = (gSelection ~= nil)

		-- check if we want to close the poi
		if (not handled) then
			if (self:closeOnClick(x, y)) then
				-- log click
				logClick("C_L", "", gSelectionID)			
				self:hide()
				handled = true
				color = false
				
			end
		end
		
		-- update buttons
		if (not handled) then
			for button, props in pairs(self.mButtons) do
				local inside = button:isInsideStrict(x, y)
				local enabled = button.enabled and button:isActive()
				if (inside) then
					if (enabled) then
						handled = true
						color = false
						button.pressed = true					
					end		
				end		
				button.over = inside
			end
			self:calcButtonVisuals()
		end
		
		-- allow layout to overwrite onMouseDown
		if (not handled) then
			local h
			local c
			h, c = self:onMouseDown(x, y)
			
			if (h ~= nil) then 
				handled = h
			end
			if (c ~= nil) then
				color = c
			end		
			
			if (h == nil) then
				print("WARNING: onMouseDown returned nil! Do all paths return a value?")
			end
			
			if (h) then
				-- log click
				logClick("H_MD", "", gSelectionID)			
			end
		end

		-- default behavior
		if (not handled) then
			local object = self:calcObjectBelowMouse(x, y)
			if (object) then
				if (object:visible()) then	
					local h
					local c			
					h, c = self:onClickObject(object, x, y)
					
					if (h ~= nil) then 
						handled = h
					end
					if (c ~= nil) then
						color = c
					end						
					
					if (h == nil) then 
						print("WARNING: onClickObject returned nil! Do all paths return a value?")
					end
				end		
			end
		end
		
		if (not handled and color) then
			cursor:red()
			playAudioTrack("BAD_CLICK_FX")
		end
		if (handled and color) then
			cursor:green()
		end		
		
--		if (not handled) then
--			self:thinkToDo()
--		end

		if (not handled) then
			if (isInsideInventory(x, y)) then
				-- log click
				logClick("H_I", "", gSelectionID)
			elseif (isInsideShoppingList(x, y)) then
				-- log click
				logClick("H_S", "", gSelectionID)			
			elseif (isInsideGui(x, y)) then
				-- log click
				logClick("H_G", "", gSelectionID)
			else
				-- log click
				logClick("F", "", gSelectionID)			
			end
		end
		
		return handled
		
	end

end
-- ----------------------------------------------------------------------------
function Layout:onMouseDown(x, y)
	-- no code here
	return false, true
end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnMouseUp = Layout._onMouseUp
	function Layout:_onMouseUp(x, y)

		assert(type(x) == "number")
		assert(type(y) == "number")

		handled = false
		
		-- always reset buttons
		-- don't check on handled!
		for button, props in pairs(self.mButtons) do
			local acted = false
			local inside = button:isInsideStrict(x, y)
			local enabled = button.enabled and button:isActive()
			local pressed = button.pressed
			if (inside and enabled and pressed) then
				self:onClickObject(button, x, y)
				acted = true
				handled = true
			end
			button.over = (inside and not acted)
			button.pressed = false
		end
		self:calcButtonVisuals()		
		
		if (not handled) then
			handled = self:onMouseUp(x, y)
		end
		
		return handled
		
	end

end
-- ----------------------------------------------------------------------------
function Layout:onMouseUp(x, y)
	-- no code here
	return false
end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnMouseRightDown = Layout._onMouseRightDown
	function Layout:_onMouseRightDown(x, y)
	
		handled = false
		
		if (not handled) then
			handled = self:onMouseRightDown(x, y)
		end
		
		return handled
	
	end

end
-- ----------------------------------------------------------------------------
function Layout:onMouseRightDown(x, y)
	-- no code here
	return false
end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnMouseRightUp = Layout._onMouseRightUp
	function Layout:_onMouseRightUp(x, y)
	
		handled = false
		
		if (not handled) then
			handled = self:onMouseRightUp(x, y)
		end
		
		return handled
	
	end

end
-- ----------------------------------------------------------------------------
function Layout:onMouseRightUp(x, y)
	-- no code here
	return false
end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnMouseMoved = Layout._onMouseMoved
	function Layout:_onMouseMoved(x, y)

		assert(type(x) == "number")
		assert(type(y) == "number")

		handled = false
		
		if (not handled) then
			for button, props in pairs(self.mButtons) do
				button.over = button:isInsideStrict(x, y)
			end
			self:calcButtonVisuals()
		end		
		
		if (not handled) then
			handled = self:onMouseMoved(x, y)
		end
		
		return handled
		
	end

end
-- ----------------------------------------------------------------------------
function Layout:onMouseMoved(x, y)
	-- no code here
	return false
end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnScrollStart = Layout.onScrollStart
	function Layout:onScrollStart()
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnScrollFinish = Layout.onScrollFinish
	function Layout:onScrollFinish()
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnHelpOpened = Layout.onHelpOpened
	function Layout:onHelpOpened()
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnHelpClosed = Layout.onHelpClosed
	function Layout:onHelpClosed()
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnMenuOpened = Layout.onMenuOpened
	function Layout:onMenuOpened()
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnMenuClosed = Layout.onMenuClosed
	function Layout:onMenuClosed()
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnInventoryOpened = Layout.onInventoryOpened
	function Layout:onInventoryOpened()
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnInventoryClosed = Layout.onInventoryClosed
	function Layout:onInventoryClosed()
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnMessageAbort = Layout.onMessageAbort
	function Layout:onMessageAbort(messageId, messageType)
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnMessageStart = Layout.onMessageStart
	function Layout:onMessageStart(messageId, messageType)
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnMessageFinish = Layout.onMessageFinish
	function Layout:onMessageFinish(messageId, messageType)
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnAnimationStart = Layout.onAnimationStart
	function Layout:onAnimationStart(animationName)
	
		oldLayoutOnAnimationStart(self, animationName)
	
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnAnimationFinish = Layout.onAnimationFinish
	function Layout:onAnimationFinish(animationName)
	
		oldLayoutOnAnimationFinish(self, animationName)
	
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnMovieStart = Layout.onMovieStart
	function Layout:onMovieStart(movieName)
		
		-- dispatch to goalStack
		if (not self:isQuickPlay()) then		
			goalStack:onMovieStart(movieName)
			
			-- Make sure ambient sound is turned off during movies
			getAudioManager():fadeType({type=kAmbientType, targetVolume=0.0, duration=500})
		end
		
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnMovieFinish = Layout.onMovieFinish
	function Layout:onMovieFinish(movieName)

		-- dispatch to goalStack
		if (not self:isQuickPlay()) then		
			goalStack:onMovieFinish(movieName)
			getAudioManager():fadeType({type=kAmbientType, targetVolume=1.0, duration=1000})
		end

	end

end
-- ----------------------------------------------------------------------------
do

	-- WARNING:
	-- only the layout in which this object is placed receives this event.
	-- this is not necessarily the top layout!

	local oldLayoutOnObjectStateChange = Layout.onObjectStateChange
	function Layout:onObjectStateChange(object, oldState, newState)

		if (self.mProps) then
			local props = self.mProps[object]
			local statePrev = object:getStatePrev()
			assert(oldState == statePrev)
			if (props ~= nil) then
				if (props.siblings ~= nil) then
					for i, sibling in ipairs(props.siblings) do
						if (sibling:getState() == statePrev) then
							-- the sibling has the same state the object had
							-- mirror that behavior
							sibling:ss(newState)
--							print("auto applied state change to: " .. sibling:name() .. " (" .. oldState .. " -> " .. newState .. ")")					
						else
							-- the sibling does not have the same state the object had
							-- this means the developer explicitly changed that state!
							-- don't mirror behavior
--							print("NOT auto applied state change to: " .. sibling:name() .. " (" .. oldState .. " -> " .. newState .. "), because it's in state: " .. sibling:getState())
						end
					end		
				end
			end
		end
		
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnTick = Layout.onTick
	function Layout:onTick(time)
	
		-- update the cursor each tick
		-- don't bother doing this only in onMouseMoved, since that
		-- leads to inconsistent behavior.
		self:calcCursorProperties()
		
		-- dispatch to goalStack
		if (not self:isQuickPlay()) then
			goalStack:onTick(time)
		end
		
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnStep = Layout.onStep
	function Layout:onStep()

		local step1, step2 = self:calcNextStep()
		
		if (step1) then
			if (type(step1) ~= "string") then			
				self:scrollToObject(step1)
				if (self:isScrolling()) then
					-- wait until scrolling is finished
					return 1
				end
			end			
		end
		
		if (step1 and step2) then
			step2:ss(kSelected)
			step1:getLayout():onClickObject(step1, 0, 0)
			return 1
		
		elseif (step1) then
			if (type(step1) == "string") then
				if (step1 == kClosePoi) then
					self:hide()
					return 1
				end
								
			elseif (step1.type == kObject) then
				step1:getLayout():onClickObject(step1, 0, 0)
				return 1
			
			elseif (step1.type == kLayout) then
				assert(step1 == self)
				self:solve()
				return 1
				
			end
		end
		
		return 0		
		
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnHint = Layout.onHint
	function Layout:onHint()

		local hint1, hint2 = self:calcNextHint()
		
		if (hint1 and hint2) then
			assert(type(hint1) ~= "string")
			assert(type(hint2) ~= "string")
			assert(hint1.type)
			assert(hint2.type)
			--print("(hint) use " .. hint2:name() .. " on " .. hint1:name())
			showLayoutHintUseOnIO(hint2, hint1)
		
		elseif (hint1) then
			if (type(hint1) == "string") then
				if (hint1 == kClosePoi) then
					think("LAYOUTHINT_CLOSEPOI")
				else
					devMessageBox("Unidentified hint string: '"..hint1.."'")
				end
			elseif (hint1.type == kObject) then
				--print("(hint) click: " .. hint1:name())
				showLayoutHintFirefly(hint1)
			
			elseif (hint1.type == kLayout) then
				--print("(hint) solve: " .. hint1:name())
				showLayoutHintLayout(hint1)
				
			else
				devMessageBox("no hint found (but something got returned!")

			end
		else
			devMessageBox("no hint found!")
		end
		
		return 0
		
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnSolve = Layout.onSolve
	function Layout:onSolve()
	
		-- info
		print("solve " .. self:getLayoutID())	
	
		-- dispatch to goalStack
		if (not self:isQuickPlay()) then
			goalStack:onSolve(self)
		end
	
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnSolveStart = Layout.onSolveStart
	function Layout:onSolveStart()

		-- info
		print("solving " .. self:getLayoutID())

		-- disable all buttons
		for button, props in pairs(self.mButtons) do
			button.enabled = false
		end
		self:calcButtonVisuals()
		
		-- dispatch to goalStack
		if (not self:isQuickPlay()) then
			goalStack:onSolveStart(self)
		end
		
	end

end
-- ----------------------------------------------------------------------------
do

	local oldLayoutOnSolveFinish = Layout.onSolveFinish
	function Layout:onSolveFinish()

		-- info
		print("solved " .. self:getLayoutID())

		-- dispatch to goalStack
		if (not self:isQuickPlay()) then		
			goalStack:onSolveFinish(self)
		end
		
	end

end
-- ----------------------------------------------------------------------------
function Layout:calcNextHint()
	local hint1 = nil
	local hint2 = nil
	local r1 = nil
	local r2 = nil
	local path = nil
	r1, r2, path = goalStack:onHint()

	local info = ""
	info = info .. "(hint)"
	if (r1) then
		info = info .. " r1->" .. r1:name()
	end
	if (r2) then
		info = info .. " r2->" .. r2:name()
	end
	print(info)
	if (path) then
		info = info .. " path->"
		for i, node in ipairs(path) do
			if (type(node) == "string") then
				info = info .. node .. ","
			else
				info = info .. node:name() .. ","
			end
		end
	end
	print(info)

	if (r1 and r2) then
		assert(path)	
		assert(r1.__cpp ~= nil)
		assert(r2.__cpp ~= nil)
	
		-- we need to use an item
		local sourceLayout = layoutStack[#layoutStack]
		local targetLayout = r1:getLayout()
		if (sourceLayout == targetLayout) then
			-- the object we need to use on is 
			-- in the current layout
			hint1 = r1
			hint2 = r2
		
		else
			-- the object we need to click is not in the current layout
			assert(#path > 0)
			if (self:isObjectExit(path[1])) then
				local lastObject = path[#path]
				local lastLayout = lastObject:getLayout()
				assert(lastLayout.mProps)
				if (not lastLayout.mProps[lastObject]) then
					-- we want to show a hint to an object in a layout that
					-- possibly hasn't been initialized yet.
					lastLayout:initialize()
				end				
				assert(lastLayout.mProps[lastObject], "ERROR: no props: " .. lastObject:name())
				assert(lastLayout.mProps[lastObject].target, "ERROR: no target: " .. lastObject:name())
				return lastLayout.mProps[lastObject].target
			else
				hint1 = path[1]
			end
		end					
	
	elseif (r1) then
		assert(path)
		assert(r1.__cpp ~= nil)
		
		if (r1.type == kObject) then
			-- we need to click an item
			local sourceLayout = layoutStack[#layoutStack]
			local targetLayout = r1:getLayout()
			if (sourceLayout == targetLayout) then
				-- the object we need to click is in the current layout
				hint1 = r1
			
			else
				-- the object we need to click is not in the current layout
				assert(#path > 0)
				if (self:isObjectExit(path[1])) then
					local lastObject = path[#path]
					local lastLayout = lastObject:getLayout()
					assert(lastLayout.mProps)
					if (not lastLayout.mProps[lastObject]) then
						-- we want to show a hint to an object in a layout that
						-- possibly hasn't been initialized yet.
						lastLayout:initialize()
					end
					assert(lastLayout.mProps[lastObject], "ERROR: no props: " .. lastObject:name())
					assert(lastLayout.mProps[lastObject].target, "ERROR: no target: " .. lastObject:name())
					return lastLayout.mProps[lastObject].target
				else
					hint1 = path[1]
				end
						
			end
		end
		
		if (r1.type == kLayout) then
			-- we need to solve a layout
			-- this is purely implied by it being a layout object
			local sourceLayout = layoutStack[#layoutStack]
			local targetLayout = r1	
		
			if (sourceLayout == targetLayout) then
				-- we're there!
				hint1 = r1
				hint2 = nil
			
			else
				-- we're not there!
				assert(#path > 0)
				hint1 = r1
				hint2 = nil
						
			end		
		end
	end
	
	return hint1, hint2
	
end

-- ----------------------------------------------------------------------------
function Layout:calcNextStep()

	local hint1 = nil
	local hint2 = nil
	local r1 = nil
	local r2 = nil
	local path = nil
	r1, r2, path = goalStack:onStep()
	if (r1 and r2) then
		assert(path)	
		assert(r1.__cpp ~= nil)
		assert(r2.__cpp ~= nil)
	
		-- we need to use an item
		local sourceLayout = layoutStack[#layoutStack]
		local targetLayout = r1:getLayout()
		if (sourceLayout == targetLayout) then
			-- the object we need to use on is 
			-- in the current layout
			hint1 = r1
			hint2 = r2
		
		else
			-- the object we need to click is not in the current layout
			assert(#path > 0)
			hint1 = path[1]
		end					
	
	elseif (r1) then
		assert(path)
		assert(r1.__cpp ~= nil)
		
		if (r1.type == kObject) then
			-- we need to click an item
			local sourceLayout = layoutStack[#layoutStack]
			local targetLayout = r1:getLayout()
			if (sourceLayout == targetLayout) then
				-- the object we need to click is in the current layout
				hint1 = r1
				hint2 = nil
			
			else
				-- the object we need to click is not in the current layout
				assert(#path > 0)
				hint1 = path[1]
				hint2 = nil
						
			end
		end
		
		if (r1.type == kLayout) then
			-- we need to solve a layout
			-- this is purely implied by it being a layout object
			local sourceLayout = layoutStack[#layoutStack]
			local targetLayout = r1	
		
			if (sourceLayout == targetLayout) then
				-- we're there!
				hint1 = r1
				hint2 = nil
			
			else
				-- we're not there!
				assert(#path > 0)
				hint1 = path[1]
				hint2 = nil
						
			end		
		end
	end
	
	return hint1, hint2

end
-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------
-- lua functions
-- ----------------------------------------------------------------------------
-- ----------------------------------------------------------------------------
function Layout:isObjectExit(object)

	if (self.mExits[object] ~= nil) then
		return object, self.mExits[object]
	end
	return false
	
end
-- ----------------------------------------------------------------------------
function Layout:isObjectPOI(object)

	if (self.mPOIs[object] ~= nil) then
		return object, self.mPOIs[object]
	end
	return false

end
-- ----------------------------------------------------------------------------
function Layout:isObjectHO(object)

	if (self.mHOs[object] ~= nil) then
		return object, self.mHOs[object]
	end
	return false

end
-- ----------------------------------------------------------------------------
function Layout:isObjectIO(object)

	if (self.mIOs[object] ~= nil) then
		return object, self.mIOs[object]
	end
	return false

end
-- ----------------------------------------------------------------------------
function Layout:isObjectBlur(object)

	return object:isBlur()

end
-- ----------------------------------------------------------------------------
function Layout:isObjectFirefly(object)

	return object:isFirefly()

end
-- ----------------------------------------------------------------------------
function Layout:isObjectButton(object)

	if (self.mButtons[object] ~= nil) then
		return object, self.mButtons[object]
	end
	return false

end
-- ----------------------------------------------------------------------------
function Layout:onClickObject(object, x, y)

	assert(type(x) == "number")
	assert(type(y) == "number")
	assert(object ~= nil, "ERROR: object is nil in onClickObject")
	assert(self.mProps[object], "ERROR: no properties for: " .. object:name())

	local handled = false
	local color = false
	local props = self.mProps[object]
	
	-- update gSelection
	-- do this here as well as in onMouseDown
	gSelection = getSelection()
	gSelectionID = getSelectionID()
	
	-- info
	if (gSelection) then
		print("(click) " .. object:name() .. " while selecting " .. gSelection:name())
	else
		print("(click) " .. object:name())	
	end
	
	-- the object might be sparling
	-- stop that
	object:sparkleFinish()
	
	-- clicked on an object
	-- dispatch the click to an appropriate handler
	if (object:isActive()) then
		if (self:isObjectExit(object)) then
			-- gc
			collectgarbage("collect")
			
			-- log click
			logClick("H_EX", object:getID(), gSelectionID)
		
			-- CFLEG-160
			-- changing location should remove the currently visible Christine text
			throw("EVENT_MESSAGE_CLEAR")	

			-- handle exits
			local h
			local c 
			local sound
			h, c = self:onClickExit(object, x, y)	
			
			if (h ~= nil) then
				handled = h
			end
			if (c ~= nil) then
				color = c
			end
			
			if (h == nil) then 
				print("WARNING: onClickExit returned nil! Do all paths return a value?")
			end
			if (sound == nil) then
				sound = true
			end
			
			-- dispatch to goalStack
			if (not self:isQuickPlay()) then			
				goalStack:onClickObject(self, object, props, x, y)
				goalStack:onClickExit(self, object, props, x, y)
			end
			
			-- sound
			if (handled and sound) then
				local trackName = "EXIT_CLICK_FX"
				if (props.track) then
					trackName = props.track
				end
				playAudioTrack(trackName)
			end					
			
		elseif (self:isObjectPOI(object)) then
			-- gc
			collectgarbage("collect")		
		
			-- log click
			logClick("H_POI", object:getID(), gSelectionID)
		
			-- CFLEG-160
			-- changing location should remove the currently visible Christine text
			throw("EVENT_MESSAGE_CLEAR")			
		
			-- handle POIs
			local h
			local c 
			local sound			
			h, c, sound = self:onClickPOI(object, x, y)
			
			if (h ~= nil) then
				handled = h
			end
			if (c ~= nil) then
				color = c
			end			
			
			if (handled == nil) then 
				print("WARNING: onClickPOI returned nil! Do all paths return a value?")
			end
			if (sound == nil) then
				sound = true				
			end
		
			-- dispatch to goalStack
			if (not self:isQuickPlay()) then			
				goalStack:onClickObject(self, object, props, x, y)
				goalStack:onClickPOI(self, object, props, x, y)
			end
			
			-- sound
			if (handled and sound) then
				local trackName = "POI_CLICK_FX"
				if (props.track) then
					trackName = props.track
				end
				playAudioTrack(trackName)
			end	
			
		elseif (self:isObjectHO(object)) then
			-- log click
			logClick("H_HO", object:getID(), gSelectionID)
		
			-- handle HOs
			local h
			local c
			local sound
			h, c, sound = self:onClickHO(object, x, y)	
			
			if (h ~= nil) then
				handled = h
			end
			if (c ~= nil) then
				color = c
			end
			
			if (h == nil) then 
				print("WARNING: onClickHO returned nil! Do all paths return a value?")
			end				
			if (c == nil) then
				color = true
			end	
			if (sound == nil) then
				sound = true
			end			
		
			-- dispatch to goalStack
			if (not self:isQuickPlay()) then			
				goalStack:onClickObject(self, object, props, x, y)
				goalStack:onClickHO(self, object, props, x, y)
			end
			
			-- sound
			if (handled and sound) then
				local trackName = "GOOD_CLICK_FX"
				if (props.track) then
					trackName = props.track
				end
				playAudioTrack(trackName)			
			end
			
		elseif (self:isObjectIO(object)) then
			-- log click
			logClick("H_IO", object:getID(), gSelectionID)
		
			-- handle IOs
			local h
			local c		
			local sound	
			h, c, sound = self:onClickIO(object, x, y)
			
			if (h ~= nil) then
				handled = h
			end
			if (c ~= nil) then
				color = c
			end					
			
			if (h == nil) then 
				print("WARNING: onClickIO returned nil! Do all paths return a value?")
			end
			if (c == nil) then
				color = true
			end
			if (sound == nil) then
				sound = true
			end
		
			-- dispatch to goalStack
			if (not self:isQuickPlay()) then			
				goalStack:onClickObject(self, object, props, x, y)
				goalStack:onClickIO(self, object, props, x, y)
			end

			if (not handled) then
				-- developer didn't overwrite the default behavior
				
				if (gSelection) then
					if (object.linked) then
						if (#(object.linked) > 0) then
							-- we have a mouse selection
							local h
							local c		
							local sound						
							h, c, sound = self:_onUseObject(gSelection, object, props)
							
							if (h ~= nil) then
								handled = h
							end
							if (c ~= nil) then
								color = c
							end									
							
							if (h == nil) then
								print("WARNING: _onUseObject returned nil! Do all paths return a value?")
							end
							if (c == nil) then
								color = true
							end
							if (sound == nil) then
								sound = true
							end
							
							-- sound
							if (handled and sound) then
								playAudioTrack("PLACE_OBJECT")
							end							
						end
					end
				end
			end
			
			-- sound
			if (handled and sound) then
				-- no sound here
				-- do we want a default?
				-- more likely we want a dedicated sound in the layout
			end
		elseif (self:isObjectFirefly(object)) then			
			-- log click
			logClick("H_FF", object:getID(), gSelectionID)
		
			-- handle fireflies
			local h
			local c		
			local sound	
			h, c, sound = self:onClickFirefly(object, x, y)			
			
			if (h ~= nil) then
				handled = h
			end
			if (c ~= nil) then
				color = c
			end					
			
			if (h == nil) then 
				print("WARNING: onClickFirefly returned nil! Do all paths return a value?")
			end
			if (c == nil) then
				color = true
			end
			if (sound == nil) then
				sound = true
			end	
			
			if (not self:isQuickPlay()) then			
				-- dispatch to goalStack			
				goalStack:onClickObject(self, object, props, x, y)
				goalStack:onClickFirefly(self, object, props, x, y)
				-- dispatch to fireFlies
				fireFlies:onClickFirefly(self, object, props, x, y)
			end			
			
			-- sound
			if (handled and sound) then
				playAudioTrack("GOOD_CLICK_FX")
			end					
		elseif (self:isObjectButton(object)) then	
			-- log click
			logClick("H_BO", object:getID(), gSelectionID)			
			
			-- handle button
			local h
			local c		
			local sound	
			h, c, sound = self:onClickButton(object)			
			
			if (h ~= nil) then
				handled = h
			end
			if (c ~= nil) then
				color = c
			end					
			
			if (h == nil) then 
				print("WARNING: onClickButton returned nil! Do all paths return a value?")
			end
			if (c == nil) then
				color = true
			end
			if (sound == nil) then
				sound = true
			end				
			
			if (not self:isQuickPlay()) then			
				-- dispatch to goalStack			
				goalStack:onClickObject(self, object, props, x, y)
				goalStack:onClickButton(self, object, props, x, y)
			end			
			
			-- sound
			if (sound) then
				playAudioTrack("BUTTON_CLICK_FX")
			end							
		end
	else
		if (object:isLocked()) then
			-- log click
			logClick("H_LOCK", object:getID(), gSelectionID)
		
			-- handle lock click
			local h
			local c		
			local sound	
			h, c, sound = self:onClickLocked(object, x, y)			
			
			if (h ~= nil) then
				handled = h
			end
			if (c ~= nil) then
				color = c
			end					
			
			if (h == nil) then 
				print("WARNING: onClickLocked returned nil! Do all paths return a value?")
			end
			if (c == nil) then
				color = true
			end
			if (sound == nil) then
				sound = true
			end	
			
			-- sound
			if (handled) then
				playAudioTrack("LOCK_CLICK_FX")
			end						
		end

		-- dispatch to goalStack
		if (not self:isQuickPlay()) then		
			goalStack:onClickObject(self, object, props, x, y)	
		end
	end
	
	return handled, color

end
-- ----------------------------------------------------------------------------
function Layout:onClickPOI(object, x, y)

	assert(type(x) == "number")
	assert(type(y) == "number")
	assert(object ~= nil, "ERROR: object is nil in onClickPOI")
	assert(self.mPOIs[object] ~= nil, "ERROR: value is nil in onClickPOI")
	assert(self.mPOIs[object].target ~= nil, "ERROR: target is nil in onClickPOI")
	
	if (object) then
	
		-- remove exit highlights
		if (self:isFullscreen()) then
			self:removeExitArrows()
			self:removeExitLabels()
		end
		self.mHighlightedExit = nil
	
		-- open POI
		local target = self.mPOIs[object].target
		if (target) then
			target:show()
			return true, false
		end		
	end
	
	return false, false

end
-- ----------------------------------------------------------------------------
function Layout:onClickExit(object, x, y)

	assert(type(x) == "number")
	assert(type(y) == "number")
	assert(object ~= nil, "ERROR: object is nil in onClickExit")
	assert(self.mExits[object] ~= nil, "ERROR: value is nil in onClickExit")
	assert(self.mExits[object].target ~= nil, "ERROR: target is nil in onClickExit")
	
	if (object) then
		local target = self.mExits[object].target
		if (target) then
			target:initialize()
			
			local targetPageH = self.mExits[object].targetPageH
			if (targetPageH == nil) then
				targetPageH = 0
			end
			local tx = -1 * kScreenWidth * targetPageH
			-- compensate for over scrolling!
			if (tx + target:width() < kScreenWidth) then
				tx = -1 * (target:width() - kScreenWidth)
			end
			target:setX(tx)
			
			local targetPageV = self.mExits[object].targetPageV
			if (targetPageV ~= nil) then
				assert("targetPageV is not implemented yet!")
			end		
			
			target:show()
			
			return true, false
		end
	end
	
	return false, false

end
-- ----------------------------------------------------------------------------
function Layout:onClickHO(object, x, y)

	assert(type(x) == "number")
	assert(type(y) == "number")
	assert(object ~= nil, "ERROR: object is nil in onClickHO")
	assert(self.mHOs[object] ~= nil, "ERROR: value is nil in onClickHO")
	
	if (object) then
		print("found object: " .. object:name())
		object:ss(kFound)
		return true, true
	end
	
	return false, true

end
-- ----------------------------------------------------------------------------
function Layout:onClickIO(object, x, y)

	assert(type(x) == "number")
	assert(type(y) == "number")
	assert(object ~= nil, "ERROR: object is nil in onClickIO")
	assert(self.mIOs[object] ~= nil, "ERROR: value is nil in onClickIO")
	
	-- we don't handle clicks on IOs per se
	-- if they have links, they'll be inspected later on
	-- return false here!
	-- if a derived layout returns true, the links will be ignored.
	
	return false, true

end
-- ----------------------------------------------------------------------------
function Layout:onClickFirefly(object, x, y)

	assert(type(x) == "number")
	assert(type(y) == "number")
	assert(object ~= nil, "ERROR: object is nil in onClickFirefly")
	assert(object:isFirefly(), "ERROR: object is not a firefly")
	
	if (object) then
		print("found firefly: " .. object:name())
		return true, true	
	end
	
	return false, true

end
-- ----------------------------------------------------------------------------
function Layout:onClickButton(button)

	return false

end
-- ----------------------------------------------------------------------------
function Layout:onClickLocked(object, x, y)
	
	if (not self:isObjectHO(object)) then
		-- if the object is locked, we show the lock text
		-- don't do this if it's a hidden object
		think(goalStack:calcLockID(object))
	end
	
	return false
	
end
-- ----------------------------------------------------------------------------
gUseObject = nil
gUseTarget = nil
-- ----------------------------------------------------------------------------
function Layout:_onUseObject(selectedObject, targetObject, targetProps)

	assert(selectedObject)
	assert(targetObject)
	assert(targetProps)
	
	gUseObject = nil
	gUseTarget = nil
	
	if (targetObject.linked) then
		-- the object we clicked on has a links entry
		if (#(targetObject.linked) > 0) then
			-- and there are still links left
			local linkPosition = nil
			for i, link in ipairs(targetObject.linked) do
				if (link == selectedObject) then
					linkPosition = i
					break
				end						
			end
			
			if (linkPosition) then
				-- the selected object can be used on the
				-- clicked object!
				assert(selectedObject.timesUsedCount)
				assert(selectedObject.timesLinkedCount)
				assert(type(selectedObject.timesUsedCount) == "number")
				assert(type(selectedObject.timesLinkedCount) == "number")		
				
				-- per default when you successfully use an object
				-- * the used object is removed from the link vector of the target object
				table.remove(targetObject.linked, linkPosition)
				
				-- * the used object increases its used count
				selectedObject.timesUsedCount = selectedObject.timesUsedCount + 1
				
				-- * if the used count is smaller than the linked count, the object
				--   is return to the inventory
				if (selectedObject.timesUsedCount < selectedObject.timesLinkedCount) then
					selectedObject:ss(kFound)
				end
				
				-- * if the used count is equal to the linked count, the object is
				--   set to kDone and removed from the inventory
				if (selectedObject.timesUsedCount >= selectedObject.timesLinkedCount) then
					selectedObject:ss(kUsed)
				end
				
				-- * trigger object used correctly animation
				animObjectUsedCorrectly(selectedObject, targetObject, "_onUseObjectCorrectCallback")
				
				-- * store objects
				gUseObject = selectedObject
				gUseTarget = targetObject
				
				return true	
				
			else
			
				-- * trigger object used incorrectly animation
				animObjectUsedIncorrectly(selectedObject, targetObject, "_onUseObjectIncorrectCallback")
				
			end					
		end
	end
	
	return false

end
-- ----------------------------------------------------------------------------
function Layout:_onUseObjectCorrectCallback()
	assert(gUseObject)
	assert(gUseTarget)
	assert(self.mProps[gUseTarget])
	
	local h
	local c		
	local sound			
	h, c, sound = self:onUseObject(gUseObject, gUseTarget, self.mProps[gUseTarget])	
	
	gUseObject = nil
	gUseTarget = nil
end
-- ----------------------------------------------------------------------------
function Layout:_onUseObjectIncorrectCallback()
end
-- ----------------------------------------------------------------------------
function Layout:onUseObject(selectedObject, targetObject, targetProps)

	-- dispatch to goalStack
	if (not self:isQuickPlay()) then						
		goalStack:onUseObject(selectedObject, targetObject, targetProps)
	end
	
	if (#(targetObject.linked) == 0) then
		-- there are no more links left in the clicked object
		-- trigger the link all					
		self:onUsedAll(targetObject, targetProps)
		
		-- dispatch to goalStack
		if (not self:isQuickPlay()) then							
			goalStack:onUsedAll(targetObject, targetProps)
		end
	end

end
-- ----------------------------------------------------------------------------
function Layout:onUsedAll(object, props)

	assert(object)
	assert(object.type)
	assert(object.type == kObject)

	if (not object:isDone()) then
		object:ss(kIdle)
	end
	return true

end
-- ----------------------------------------------------------------------------
function Layout:onQuickPlay()
end
-- ----------------------------------------------------------------------------
function Layout:calcObjectBelowMouse(x, y)

	assert(type(x) == "number")
	assert(type(y) == "number")

	-- strict check
	for i, object in ipairs(self.mOrder) do
		if (object:isClickable()) then	
			object.insidePocket = object:isInsidePocket(x, y)
			if (not object.insidePocket) then
				if (object:isInsideStrict(x, y)) then
					assert(self.mProps[object])
					return object, self.mProps[object]
				end
			end
		end
	end

	-- loose check
	for i, object in ipairs(self.mOrder) do
		if (not object.insidePocket) then
			if (object:isClickable()) then	
				if (object:isInsideLoose(x, y)) then
					assert(self.mProps[object])
					return object, self.mProps[object]
				end
			end
		end
	end
	
    return nil

end
-- ----------------------------------------------------------------------------
function Layout:calcCursorProperties()

    local cursorX = cursor:getX()
    local cursorY = cursor:getY()
    local cursorSet = false

	local object, props = self:calcObjectBelowMouse(cursorX, cursorY)
	local insideGui = isInsideGuiElement(cursorX, cursorY)
    
	if (self.mHighlightedExit) then
		local removeHighlight = false
		if (self.mHighlightedExit ~= object) then
			removeHighlight = true
		end
		if (insideGui) then
			removeHighlight = true
		end
		
		if (removeHighlight) then
			self:removeExitArrows()
            self:removeExitLabels()
			self.mHighlightedExit = nil
		end
	end    
    
    if (self:isInputActive()) then
	    if (not insideGui) then
		    if (object and props) then
		    	-- cursor icon
		    	if (cursor:hasSelection()) then
				    if (props.dragcursor ~= nil) then
				        cursor:setCursor(props.dragcursor)
				        cursorSet = true
				    elseif (props.cursors ~= nil) then
				        cursor:setCursor(props.cursors)		    
				        cursorSet = true
				    else
				    	cursor:setCursor(kCursorSelected)
				    	cursorSet = true
				    end
		    	else
				    if (props.cursor ~= nil) then
				        cursor:setCursor(props.cursor)
				        cursorSet = true
				    elseif (props.cursors ~= nil) then
				        cursor:setCursor(props.cursors)
				        cursorSet = true
				    else
				    	cursor:setCursor(kCursorDefault)
				    	cursorSet = true
				    end
				end
				-- offset
				if (cursor:getCursor() == kCursorCombine) then
					cursor:setCursorOffsetX(-38)
					cursor:setCursorOffsetY(-38)
				end				
				-- extra work for exits
				if (self.mHighlightedExit ~= object) then
					if (self:isObjectExit(object)) then
						-- store reference
						self.mHighlightedExit = object
						-- highlight it
						self:showExitArrow(object)
						self:showExitLabel(object)
					end
				end
		    end
		end
	end
	
	if (not cursorSet) then
		if (cursor:hasSelection()) then
			cursor:setCursor(kCursorSelected)
		end
	end

end
-- ----------------------------------------------------------------------------
function Layout:calcButtonVisuals()

	for button, props in pairs(self.mButtons) do
		local frame = 0
		if (not button.enabled or not button:isActive()) then
			frame = 3
		elseif (button.pressed) then
			if (button.over) then
				frame = 2
			else
				frame = 1
			end
		elseif (button.over) then
			frame = 1
		end
		
		button:setFrame(frame)
	end

end
-- ----------------------------------------------------------------------------
function Layout:closeOnClick(x, y) 

	if (self:isPOI()) then
		if (not self:isInside(x, y)) then	
			return true
		end
	end
	
	return false

end
-- ----------------------------------------------------------------------------
function Layout:shouldShowExitArrows()

    return false

end
-- ----------------------------------------------------------------------------
function Layout:shouldPlaceFireflies()

    return self:isFullscreen()

end
-- ----------------------------------------------------------------------------
function Layout:thinkToDo()

	local nothingToDo = false

	if self:isSolvedOrSolving() then
		nothingToDo = true
	end
	
	local hasActiveHO = false
	local hasActiveIO = false
	for object, props in pairs(self.mHOs) do
	  if object:isActive() then
	    hasActiveHO = true
	    break
	  end
	end
	
	for object, props in pairs(self.mIOs) do
	  if object:isActive() then
	    hasActiveIO = true
	    break
	  end
	end		
	
	if not hasActiveHO and not hasActiveIO then
		nothingToDo = true
	end
	
	if nothingToDo then
		local r1
		local r2
		local r3
		r1, r2, r3 = goalStack:calcStep(self)
		if r1 then
			nothingToDo = false
		end
	end
	
	if nothingToDo then
		for object, props in pairs(self.mPOIs) do
			r1, r2, r3 = goalStack:calcStep(props.target)
			if r1 then
				nothingToDo = false
				break
			end
		end
	end
	
	if nothingToDo then
		if self:isPuzzling() then
			nothingToDo = false
		end
	end

	if nothingToDo then
		think("MESSAGE_NOTHINGTODO")
	end

end
