-- ************************************ Start Story Task ************************************ --
StartStoryTask = deriveLuaClass("StartStoryTask", "LuaTask")
function StartStoryTask:start()
	self.duration = self.duration or storyBarsDuration
	level:startStory()
	-- Let the duration determine the time.
	return self.wait
end

-- ************************************ End Story Task ************************************ --
EndStoryTask = deriveLuaClass("EndStoryTask", "LuaTask")
function EndStoryTask:start()
	self.duration = self.duration or storyBarsDuration
	level:endStory()
	-- Let the duration determine the time.
	return self.wait
end

-- ************************************ Remove Task ************************************ --
RemoveTask = deriveLuaClass("RemoveTask", "LuaTask")
function RemoveTask:start()
	self.actor:removeFromParent()
	return false
end

-- ************************************ Trigger Task ************************************ --
TriggerTask = deriveLuaClass("TriggerTask", "LuaTask")
function TriggerTask:start()
--print("Fired trigger via Task: "..self.trigger)
	level:fireTrigger(self.trigger, self)
	return false
end

-- ************************************ Set Task ************************************ --
SetTask = deriveLuaClass("SetTask", "LuaTask")
function SetTask:start()
	assert(isTable(self.actor), "Must provide an actor")
	for k,v in pairs(self) do
		if (not table.contains({"class", "actor", "__cpp", "values"}, k)) then
			--print(">>>> SetTask: "..tostring(k).." = "..tostring(v).."\n")
			self.actor[k] = v
		end
	end
	if (isString(self.values)) then
		-- Try to parse the string
		local f = loadstring("return "..self.values)
		if (isCallable(f)) then
			local success, r = pcall(f)
			if (success and isTable(r)) then
				self.values = r
			end
		end
	end
	if (isTable(self.values)) then
		for k,v in pairs(self.values) do
			if (not table.contains({"class", "actor", "__cpp"}, k)) then
				--print(">>>> SetTask: "..tostring(k).." = "..tostring(v).."\n")
				self.actor[k] = v
			end
		end
	end
	return false
end

-- ************************************ Call Task ************************************ --
CallTask = deriveLuaClass("CallTask", "LuaTask")
function CallTask:start()
	local object = self.object or self.actor
	local func = self.func
	if (not isCallable(func)) then
		if (isTable(object)) then
			func = object[func]
		end
		if (not isCallable(func)) then
			func = self[func]
			if (not isCallable(func)) then
				func = _G[func]
			end
		end
	end

	self.params = self.params or {}
	assert(isCallable(func), "Uncallable in CallTask: "..tostring(func))
	if (object) then
		func(object, unpack(self.params))
	else
		func(unpack(self.params))
	end
	return false
end

-- ************************************ Play Sample Task ************************************ --
PlaySampleTask = deriveLuaClass("PlaySampleTask", "LuaTask")
function PlaySampleTask:start()
	assert(self.sound, "Need to add sound")
	self.actor:playSample(self)
	return false
end

-- ************************************ Loop Sample Task ************************************ --
LoopSampleTask = deriveLuaClass("LoopSampleTask", "LuaTask")
function LoopSampleTask:start()
	assert(self.sound, "Need to add sound")
	assert(self.loop, "Need to add loop")
	self.actor:loopSample(self)
	return false
end

-- ************************************ Stop Loop Sample Task ************************************ --
StopLoopSampleTask = deriveLuaClass("StopLoopSampleTask", "LuaTask")
function StopLoopSampleTask:start()
	assert(self.sound, "Need to add sound")
	assert(self.loop, "Need to add loop")
	self.actor:stopLoopSample(self)
	return false
end

-- ************************************ Set Position Task ************************************ --
SetPositionTask = deriveLuaClass("SetPositionTask", "LuaTask")
function SetPositionTask:init(desc)
	SetPositionTask.superInit(self, desc)
	self.target = desc.target or desc.pos
end

function SetPositionTask:start()
	self.actor.locationByTarget = self.target
	return false
end

-- ************************************ Play Animation Task ************************************ --
PlayAnimationTask = deriveLuaClass("PlayAnimationTask", "LuaTask")
function PlayAnimationTask:start()
--print("["..tostring(self.actor.name).."] base: "..tostring(self.actor.baseAnimation).." ani: "..tostring(self.animation).." cyc: "..tostring(self.cycles).." fin: "..tostring(self.whenFinished).." time: "..tostring(self.frameTime))
	self.actor:playAnimation(self.animation, self.cycles, self.whenFinished, self.frameTime)

	if (self.loopSound) then
		self.actor:loopSample(self.loopSound, self.loopSoundId, self.volume, self.pan, self.pitch)
	end

	-- Protect against self.wait being nil
	return self.wait or false
