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.ATTACK, "attack_pre"),
	ActionHandler(ACTIONS.PICKUP, "action"),
	ActionHandler(ACTIONS.DROP, "action"),
	--ActionHandler(ACTIONS.EAT, "action"),
	ActionHandler(ACTIONS.HARVEST, "action"),
	ActionHandler(ACTIONS.FEED, "action"),
	ActionHandler(ACTIONS.PICK, "action"),
	ActionHandler(ACTIONS.COMBINESTACK, "action"),
	ActionHandler(ACTIONS.UNWRAP, "action"),
	--ActionHandler(ACTIONS.CHANGEIN, "attack"),
	ActionHandler(ACTIONS.ACTIVATE, "action"),	
	ActionHandler(ACTIONS.GIVE, "action"),
	ActionHandler(ACTIONS.GIVETOPLAYER, "action"),
	ActionHandler(ACTIONS.GIVEALLTOPLAYER, "action"),
	ActionHandler(ACTIONS.FEED, "action"),
	--ActionHandler(ACTIONS.JUMPIN, "eat"),
	--ActionHandler(ACTIONS.TRAVEL, "eat"),
	ActionHandler(ACTIONS.MIGRATE, "action"),
	
}

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


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 events=
{
    EventHandler("attacked", function(inst) if not inst.components.health:IsDead() and not inst.sg:HasStateTag("attack") and not inst.sg:HasStateTag("nointerrupt") then inst.sg:GoToState("hit") end end),
    EventHandler("death", function(inst) inst.sg:GoToState("death") end),
    EventHandler("doattack", function(inst, data) if not inst.components.health:IsDead() and (inst.sg:HasStateTag("hit") or not inst.sg:HasStateTag("busy")) then inst.sg:GoToState("attack", data.target) end end),
    CommonHandlers.OnSleep(),
    --CommonHandlers.OnLocomote(true,false),
	EventHandler("locomote", function(inst) 
        if not inst.sg:HasStateTag("busy") then
            
            local is_moving = inst.sg:HasStateTag("moving")
            local wants_to_move = inst.components.locomotor:WantsToMoveForward()
			local should_move = inst.components.locomotor:WantsToMoveForward()
            if not inst.sg:HasStateTag("attack") and not (inst.sg:HasStateTag("home") or inst.sg:HasStateTag("sleeping")) and is_moving ~= wants_to_move then
                if wants_to_move then
                    inst.sg:GoToState("run_start")
                else
                    inst.sg:GoToState("run_stop")
                end
            end
			if inst.sg:HasStateTag("home") or inst.sg:HasStateTag("home_waking") then -- wakeup on locomote
            if inst.sleepingbag ~= nil and inst.sg:HasStateTag("sleeping") and inst.sg:HasStateTag("home") then
                inst.sleepingbag.components.sleepingbag:DoWakeUp()
                inst.sleepingbag = nil
				inst:Show()
				--inst.AnimState:PushAnimation("pig_pickup")
				SetSleeperAwakeState(inst)
				--inst.AnimState:PushAnimation("pig_pickup")
				inst.sg:GoToState("taunt")
				
            end end
        end
    end),    
    CommonHandlers.OnFreeze(),
	
	 EventHandler("ms_opengift",
        function(inst)
            if not inst.sg:HasStateTag("busy") then
                inst.sg:GoToState("opengift")
            end
        end),
}


 local states=
{
	
	 State{
        name = "rumble",
        tags = {"idle", "invisible"},
        onenter = function(inst)
            inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_rumble_LP", "tentacle")
            inst.SoundEmitter:SetParameter( "tentacle", "state", 0)
            inst.AnimState:PlayAnimation("ground_pre")
            inst.AnimState:PushAnimation("ground_loop", true)
            inst.sg:SetTimeout(GetRandomWithVariance(10, 5) )
        end,
        ontimeout = function(inst)
            inst.AnimState:PushAnimation("ground_pst", false)
            inst.sg:GoToState("idle")
        end,

        onexit = function(inst)
            inst.SoundEmitter:KillSound("tentacle")
        end,
    },
   
    State{
        name = "idle",
        tags = {"idle", "invisible"},
        onenter = function(inst)
            inst.AnimState:PushAnimation("idle", true)
            --inst.sg:SetTimeout(GetRandomWithVariance(10, 5) )
            inst.SoundEmitter:KillAllSounds()
        end,
                
        ontimeout = function(inst)
			--inst.sg:GoToState("rumble")
        end,
    },


    State{
        name = "run_start",
        tags = {"moving", "canrotate"},

        onenter = function(inst) 
            inst.components.locomotor:RunForward() 
			inst.sg:GoToState("run")
        end,

        events =
        {   
            --EventHandler("animover", function(inst) inst.sg:GoToState("run") end ),        
        },
    },
        
    State{            
        name = "run",
        tags = {"moving", "canrotate"},
        
        onenter = function(inst) 
				inst.components.locomotor:RunForward() 
        end,

        events=
        {   
            EventHandler("animover", function(inst) inst.sg:GoToState("run") end ),        
        },
    },      
    
    State{            
        name = "run_stop",
        tags = {"idle", "canrotate"},
        
        onenter = function(inst) 
        inst.components.locomotor:StopMoving()
		inst.sg:GoToState("idle")
        end,

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

    State{
        name = "special_atk1",
        tags = {"busy"},
        
        onenter = function(inst)
            inst.Physics:Stop()
            inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_rumble_LP", "tentacle")
            inst.SoundEmitter:SetParameter( "tentacle", "state", 0)
            inst.AnimState:PlayAnimation("ground_pre")
            inst.AnimState:PushAnimation("ground_loop", true)
            inst.sg:SetTimeout(2)

        end,
		
		ontimeout = function(inst)
            inst.AnimState:PushAnimation("ground_pst", false)
            inst.sg:GoToState("idle")
        end,

        onexit = function(inst)
            inst.SoundEmitter:KillSound("tentacle")
        end,
    },
	
	State{
        name = "action",
        tags = {"busy"},
        
        onenter = function(inst)
            inst.Physics:Stop()
            inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_rumble_LP", "tentacle")
            inst.SoundEmitter:SetParameter( "tentacle", "state", 0)
            inst.AnimState:PlayAnimation("ground_pre")
            inst.AnimState:PushAnimation("ground_loop", true)
            inst.sg:SetTimeout(1)

        end,
		
		ontimeout = function(inst)
			inst:PerformBufferedAction()
            inst.AnimState:PushAnimation("ground_pst", false)
            inst.sg:GoToState("idle")
        end,

        onexit = function(inst)
            inst.SoundEmitter:KillSound("tentacle")
        end,
    },

    State{
        name = "special_atk2",
        tags = {"busy"},
        onenter = function(inst)
			inst.Physics:Stop()
			inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_rumble_LP", "tentacle")
			inst.SoundEmitter:SetParameter( "tentacle", "state", 0)
            inst:RemoveTag("notarget")
            inst.AnimState:PlayAnimation("breach_pre")
            inst.AnimState:PushAnimation("breach_loop", true)
			inst.sg:SetTimeout(2)
        end,

        ontimeout = function(inst)           
            inst.AnimState:PlayAnimation("breach_pst")
            inst.sg:GoToState("idle")        

        end,
        onexit = function(inst)
            inst.SoundEmitter:KillSound("tentacle")
			inst:AddTag("notarget")
        end,
    },
	
	State{
        name ="attack_pre",
        tags = {"attack", "attacking", "busy"},
        onenter = function(inst)
			inst.Physics:Stop()
            inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_emerge")
            inst.components.combat:StartAttack()
			inst:RemoveTag("notarget")
            inst.AnimState:PlayAnimation("atk_pre")
			if not inst.SoundEmitter:PlayingSound("tentacle") then
				inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_rumble_LP", "tentacle")
			end      
			inst.SoundEmitter:SetParameter( "tentacle", "state", 1)      
        end,
        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("attack") end),
        },
        timeline=
        {
            TimeEvent(20*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_emerge_VO") end),
        }
        
    },
    
    State{ 
        name = "attack",
        tags = {"attack", "attacking", "busy"},
        onenter = function(inst)
			local buffaction = inst:GetBufferedAction()
			local target = buffaction ~= nil and buffaction.target or nil
			inst.components.combat:SetTarget(target)
			if target ~= nil then
            if target:IsValid() then
                inst:FacePoint(target:GetPosition())
                inst.sg.statemem.attacktarget = target
				end
			end
			inst.Physics:Stop()
            inst.AnimState:PlayAnimation("atk_loop")
            inst.AnimState:PushAnimation("atk_idle", false)
        end,
        
        timeline=
        {
            TimeEvent(2*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_attack") end),
			TimeEvent(7*FRAMES, function(inst) inst.components.combat:DoAttack(inst.sg.statemem.target) end),
            TimeEvent(15*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_attack") end),
            TimeEvent(17*FRAMES, function(inst) inst.components.combat:DoAttack(inst.sg.statemem.target) end),
            TimeEvent(18*FRAMES, function(inst) inst.sg:RemoveStateTag("attack") end),
        },
        
        events=
        {
            EventHandler("animqueueover", function(inst) 
                if inst.wants_to_sleep == false then
                    inst.sg:GoToState("attack") 
                else
                    inst.sg:GoToState("attack_post") 
                end
            end),
        },
    },
    
    State{
        name ="attack_post",
		tags = {"busy", "nointerrupt"},
        onenter = function(inst)
            inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_disappear")
            inst.AnimState:PlayAnimation("atk_pst")
			inst.wants_to_sleep = false
        end,
        events=
        {
            EventHandler("animover", function(inst) inst.SoundEmitter:KillAllSounds() inst.sg:GoToState("idle") end),
        },
		
		onexit = function(inst) inst:AddTag("notarget") end,
    },
	
	State{
        name = "hit",
        tags = {"busy", "hit"},
        
        onenter = function(inst)
			inst.Physics:Stop()
			inst:RemoveTag("notarget")
            inst.AnimState:PlayAnimation("hit")
            inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_hurt_VO")
        end,
        
        events=
        {
            EventHandler("animover", function(inst) if inst.wants_to_sleep == false then
			inst.sg:GoToState("attack")
			else
			inst.sg:GoToState("attack_post")
			end 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("ground_pre")
            inst.AnimState:PushAnimation("ground_loop", 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("idle", true)
            end),
        },

        events =
        {
            EventHandler("firedamage", function(inst)
                inst.AnimState:PlayAnimation("ground_pst")
                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 = "death",
        tags = {"busy"},

        onenter = function(inst)
            inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_death_VO")
            inst.AnimState:PlayAnimation("death")
            inst.Physics:Stop()
            RemovePhysicsColliders(inst)
            inst.components.lootdropper:DropLoot(inst:GetPosition())
			inst.components.inventory:DropEverything(true)
			
            if inst.components.playercontroller ~= nil then
                inst.components.playercontroller:RemotePausePrediction()
            end
        end,
		
		timeline = 
		{
		
		},
		
        events =
        {
            EventHandler("animover", function(inst)
				inst.SoundEmitter:PlaySound("dontstarve/tentacle/tentacle_splat")
                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),
        },
    },

	
}
  

CommonStates.AddFrozenStates(states)
    



    
return StateGraph("tentaclep", states, events, "idle", actionhandlers)

