require("stategraphs/commonstates")



function TableConcat(t1,t2)
    for i=1,#t2 do
        t1[#t1+1] = t2[i]
    end
    return t1
end

local actionhandlers = 
{
    ActionHandler(ACTIONS.GOHOME, "action"),
	ActionHandler(ACTIONS.ATTACK, "attack"),
	ActionHandler(ACTIONS.PICKUP, "attack"),
	ActionHandler(ACTIONS.DROP, "taunt"),
	ActionHandler(ACTIONS.GIVE, "taunt"),
	ActionHandler(ACTIONS.GIVETOPLAYER, "taunt"),
	ActionHandler(ACTIONS.GIVEALLTOPLAYER, "taunt"),	
	--ActionHandler(ACTIONS.EQUIP, "taunt"),
	--ActionHandler(ACTIONS.LOOKAT, "taunt"),
	ActionHandler(ACTIONS.EAT, "taunt"),
	ActionHandler(ACTIONS.HEAL, "taunt"),
	ActionHandler(ACTIONS.SLEEPIN, "sleep"),
	ActionHandler(ACTIONS.FAN, "wake"),
	--ActionHandler(ACTIONS.PICK, "attack"),
	ActionHandler(ACTIONS.DEPLOY, "special_atk1"),
	ActionHandler(ACTIONS.ACTIVATE, "taunt"),	
	ActionHandler(ACTIONS.MIGRATE, "taunt"),
	ActionHandler(ACTIONS.FEED, "taunt"),
	ActionHandler(ACTIONS.COMBINESTACK, "taunt"),
	ActionHandler(ACTIONS.UNWRAP, "taunt"),
}

local mobCraftActions =
{
ActionHandler(ACTIONS.GOHOME, "gohome"),
	ActionHandler(ACTIONS.FEED, "taunt"),
	ActionHandler(ACTIONS.ATTACK, "attack"),
	ActionHandler(ACTIONS.PICKUP, "attack"),
	ActionHandler(ACTIONS.PICK, "attack"),
	ActionHandler(ACTIONS.DROP, "taunt"),
	ActionHandler(ACTIONS.SLEEPIN, "sleep"),
	ActionHandler(ACTIONS.EAT, "taunt"),
	ActionHandler(ACTIONS.HEAL, "attack"),
	ActionHandler(ACTIONS.FAN, "taunt"),
	ActionHandler(ACTIONS.DIG, "taunt"),
	ActionHandler(ACTIONS.CHOP, "attack"),
	ActionHandler(ACTIONS.MINE, "attack"),
	ActionHandler(ACTIONS.COOK, "taunt"),
	ActionHandler(ACTIONS.FILL, "taunt"),
	ActionHandler(ACTIONS.DRY, "taunt"),
	ActionHandler(ACTIONS.ADDFUEL, "taunt"),
	ActionHandler(ACTIONS.ADDWETFUEL, "taunt"),
	ActionHandler(ACTIONS.LIGHT, "taunt"),
	ActionHandler(ACTIONS.BAIT, "taunt"),
	ActionHandler(ACTIONS.BUILD, "taunt"),
	ActionHandler(ACTIONS.PLANT, "taunt"),
	ActionHandler(ACTIONS.REPAIR, "taunt"),
	ActionHandler(ACTIONS.ACTIVATE, "taunt"),
	ActionHandler(ACTIONS.HARVEST, "taunt"),
	ActionHandler(ACTIONS.STORE, "taunt"),
	ActionHandler(ACTIONS.RUMMAGE, "taunt"),
	ActionHandler(ACTIONS.DEPLOY, "taunt"),
	ActionHandler(ACTIONS.HAMMER, "attack"),
	ActionHandler(ACTIONS.FERTILIZE, "taunt"),
	ActionHandler(ACTIONS.MURDER, "taunt"),
	ActionHandler(ACTIONS.UNLOCK, "taunt"),
	ActionHandler(ACTIONS.TURNOFF, "taunt"),
	ActionHandler(ACTIONS.TURNON, "taunt"),
	ActionHandler(ACTIONS.SEW, "taunt"),
	ActionHandler(ACTIONS.COMBINESTACK, "taunt"),
	ActionHandler(ACTIONS.UPGRADE, "taunt"),
	ActionHandler(ACTIONS.WRITE, "taunt"),
	ActionHandler(ACTIONS.FEEDPLAYER, "taunt"),
	ActionHandler(ACTIONS.TERRAFORM, "taunt"),
	ActionHandler(ACTIONS.NET, "attack"),
	ActionHandler(ACTIONS.CHECKTRAP, "taunt"),
	ActionHandler(ACTIONS.SHAVE, "taunt"),
	ActionHandler(ACTIONS.FISH, "taunt"),
	ActionHandler(ACTIONS.REEL, "taunt"),
	ActionHandler(ACTIONS.CATCH, "taunt"),
	ActionHandler(ACTIONS.TEACH, "taunt"),
	ActionHandler(ACTIONS.MANUALEXTINGUISH, "taunt"),
	ActionHandler(ACTIONS.RESETMINE, "taunt"),
	ActionHandler(ACTIONS.BLINK, "taunt"),
	ActionHandler(ACTIONS.GIVE, "taunt"),
	ActionHandler(ACTIONS.GIVEALLTOPLAYER, "taunt"),
	--ActionHandler(ACTIONS.CHANGEIN, "changeskin"),
	ActionHandler(ACTIONS.SMOTHER, "taunt"),
	ActionHandler(ACTIONS.CASTSPELL, "taunt"),
	ActionHandler(ACTIONS.WRAPBUNDLE, "taunt"),
	ActionHandler(ACTIONS.UNWRAP, "taunt"),
	ActionHandler(ACTIONS.UNLOCK, "taunt"),
	ActionHandler(ACTIONS.USEKLAUSSACKKEY, "taunt"),
}


local extraActions = 
{
	--ActionHandler(ACTIONS.SLEEPIN, "sleep"),
	ActionHandler(ACTIONS.TRAVEL, "taunt"),
	ActionHandler(ACTIONS.LOOKAT, "taunt"),
}

if MOBCRAFT == "Enable" then
	extraActions = mobCraftActions
end

actionhandlers = TableConcat(actionhandlers, extraActions)

--local function MakeBaby(inst)
    --local angle = inst.Transform:GetRotation()/DEGREES
    --local prefab = (inst.components.combat.target and math.random() < .333) and "spider_warrior" or "spider"
    --local spider = inst.components.lootdropper:SpawnLootPrefab(prefab)
   -- local rad = spider.Physics:GetRadius()+inst.Physics:GetRadius()+.25;
    --local pt = Vector3(inst.Transform:GetWorldPosition())
    --if spider then
       -- spider.Transform:SetPosition(pt.x + rad*math.cos(angle), pt.y, pt.z + rad*math.sin(angle))
        --spider.sg:GoToState("taunt")
        --inst.components.leader:AddFollower(spider)
        --if inst.components.combat.target then
            --spider.components.combat:SetTarget(inst.components.combat.target)
        --end
    --end
--end

local events=
{
    EventHandler("attacked", function(inst)
        if not inst.components.health:IsDead() and
            (not inst.sg:HasStateTag("busy") or inst.sg:HasStateTag("sleeping")) and
            (inst.sg.mem.last_hit_time or 0) + inst.hit_recovery < GetTime() then
				inst.sg:GoToState("hit")
        end
    end),
    EventHandler("death", function(inst) inst.sg:GoToState("death") end),
    EventHandler("doattack", function(inst) if not inst.components.health:IsDead() and (inst.sg:HasStateTag("hit") or not inst.sg:HasStateTag("busy")) then inst.sg:GoToState("attack") end end),
    CommonHandlers.OnSleep(),
    CommonHandlers.OnLocomote(false,true),
    CommonHandlers.OnFreeze(),
	EventHandler("ms_opengift",
        function(inst)
            if not inst.sg:HasStateTag("busy") then
                inst.sg:GoToState("opengift")
            end
        end),
}



local states=
{

    State{
        name = "idle",
        tags = {"idle", "canrotate"},
        onenter = function(inst, playanim)
            inst.Physics:Stop()
			inst.AnimState:PlayAnimation("idle", true)
			if math.random() < .2 then
				inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/scream_short")
			end
        end,

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

        onenter = function(inst)
            inst.components.locomotor:Stop()
            inst.components.locomotor:Clear()
            inst:ClearBufferedAction()

            --if IsNearDanger(inst) then
                --inst.sg.statemem.isdanger = true
                --inst.sg:GoToState("idle")
                --if inst.components.talker ~= nil then
                   -- inst.components.talker:Say(GetString(inst, "ANNOUNCE_NODANGERGIFT"))
                --end
                --return
           -- end

            inst.SoundEmitter:PlaySound("dontstarve/common/player_receives_gift")
            --inst.AnimState:PlayAnimation("taunt")
            --inst.AnimState:PushAnimation("taunt", true)
            -- NOTE: the previously used ripping paper anim is called "giift_loop"

            if inst.components.playercontroller ~= nil then
                inst.components.playercontroller:RemotePausePrediction()
                inst.components.playercontroller:EnableMapControls(false)
                inst.components.playercontroller:Enable(false)
            end
            inst.components.inventory:Hide()
            inst:PushEvent("ms_closepopups")
            inst:ShowActions(false)
            inst:ShowGiftItemPopUp(true)

            if inst.components.giftreceiver ~= nil then
                inst.components.giftreceiver:OnStartOpenGift()
            end
        end,

        timeline =
        {
            -- Timing of the gift box opening animation on giftitempopup.lua
            TimeEvent(155 * FRAMES, function(inst)
               -- inst.AnimState:PlayAnimation("gift_open_pre")
                --inst.AnimState:PushAnimation("taunt", true)
            end),
        },

        events =
        {
            EventHandler("firedamage", function(inst)
                --inst.AnimState:PlayAnimation("taunt")
                inst.sg:GoToState("idle", true)
                if inst.components.talker ~= nil then
                    inst.components.talker:Say(GetString(inst, "ANNOUNCE_NODANGERGIFT"))
                end
            end),
            EventHandler("ms_doneopengift", function(inst, data)
                inst.sg:GoToState("idle", true)
            end),
        },

        onexit = function(inst)
            if inst.sg.statemem.isdanger then
                return
            elseif not inst.sg.statemem.isopeningwardrobe then
                if inst.components.playercontroller ~= nil then
                    inst.components.playercontroller:EnableMapControls(true)
                    inst.components.playercontroller:Enable(true)
                end
                inst.components.inventory:Show()
                inst:ShowActions(true)
            end
            inst:ShowGiftItemPopUp(false)
        end,
    },

    State{
        name = "attack",
        tags = {"attack", "nointerrupt"},

        onenter = function(inst, cb)
			local buffaction = inst:GetBufferedAction()
			local target = buffaction ~= nil and buffaction.target or nil
			inst.components.combat:SetTarget(target)
			inst.components.combat:StartAttack()
            inst.Physics:Stop()
            inst.AnimState:PlayAnimation("atk")
			if target ~= nil then
            if target:IsValid() then
                inst:FacePoint(target:GetPosition())
                inst.sg.statemem.attacktarget = target
            end
        end
    end,
     
    onexit = function(inst)
        inst.components.combat:SetTarget(nil)
    end,
       

        timeline=
        {
            TimeEvent(0*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/attack") end),
            TimeEvent(25*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/attack_grunt") end),
            TimeEvent(28*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/swipe") end),
            TimeEvent(28*FRAMES, function(inst) inst:PerformBufferedAction() end),
        },

        events=
        {
            EventHandler("animover", function(inst)inst.sg:GoToState("idle") end),
        },
    },

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

        onenter = function(inst, cb)
            inst.Physics:Stop()
			inst.sg.mem.last_hit_time = GetTime()
            inst.AnimState:PlayAnimation("hit")
            inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/hurt")
        end,

        events=
        {
			EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
        },
    },

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

        onenter = function(inst, cb)
            inst.Physics:Stop()
            inst.AnimState:PlayAnimation("taunt")
            inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/scream")
			inst:PerformBufferedAction()
        end,

        events=
        {
			EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
        },
    },

	State{
		name = "makenest",
        tags = {"busy", "nointerrupt"},

        onenter = function(inst, cb)
            inst.Physics:Stop()
            inst.AnimState:PlayAnimation("cocoon")
            --inst.SoundEmitter:PlaySound("dontstarve/creatures/krampus/taunt")
        end,

		timeline=
        {
            TimeEvent(15*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/scream") end),
        },

        events=
        {
			EventHandler("animover", function(inst)
				inst.Physics:ClearCollisionMask()
				inst:Remove()
				local den = SpawnPrefab("spiderden")
				den.AnimState:PlayAnimation("cocoon_small")
				den.Transform:SetPosition(inst.Transform:GetWorldPosition())
			end),
        },
    },


	State{
		name = "birth",
        tags = {"busy", "nointerrupt"},

        onenter = function(inst, cb)
            inst.AnimState:PlayAnimation("enter")
			inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/emerge_voice")
			inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/emerge_foley")
		end,

		timeline=
        {
        },


        events=
        {
			EventHandler("animover", function(inst)
				inst.sg:GoToState("idle")
			end),
        },
    },

	State{
		name = "special_atk1",
        tags = {"busy", "nointerrupt"},

        onenter = function(inst, cb)
            inst.Physics:Stop()
            inst.components.locomotor:Stop()
			local angle = TheCamera:GetHeadingTarget()*DEGREES -- -22.5*DEGREES
			inst.Transform:SetRotation(angle / DEGREES)
            inst.AnimState:PlayAnimation("poop_pre")

        end,

        timeline=
        {
            TimeEvent(20*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/scream_short") end),
        },

        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("poop_loop") end),
        },
    },

    State{
        name = "poop_loop",
        tags = {"busy", "nointerrupt"},

        onenter = function(inst, cb)
            inst.Physics:Stop()
            inst.components.locomotor:Stop()
            local angle = TheCamera:GetHeadingTarget()*DEGREES -- -22.5*DEGREES
            inst.Transform:SetRotation(angle / DEGREES)
            inst.AnimState:PlayAnimation("poop_loop")

        end,

        timeline=
        {
            TimeEvent(4*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/givebirth_voice") end),

            TimeEvent(8*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/givebirth_foley") end),
			--TimeEvent(10*FRAMES, MakeBaby),
			TimeEvent(10*FRAMES, function(inst) inst:PerformBufferedAction() end),
                TimeEvent(10*FRAMES, function(inst)
                if inst.components.incrementalproducer and inst.specialatk2 == true then
					inst.specialatk2 = false
                    inst.components.incrementalproducer:TryProduce()
                end
				inst:DoTaskInTime(20, function(inst) inst.specialatk2 = true end)
            end),
        },

        events=
        {
            EventHandler("animover", function(inst)
                if inst.components.incrementalproducer and inst.specialatk2 == true then
                    inst.sg:GoToState("poop_loop")
                else
                    inst.sg:GoToState("poop_pst")
                end
            end),
        },
    },

    State{
        name = "poop_pst",
        tags = {"busy", "nointerrupt"},

        onenter = function(inst, cb)
            inst.Physics:Stop()
            inst.components.locomotor:Stop()
            local angle = TheCamera:GetHeadingTarget()*DEGREES -- -22.5*DEGREES
            inst.Transform:SetRotation(angle / DEGREES)
            inst.AnimState:PlayAnimation("poop_pst")

        end,
        events=
        {
			EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
        },
    },

	--State{
		--name = "plant_pre",
        --tags = {"busy", "nointerrupt"},

        --onenter = function(inst, cb)
           -- inst.Physics:Stop()
           -- inst.components.locomotor:Stop()
			--local angle = TheCamera:GetHeadingTarget()*DEGREES -- -22.5*DEGREES
			--inst.Transform:SetRotation(angle / DEGREES)
            --inst.AnimState:PlayAnimation("poop_pre")

       -- end,

        --timeline=
        --{
           -- TimeEvent(20*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/scream_short") end),
        --},

        --events=
        --{
            --EventHandler("animover", function(inst) inst.sg:GoToState("plant_loop") end),
        --},
   -- },

    --State{
        --name = "plant_loop",
        --tags = {"busy", "nointerrupt"},

        --onenter = function(inst, cb)
            --inst.Physics:Stop()
            --inst.components.locomotor:Stop()
            --local angle = TheCamera:GetHeadingTarget()*DEGREES -- -22.5*DEGREES
            --inst.Transform:SetRotation(angle / DEGREES)
            --inst.AnimState:PlayAnimation("poop_loop")

       -- end,

        --timeline=
        --{
            --TimeEvent(4*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/givebirth_voice") end),

            --TimeEvent(8*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/givebirth_foley") end),
            --TimeEvent(10*FRAMES, function(inst) inst:PerformBufferedAction() end),
        --},

        --events=
        --{
            --EventHandler("animover", function(inst)
                --if inst.components.incrementalproducer and inst.components.incrementalproducer:CanProduce() then
                    --inst.sg:GoToState("plant_loop")
                ---else
                    --inst.sg:GoToState("plant_pst")
                --end
           -- end),
       -- },
   -- },

    --State{
       -- name = "plant_pst",
       -- tags = {"busy", "nointerrupt"},

        --onenter = function(inst, cb)
            --inst.Physics:Stop()
            --inst.components.locomotor:Stop()
            --local angle = TheCamera:GetHeadingTarget()*DEGREES -- -22.5*DEGREES
            --inst.Transform:SetRotation(angle / DEGREES)
            --inst.AnimState:PlayAnimation("poop_pst")

        --end,
        --events=
        --{
			--EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
        --},
    --},
	
	State{
        name = "death",
        tags = {"busy"},
        
        onenter = function(inst)
            inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/die")
            inst.AnimState:PlayAnimation("death")
            inst.components.locomotor:StopMoving()
            RemovePhysicsColliders(inst)            
            inst.components.lootdropper:DropLoot(Vector3(inst.Transform:GetWorldPosition()))         
			inst.components.inventory:DropEverything(true)
        end,
		
		 events =
        {
            EventHandler("animover", function(inst)
                if inst.AnimState:AnimDone() then
					if MOBGHOST == "Enable" then
                     inst:PushEvent(inst.ghostenabled and "makeplayerghost" or "playerdied", { skeleton = false })
					else
						TheWorld:PushEvent("ms_playerdespawnanddelete", inst)
					end
                end
            end),
        },
        
    },
	
	State {
        name = "sleep",
        tags = { "sleeping" }, --add tag "busy" if you hate sliding

        onenter = function(inst)
            if inst.components.locomotor ~= nil then
                inst.components.locomotor:StopMoving()
            end
            inst.AnimState:PlayAnimation("sleep_pre")
			inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/fallasleep")
            --if fns ~= nil and fns.onsleep ~= nil then
                --fns.onsleep(inst)
            --end
        end,

        --timeline = timelines ~= nil and timelines.starttimeline or nil,
				
        events =
        {
            EventHandler("animqueueover", function(inst) inst.sg:GoToState("sleeping") end ),
            EventHandler("onwakeup", function(inst) inst.sg:GoToState("wake") end),
        },
    },

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

        --onenter = onentersleeping,
		
		onenter = function(inst)
				inst.components.locomotor:StopMoving()
				local hungerpercent = inst.components.hunger:GetPercent()
				if hungerpercent ~= nil and hungerpercent ~= 0 then -- We don't want players to heal out starvation.
				inst.components.health:DoDelta(15, false)
				end
				--inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/bearger/sleep")
				inst.AnimState:PlayAnimation("sleep_loop")
			end,

        --timeline = timelines ~= nil and timelines.sleeptimeline or nil,
		timeline =
		{
			TimeEvent(30*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/sleeping") end),
		},

        events =
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("sleeping") end ),
			EventHandler("onwakeup", function(inst) inst.sg:GoToState("wake") end),
        },
    },

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

        onenter = function(inst)
            if inst.components.locomotor ~= nil then
                inst.components.locomotor:StopMoving()
            end
			inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/wakeup")
            inst.AnimState:PlayAnimation("sleep_pst")
            if inst.components.sleeper ~= nil and inst.components.sleeper:IsAsleep() then
                inst.components.sleeper:WakeUp()
            end
            --if fns ~= nil and fns.onwake ~= nil then
                --fns.onwake(inst)
            --end
        end,

        --timeline = timelines ~= nil and timelines.waketimeline or nil,
		
		events =
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
        },
    },

}

CommonStates.AddWalkStates(states,
{
	walktimeline = {
		TimeEvent(0*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/walk_spiderqueen") end),
		TimeEvent(7*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/walk_spiderqueen") end),
		TimeEvent(10*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/walk_spiderqueen") end),
		TimeEvent(13*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/walk_spiderqueen") end),
		TimeEvent(17*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/walk_spiderqueen") end),
		TimeEvent(25*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/walk_spiderqueen") end),
		TimeEvent(32*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/walk_spiderqueen") end),
		TimeEvent(38*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spiderqueen/walk_spiderqueen") end),
	},
})

CommonStates.AddFrozenStates(states)

CommonStates.AddSimpleActionState(states,"drop", "taunt", 10*FRAMES, {"busy"})



    
return StateGraph("spider", states, events, "taunt", actionhandlers)