end

function PlayAnimationTask:update(time)
	assert(self.wait)
	-- Wait until the actor has finished animating.
	return not self.actor.isCyclingAnimation
end

function PlayAnimationTask:skip()
	self.actor:finishCycleAnimation()
end

function PlayAnimationTask:finish()
	if (self.loopSound) then
		self.actor:stopLoopSample(self.loopSound, self.loopSoundId)
	end
end

-- ************************************ Message Task ************************************ --
MessageTask = deriveLuaClass("MessageTask", "LuaTask")
function MessageTask:init(desc)
	MessageTask.superInit(self, desc)

	self.msgType = self.msgType or "message"
	self.task = self

	if (table.contains({ "ok", "yesno", "choice", "input" }, self.msgType)) then
		self:requireUserInput()
	end

	if (self.keepOpen) then
		self.skippable = true
	end
end

function MessageTask:start()

	if (self.msgType == "ok") then
		self.dlg = self.actor:showOkMessage(self)

	elseif (self.msgType == "yesno") then
		self.dlg = self.actor:showYesNoMessage(self)

	elseif (self.msgType == "choice") then
		self.dlg = self.actor:showChoiceMessage(self)

	elseif (self.msgType == "input") then
		self.dlg = self.actor:showInputMessage(self)

	else
		self.dlg = self.actor:showMessageDialog(self)
	end

	if (self.needsClick) then
		level:showClickToContinue()
	end

	if (self.keepOpen) then
		return true
	end
end

function MessageTask:requireUserInput()
	self.needsUserInput = true
	self.needsClick = false
	self.skippable = false
	self.duration = -1
end

function MessageTask:update(time)
	local durationEnded = MessageTask.super.update(self, time)
	local shouldCloseDialog = durationEnded
	local dialogOpen = self.actor:findMessageDialog(self.dlg or self.textId) ~= nil
	if (self.needsUserInput or self.needsClick) then
		shouldCloseDialog = not dialogOpen
	end

	if (shouldCloseDialog) then
		if (not self.keepOpen) then
			self.actor:hideMessageDialog(self.dlg or self.textId)
		end
		level:hideClickToContinue()
	end

	return not dialogOpen or self.keepOpen
end

function MessageTask:skip()
	if (not self.keepOpen) then
		local dlg = self.actor:findMessageDialog(self.dlg or self.textId)
		if (dlg and dlg.onDebugSkip) then
			dlg:onDebugSkip()
		end
		self.actor:removeMessageDialog(self.dlg or self.textId)
		level:hideClickToContinue()
	end
	return true
end

function MessageTask:click()
	if (self.needsClick) then
		self.actor:hideMessageDialog(self.textId)
		return true
	end
	return false
end

-- ************************************ Remove Message Task ************************************ --
RemoveMessageTask = deriveLuaClass("RemoveMessageTask", "LuaTask")
function RemoveMessageTask:start()
	assert(isString(self.textId), "A RemoveMessageTask needs a text ID to remove that message")
	if (self.actor.hideMessageDialog) then
		self.actor:hideMessageDialog(self.textId)
	end
	return self.wait ~= nil
end

function RemoveMessageTask:update(time)
	if (self.textId == nil) then
		return true -- Guard against infinite loop
	end
	local dlg
	if (self.actor.hideMessageDialog) then
		self.actor:hideMessageDialog(self.textId)
	end
	if (self.actor.findMessageDialog) then
		dlg = self.actor:findMessageDialog(self.textId)
	end
	return dlg == nil
end

function RemoveMessageTask:skip()
	if (self.actor.removeMessageDialog) then
		self.actor:removeMessageDialog(self.textId)
	end
end

-- ************************************ Overhead Task ************************************ --
OverheadTask = deriveLuaClass("OverheadTask", "LuaTask")
function OverheadTask:start()
	if (self.ofStation) then
		self.actor:createStationOverhead(self.doPop ~= false)
	else
		self.section = self.section or "icons"
		self.actor:createOverhead(self.image..":"..self.section)
	end
	return false
end

-- ************************************ Remove Overhead Task ************************************ --
RemoveOverheadTask = deriveLuaClass("RemoveOverheadTask", "LuaTask")
function RemoveOverheadTask:start()
	self.actor:removeOverhead(self.animated ~= false)
	return false
