local prefabs=
{
	"tornado",
}

local function CheckForNewLeader(inst)
    if inst.components.follower ~= nil and inst.components.follower.leader == nil then
        inst.userfunctions.FollowLeader(inst)
        if inst.components.follower.leader == nil then
            --Didn't find a leader yet
            return
        end
    end
    if inst.sg.statemem.checkleadertask ~= nil then
        inst.sg.statemem.checkleadertask:Cancel()
        inst.sg.statemem.checkleadertask = nil
    end
end

local function StartFlap(inst)
    inst:EnableFlap(true)
end

local function StopFlap(inst)
    inst:EnableFlap(false)
end

--Stategraphs are used to present feedback to the player based on the state of the creature.  Here we setup two states,
--one to handle when the creature is idle and one to handle when the creature is running.
local states=
{

	State{
        name = "death",
        tags = { "busy" },

        onenter = function(inst, playanim)
			StopFlap(inst)
            inst.SoundEmitter:PlaySound("hooh/hooh/death") 
            inst.AnimState:PlayAnimation("death")
            inst.Physics:Stop()
            RemovePhysicsColliders(inst)
            if inst.components.lootdropper ~= nil then
                inst.components.lootdropper:DropLoot(inst:GetPosition())
            end
        end,
    },
	--This handles the idle state.
    State{

        name = "idle",

        --Tags are how we can classify states.  The 'canrotate' tag tells the animation system that these animations can
		--be flipped based on which way the creature is facing which means we don't have to create multiple animations.
        tags = {"idle", "canrotate"},

        --Here is how we define what happens when we enter this state.
        onenter = function(inst, playanim)
			StartFlap(inst)
        	--In this case, all we want to do is play a looping version of the idle animation.
            inst.AnimState:PlayAnimation("frontfly", true)
            CheckForNewLeader(inst)
            if inst.components.follower ~= nil and inst.components.follower.leader == nil then
                inst.sg.statemem.checkleadertask = inst:DoPeriodicTask(1, CheckForNewLeader)
            end
        end,
		
		onexit = function(inst)
            if inst.sg.statemem.checkleadertask ~= nil then
                inst.sg.statemem.checkleadertask:Cancel()
                inst.sg.statemem.checkleadertask = nil
            end
		end
    },

	--This handles the running state.
    State{

        name = "run",

        --Our running animation is also safe to be rotated.
        tags = {"run", "canrotate", "moving" },

        onenter = function(inst, playanim)
			StartFlap(inst)
        	--When entering this state, we now play a looping run animation.
            inst.AnimState:PlayAnimation("frontfly", true)

    		--Tell the locomotor that it's ok to start running.
    		inst.components.locomotor:RunForward()            
        end,
    },    

    --This handles the yell state.
    State{

        name = "yell",

        --Our new state along with our run state are tagged as 'moving' so that we can check for either one when we
        --receive a 'locomote' event from our 'locomotor' component.
        tags = {"yell", "canrotate", "moving"},

        onenter = function(inst, playanim)

            --When we first enter this state, we want our creature to yell.  The name of the sound is a combination of the fmod project, 
            --the folder within the fmod project and the name of the sound event.
            inst.SoundEmitter:PlaySound("hooh/hooh/taunt")            

            --We also want it to play our new fancy yell animation.
            inst.AnimState:PlayAnimation("taunt")
        end,

        --The events section allows us to handle events specific to the current state we are in.
        --In this case we are going to switch to the run state as soon as we receive the 'animover'
        --event which tells us that our yell animation is done.
        events=
        {
            EventHandler("animover", 
                function (inst, data)

                    --Time to start running.
                    inst.sg:GoToState("run")
                end
            ),
        }        
    },    
	
    State{
        name = "hit",
        tags = { "busy" },
        
        onenter = function(inst)
            inst.AnimState:PlayAnimation("hit")
			inst.SoundEmitter:PlaySound("hooh/hooh/hurt") 
            inst.Physics:Stop()            
        end,

        events =
        {
            EventHandler("animover", function(inst)
                inst.sg:GoToState("idle")
            end),
        },
    },
	
	State{
        name = "attack",
        tags = { "attack", "busy" },

        onenter = function(inst, cb)
			StartFlap(inst)
            inst.Physics:Stop()
            inst.components.combat:StartAttack()
            inst.AnimState:PlayAnimation("attack")
        end,

        timeline =
        {
            TimeEvent(10 * FRAMES, function(inst)
                inst.SoundEmitter:PlaySound("hooh/hooh/hurt")
            end),
            TimeEvent(15 * FRAMES, function(inst)
                inst.components.combat:DoAttack()
            end),
        },

        events =
        {
            EventHandler("animover", function(inst)
                inst.sg:GoToState("idle")
            end),
        },
    },
	
	State{
        name = "sleep",
        tags = { "busy", "sleeping", "nowake", "caninterrupt" },

        onenter = function(inst)
            inst.components.locomotor:StopMoving()
            inst.AnimState:PushAnimation("sleep_pre", false)
        end,

        timeline =
        {
            TimeEvent(14*FRAMES, function(inst) StopFlap(inst) end),

            TimeEvent(202*FRAMES, function(inst)
                inst.sg:RemoveStateTag("caninterrupt")
            end),
        },

        events =
        {
            EventHandler("animqueueover", function(inst)
                if inst.AnimState:AnimDone() then
                    inst.sg.statemem.continuesleeping = true
                    inst.sg:GoToState(inst.sg.mem.sleeping and "sleeping" or "wake")
                end
            end),
        },

        onexit = function(inst)
            if not inst.sg.statemem.continuesleeping then
                --V2C: interrupted? bad! restore sound tho
                StartFlap(inst)
                if inst.components.sleeper ~= nil and inst.components.sleeper:IsAsleep() then
                    inst.components.sleeper:WakeUp()
                end
            end
        end,
    },

    State{
        name = "sleeping",
        tags = { "busy", "sleeping" },

        onenter = function(inst)
            inst.AnimState:PlayAnimation("sleep")
        end,

        events =
        {
            EventHandler("animover", function(inst)
                if inst.AnimState:AnimDone() then
                    inst.sg.statemem.continuesleeping = true
                    inst.sg:GoToState("sleeping")
                end
            end),
        },

        onexit = function(inst)
            if not inst.sg.statemem.continuesleeping then
                --V2C: interrupted? bad! restore sound tho
                StartFlap(inst)
                if inst.components.sleeper ~= nil and inst.components.sleeper:IsAsleep() then
                    inst.components.sleeper:WakeUp()
                end
            end
        end,
    },

    State{
        name = "wake",
        tags = { "busy", "waking", "nosleep" },

        onenter = function(inst)
            inst.components.locomotor:StopMoving()
            inst.AnimState:PlayAnimation("sleep_pst")
            StartFlap(inst)
            if inst.components.sleeper ~= nil and inst.components.sleeper:IsAsleep() then
                inst.components.sleeper:WakeUp()
            end
        end,

        timeline =
        {
            CommonHandlers.OnNoSleepTimeEvent(26 * FRAMES, function(inst)
                inst.sg:RemoveStateTag("busy")
                inst.sg:RemoveStateTag("nosleep")
            end),
        },

        events =
        {
            CommonHandlers.OnNoSleepAnimOver("idle"),
        },

        onexit = function(inst)
            --V2C: in case we got interrupted
            if not inst.SoundEmitter:PlayingSound("flying") then
                inst.SoundEmitter:PlaySound("hooh/hooh/wings", "flying")
            end
        end,
    },

}

