-- ************************************ Level ************************************ --
Level = getClass("Level")

function Level:fireTrigger(trigger, data)
	local handled = false
	if (not handled and self.event) then
		handled = self.event:handleTrigger(trigger, data)
	end
	if (not handled) then
		handled = taskSystem:handleTrigger(trigger, data)
	end
	if (not handled) then
		handled = self:handleTrigger(trigger, data)
	end
end

function Level:onAnimationStarted(anim)
	local musicMoodStart = musicMoodString(anim.musicMoodStart)
	anim.musicMoodEnd_original = self.musicMood
	if (self.setMusicAndMood and musicMoodStart) then
		self:setMusicAndMood({mood=musicMoodStart, quickFade=true})
	end

	if (self.selectedObject) then
		self.wasSelected = self.selectedObject.selected
		self.selectedObject.selected = false
	end
end

function Level:onAnimationEnded(anim)
	local musicMoodEnd = musicMoodString(anim.musicMoodEnd)
	if (not musicMoodEnd) then
		musicMoodEnd = anim.musicMoodEnd_original
	end
	if (self.setMusicAndMood) then
		self:setMusicAndMood({mood=musicMoodEnd, quickFade=true})
	end

	if (self.selectedObject) then
		self.selectedObject.selected = self.wasSelected
	end
end

-- ************************************ Game Level ************************************ --
CareLevel = getClass("CareLevel")

function CareLevel:init(desc)
	miniGameLevels = {}

	CareLevel.superInit(self, desc)

	self:startGame(desc)
end

function CareLevel:onLevelInitialized()
	self:traverse(function(_, node)
		if (node.onLevelInitialized and node ~= self) then
			node:onLevelInitialized()
		end
	end)
    self:onInitialized()
end

function CareLevel:incMiniGameLevel(miniGameId)
	miniGameLevels[miniGameId] = miniGameLevels[miniGameId] or 1
	if (miniGameLevels[miniGameId] < 5) then
		miniGameLevels[miniGameId] = miniGameLevels[miniGameId] + 1
	end
end

function CareLevel:resetMiniGameLevel(miniGameId)
	miniGameLevels[miniGameId] = 1
end

function CareLevel:getMiniGameLevel(miniGameId)
   return miniGameLevels[miniGameId] or 1
end

function CareLevel:createCharacter(desc)
	local classDesc = table.copy(levelDesc.characterTypes.default, true)
	local base = levelDesc.characterTypes[desc.base]
	table.copy_into(classDesc, base, true)
	table.copy_into(classDesc, desc, true)
    if(classDesc.location) then
        print(classDesc.location)
        print("location x:" .. classDesc.location.x)
        print("location y:" .. classDesc.location.y)
        
    end
	return self:add(classDesc)
end

function CareLevel:spawnPatient(meta, playSound)
	-- Build a class to spawn a patient
	-- The properties of the character can be defined in 3 places with increasing priority
	-- * classDesc (defaults)
	-- * levelDesc.patientList (overwrites defaults)
	-- * trigger metaData (overwrites defaults and levelDesc)

	-- Determine room
	local room = nil
	if (isNumber(levelDesc.areaId)) then
		room = self:getRoom(levelDesc.areaId)
	end

	-- Determine entrance
	local entrance = {x = 0, y = 0}
	if (room) then
		entrance = room.entrance
		assert(entrance)
		assert(entrance.x)
		assert(entrance.y)
	end

	-- Build class description
	-- These properties might be overwritten below
	local classDesc = table.copy(levelDesc.characterTypes.default, true)
	classDesc.class = "Patient"
	classDesc.x = entrance.x
	classDesc.y = entrance.y

	-- Get patient info
	-- If the trigger predefines a type, take that one...
	-- ... otherwise choose one at random,
	-- ... otherwise no info
	local patientInfo = meta and meta.patient
	if (isString(patientInfo)) then
		local pi = patientInfo
		patientInfo = levelDesc.patientList[patientInfo]
		if (not patientInfo) then
			print("Error! Patient not found: "..pi)
		end
	end

	if (not isTable(patientInfo) and levelDesc.patientList) then
		patientInfo = randomFromWeightedTable(levelDesc.patientList)
	end

	local patientInfoBase = patientInfo and patientInfo.base

	self.patientNumber = (self.patientNumber or 0) + 1
	if (classDesc.name == nil or classDesc.name == "") then
		classDesc.name = "Patient "..tostring(self.patientNumber)..": "..tostring(patientInfoBase)
	end

	if (patientInfoBase) then
		-- Merge with patient definition
		-- This overwrites default properties
		local baseCharacterValues = levelDesc.characterTypes[patientInfoBase]
		table.copy_into(classDesc, baseCharacterValues, true)
	end

	if (isTable(patientInfo)) then
		-- Merge with explicit patient values
		-- This overwrites default properties
		table.copy_into(classDesc, patientInfo, true)
	end

	if (levelDesc.diseases) then
		-- Random disease
		-- This property might be overwritten below
		classDesc.diseaseDesc = { class="Disease", }
		classDesc.diseaseDesc.steps = randomFromWeightedTable(levelDesc.diseases)
	end

	-- Merge with trigger
	-- This overwrites existing properties
	if (meta) then
		for k, v in pairs(meta) do
			local copy = true
			copy = copy and (k ~= "trigger")
			copy = copy and (k ~= "delay")
			copy = copy and (k ~= "type")
			copy = copy and (k ~= "patient")
			if (copy) then
				if (isTable(v)) then
					classDesc[k] = {}
					classDesc[k] = table.copy_into(classDesc[k], v, true, false, true)
				else
					classDesc[k] = v
				end
			end
		end
	end

	-- Add
	local obj = self:add(classDesc)
	if (obj and level and playSound ~= false) then
		level:playDoorSound(obj)
	end
	return obj
end

function CareLevel:handleTrigger(trigger, meta)
	if (trigger == "spawn") then
		self:spawnPatient(meta, meta.playSound)

	elseif (trigger == "object") then

		if (not meta.name) then
			CareLevel.super.handleTrigger(self, trigger, meta)

		else
			local object = level:getObject(meta.name)
			assert(object, "Trigger object not found: '"..tostring(name).."'")
			if (object and isCallable(object.handleTrigger)) then
				object:handleTrigger(meta.type, meta)
			end
		end
	end
end

function CareLevel:createPreShiftAnimation()
	if (isTable(taskSystem:getAnimationDesc("preShift"))) then
		return taskSystem:createAnimation("preShift")
	end
end

function CareLevel:createPostShiftAnimation()
	local postShiftAnim
	local doShiftFinish = true

	if (self.event) then
		local postShiftFunc = self.event.createPostShiftAnimation
		if (isCallable(postShiftFunc)) then
			postShiftAnim = postShiftFunc(self.event)
		end

		if (level.heartScore >= level.targetScores[player.room][player.shift].target and
			isTable(taskSystem:getAnimationDesc("postShift"))) then
			if (postShiftAnim) then
				postShiftAnim:atEnd({class="CallTask", func=function()
					local anim = taskSystem:createAnimation("postShift")
					anim:atEnd({class="CallTask", func=function() self:onShiftFinish() end})
				end})
				doShiftFinish = false
			else
				postShiftAnim = taskSystem:createAnimation("postShift")
			end
		end
	end

	if (doShiftFinish) then
		if (postShiftAnim) then
			postShiftAnim:atEnd({class="CallTask", func=function() self:onShiftFinish() end})
		else
			self:onShiftFinish()
		end
	end
end

function CareLevel:onCancelChain()
end