end

-- ************************************ Leave Station Task ************************************ --
LeaveStationTask = deriveLuaClass("LeaveStationTask", "LuaTask")
function LeaveStationTask:start()
	self.actor:setState("walking to station")
	local station = self.station or self.actor.station
	if (station) then
		station:leave(self.actor)
	end
	return false
end

-- ************************************ ToCheckoutDesk Task ************************************ --
LeaveStationToCheckoutDeskTask = deriveLuaClass("LeaveStationToCheckoutDeskTask", "LuaTask")
function LeaveStationToCheckoutDeskTask:start()
	self.actor:setState("walking to checkout")
	local station = self.station or self.actor.station
	if (station) then
		station:leave(self.actor)
	end
	return false
end


-- ************************************ Place Patient Task ************************************ --
PlacePatientTask = deriveLuaClass("PlacePatientTask", "LuaTask")
function PlacePatientTask:start()
	self.target:onObjectDrop(self.actor)
	return false
end

-- ************************************ Fade Screen Task ************************************ --
FadeScreenTask = deriveLuaClass("FadeScreenTask", "LuaTask")
function FadeScreenTask:start()
	self.fadeIn = self.fadeIn or 0
	self.fadeOut = self.fadeOut or 0
	self.fadeDelay = self.fadeDelay or 0
	self.width = self.width or 1024
	self.height = self.height or 768
	self.draw = self.draw or (self.color and "color") or "image"
	self.section = self.section or "objects"
	self.color = self.color or 0

	local anims = {}
	local startAlpha = 1
	if (self.fadeIn > 0) then
		table.insert(anims, {alpha=1, duration=self.fadeIn})
		startAlpha = 0
	end
	if (self.fadeDelay > 0) then
		table.insert(anims, {delay=self.fadeDelay})
	end
	if (self.fadeOut > 0) then
		table.insert(anims, {alpha=0, duration=self.fadeOut})
	end

	local imageName = ""
	if (isString(self.image) and isString(self.section)) then
		imageName = self.image..":"..self.section
	end

	self.cover = level.topLayer:newChild({class="Sprite",
		name="COVER_"..imageName,
		x=self.x, y=self.y, width=self.width, height=self.height,
		alpha=startAlpha,
		image=imageName, color=self.color, draw=self.draw,
	})

	if (self.remove ~= false) then
		table.insert(anims, {remove=true})
	end

	self.cover:animate(anims)

	self.duration = self.fadeIn + self.fadeDelay + self.fadeOut
	return self.wait
end

function FadeScreenTask:skip()
	if (self.remove ~= false) then
		if (isTable(self.cover) and self.cover.remove) then
			self.cover:remove()
		end
	end
end

-- ************************************ Arrow Task ************************************ --
ArrowTask = deriveLuaClass("ArrowTask", "LuaTask")
function ArrowTask:start()
	self.arrow = hintManager:placeArrow({type=self.arrowType, name=self.id, parent=self.actor, x=self.x, y=self.y})
	return self.wait or false
end

-- ************************************ Remove Arrow Task ************************************ --
RemoveArrowTask = deriveLuaClass("RemoveArrowTask", "LuaTask")
function RemoveArrowTask:start()
	hintManager:removeArrows(self.id or "", self.animated ~= false)
end

function RemoveArrowTask:skip()
	if (isTable(self.arrow) and self.arrow.remove) then
		hintManager:removeArrows(self.arrow, false)
	end
end

-- ************************************ Play Music Task ************************************ --
PlayMusicTask = deriveLuaClass("PlayMusicTask", "LuaTask")
function PlayMusicTask:start()
	-- Avalable music: "INTRO" "SELECTION" "GAME" "DELICIOUS"
	-- Avalable music moods: "1" "2" "3" "ANGER" "HAPPINESS" "LOVE" "RELIEF" "SADNESS" "SUSPENSE"
	self.quickFade = (self.quickFade ~= false) -- Guard against nil
	level:setMusicAndMood(
		self.music or level.music,
		self.mood or level.musicMood,
		self.quickFade)
	return false
end

-- ************************************ Fade Music Task ************************************ --
FadeMusicTask = deriveLuaClass("FadeMusicTask", "LuaTask")
function FadeMusicTask:start()
	level:fadeMusic(self.volume, self.duration)
	return self.wait ~= true
end