--Event handlers are how stategraphs get told what happening with the prefab.  The stategraph then decides how it wants
--to present that to the user which usually involves some combination of animation and audio.
local event_handlers=
{
	CommonHandlers.OnSleepEx(),
    CommonHandlers.OnWakeEx(),
    CommonHandlers.OnFreeze(),
--The locomotor sends events to the state graph called 'locomote'.  Here we setup how we're going to handle the event.
    EventHandler("locomote", 
        function(inst) 
			if not inst.sg:HasStateTag("busy") then
				--First we check to see if the locomotor is trying to move our creature.
				if inst.components.locomotor:WantsToMoveForward() then

					--Next we check to see if we're not already in a moving state.
					if not inst.sg:HasStateTag("moving") then

						--Instead of going straight to the run state, let's jump to the yell state first.
						inst.sg:GoToState("yell")
					end

			   --If we're not trying to move forward, then all we want to do is stand still.
				else

					--So if we're not already standing still.
					if not inst.sg:HasStateTag("idle") then
						
						--Let's start standing still.
						inst.sg:GoToState("idle")
					end
				end
            end
        end),
		
    EventHandler("attacked", function(inst)
        if not inst.components.health:IsDead() and not inst.sg:HasStateTag("busy") then
            inst.sg:GoToState("hit")
        end
    end),
	
    EventHandler("death", function(inst)
        inst.sg:GoToState("death")
    end),
	
	EventHandler("doattack", function(inst)
        if not (inst.sg:HasStateTag("busy") or inst.components.health:IsDead()) then
            inst.sg:GoToState("attack")
        end
    end),
}
CommonStates.AddFrozenStates(states, StopFlap, StartFlap)
local function CleanupIfSleepInterrupted(inst)
    if not inst.sg.statemem.continuesleeping then
        StartFlap(inst)
    end
end

--Register our new stategraph and set the default state to 'idle'.
return StateGraph("hooh", states, event_handlers, "idle", {})