require "prefabutil"
--local brain = require "brains/chesterbrain"

local WAKE_TO_FOLLOW_DISTANCE = 4
local SLEEP_NEAR_LEADER_DISTANCE = 6
local IsDLC2 = IsDLCEnabled(CAPY_DLC)

local assets =
{
    Asset("ANIM", "anim/ui_chester_shadow_3x4.zip"),
    Asset("ANIM", "anim/ui_chest_3x3.zip"),

    Asset("ANIM", "anim/chester.zip"),
    Asset("ANIM", "anim/licking_build.zip"),
    Asset("ANIM", "anim/licking_shadow_build.zip"),
    Asset("ANIM", "anim/licking_snow_build.zip"),
--======================	
	Asset( "ATLAS", "images/inventoryimages/personal_licking.xml"),
	Asset( "IMAGE", "images/inventoryimages/personal_licking.tex" ),	
--======================
    Asset("SOUND", "sound/chester.fsb"),
}

local prefabs =
{
    "personal_licking_eyebone",
    --"chesterlight",
    --"chester_transform_fx",
}

local sounds =
{
    hurt = "dontstarve/creatures/chester/hurt",
    pant = "dontstarve/creatures/chester/pant",
    death = "dontstarve/creatures/chester/death",
    open = "dontstarve/creatures/chester/open",
    close = "dontstarve/creatures/chester/close",
    pop = "dontstarve/creatures/chester/pop",
    boing = "dontstarve/creatures/chester/boing",
    lick = "dontstarve/creatures/chester/lick",
}


local function ShouldWakeUp(inst)
    return DefaultWakeTest(inst) or not inst.components.follower:IsNearLeader(WAKE_TO_FOLLOW_DISTANCE)
end

local function ShouldSleep(inst)
    --print(inst, "ShouldSleep", DefaultSleepTest(inst), not inst.sg:HasStateTag("open"), inst.components.follower:IsNearLeader(SLEEP_NEAR_LEADER_DISTANCE))
    return DefaultSleepTest(inst) and not inst.sg:HasStateTag("open") and inst.components.follower:IsNearLeader(SLEEP_NEAR_LEADER_DISTANCE) and GetClock():GetMoonPhase()~='full'
end


local function ShouldKeepTarget()
    return false -- licking can't attack, and won't sleep if he has a target
end

local function OnOpen(inst)
    if not inst.components.health:IsDead() then
        inst.sg:GoToState("open")
    end
end

local function OnClose(inst)
    if not inst.components.health:IsDead() and inst.sg.currentstate.name ~= "transition" then
        inst.sg:GoToState("close")
    end
end

-- eye bone was killed/destroyed
local function OnStopFollowing(inst)
    --print("licking - OnStopFollowing")
    inst:RemoveTag("companion")
end

local function OnStartFollowing(inst)
    --print("licking - OnStartFollowing")
    inst:AddTag("companion")
end

local function MorphShadowlicking(inst)
    inst.AnimState:SetBuild("licking_shadow_build")
    inst:AddTag("spoiler")

    inst.components.container:WidgetSetup("shadowchester")

    local leader = inst.components.follower.leader    
    if leader ~= nil then
        inst.components.follower.leader:MorphShadowEyebone()
    end

    inst.lickingState = "SHADOW"
--    inst._isshadowlicking:set(true)
end


local function MorphSnowlicking(inst)
    inst.AnimState:SetBuild("licking_snow_build")
    inst:AddTag("fridge")
--    inst:AddTag("lowcool")

    local leader = inst.components.follower.leader
    if leader ~= nil then
        inst.components.follower.leader:MorphSnowEyebone()
    end

    inst.lickingState = "SNOW"
--    inst._isshadowlicking:set(false)
end

--[[
local function MorphNormallicking(inst)
    inst.AnimState:SetBuild("licking_build")
    inst:RemoveTag("fridge")
    inst:RemoveTag("spoiler")

    inst.components.container:WidgetSetup("chester")

    local leader = inst.components.follower.leader    
    if leader ~= nil then
        inst.components.follower.leader:MorphNormalEyebone()
    end

    inst.lickingState = "NORMAL"
    inst._isshadowlicking:set(false)
end
]]


local function CanMorph(inst)
    if inst.lickingState ~= "NORMAL" or GetClock():GetMoonPhase()~='full' then
        return false, false
    end

    local container = inst.components.container
    if container:IsOpen() then
        return false, false
    end

    local canShadow = true
    local canSnow = true

    for i = 1, container:GetNumSlots() do
        local item = container:GetItemInSlot(i)
        if item == nil then
            return false, false
        end

        canShadow = canShadow and item.prefab == "nightmarefuel"
        canSnow = canSnow and item.prefab == "bluegem"

        if not (canShadow or canSnow) then
            return false, false
        end
    end

    return canShadow, canSnow
end


local function CheckForMorph(inst)
    local canShadow, canSnow = CanMorph(inst)
    if canShadow or canSnow then
        inst.sg:GoToState("transition")
    end
end

local function DoMorph(inst, fn)
    inst.MorphChester = nil
--    inst:StopWatchingWorldState("isfullmoon", CheckForMorph)
    inst:RemoveEventCallback("onclose", CheckForMorph)
    fn(inst) 
end
local function Morphlicking(inst)
    local canShadow, canSnow = CanMorph(inst)
    if not (canShadow or canSnow) then
        return
    end

    local container = inst.components.container
    for i = 1, container:GetNumSlots() do
        container:RemoveItem(container:GetItemInSlot(i)):Remove()
    end

    DoMorph(inst, canShadow and MorphShadowlicking or MorphSnowlicking)
end

local function OnSave(inst, data)
    data.lickingState = inst.lickingState
end

local function OnPreLoad(inst, data)
    if data == nil then
        return
    elseif data.lickingState == "SHADOW" then
        DoMorph(inst, MorphShadowlicking)
    elseif data.lickingState == "SNOW" then
        DoMorph(inst, MorphSnowlicking)
    end
end

--local function OnIsShadowlickingDirty(inst)
--    if inst._isshadowlicking:value() ~= inst._clientshadowmorphed then
--        inst._clientshadowmorphed = inst._isshadowlicking:value()
--        inst.replica.container:WidgetSetup(inst._clientshadowmorphed and "shadowchester" or nil)
--    end
--end

local function create_licking()
    --print("licking - create_licking")

    local inst = CreateEntity()
    
    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddDynamicShadow()
    inst.entity:AddMiniMapEntity()
 --   inst.entity:AddNetwork()
	
	if IsDLC2 then
		inst:AddTag("amphibious")	
		MakeAmphibiousCharacterPhysics(inst, 75, .5)
	else
		MakeCharacterPhysics(inst, 75, .5)
		inst.Physics:SetCollisionGroup(COLLISION.CHARACTERS)
		inst.Physics:ClearCollisionMask()
		inst.Physics:CollidesWith(COLLISION.WORLD)
		inst.Physics:CollidesWith(COLLISION.OBSTACLES)
		inst.Physics:CollidesWith(COLLISION.CHARACTERS)
	end
    inst:AddTag("companion")
    inst:AddTag("character")
    inst:AddTag("scarytoprey")
--    inst:AddTag("chester")	
    inst:AddTag("personal_licking")
    inst:AddTag("notraptrigger")
    inst:AddTag("cattoy")
	
    inst:AddTag("_named")

    inst.MiniMapEntity:SetIcon("personal_licking.tex")
--    inst.MiniMapEntity:SetCanUseCache(false)

    inst.AnimState:SetBank("miho")
    inst.AnimState:SetBuild("licking_build")

    inst.DynamicShadow:SetSize(2, 1.5)

    inst.Transform:SetFourFaced()

 --   inst._isshadowlicking = net_bool(inst.GUID, "_isshadowlicking", "onisshadowlickingdirty")
	
	if TUNING.OPENLI and GetClock():IsNight() then
		local light = inst.entity:AddLight()
		inst:AddComponent("lighttweener")
		inst.components.lighttweener:StartTween(light, 1, 0.5, 0.7, {237/255, 237/255, 209/255}, 0)
		light:Enable(true)
	end

 --   inst.entity:SetPristine()
	
 --   if not TheWorld.ismastersim then
--		inst:DoTaskInTime(0.1, function(inst)
--			inst.replica.container:WidgetSetup(inst._isshadowlicking:value() and "shadowchester" or "chester")
--		end)
 --       inst._clientshadowmorphed = false
 --       inst:ListenForEvent("onisshadowlickingdirty", OnIsShadowlickingDirty)
--        return inst
--    end
	
	-- licking will not be saved normally. He is saved with the player.
--	inst.persists = false

    ------------------------------------------


    --print("   health")
    inst:AddComponent("health")
    inst.components.health:SetMaxHealth(TUNING.CHESTER_HEALTH)
    inst.components.health:StartRegen(TUNING.CHESTER_HEALTH_REGEN_AMOUNT, TUNING.CHESTER_HEALTH_REGEN_PERIOD)
    inst:AddTag("noauradamage")

    --print("   inspectable")
    inst:AddComponent("inspectable")
    inst.components.inspectable:RecordViews()
    --inst.components.inspectable.getstatus = GetStatus
--    inst.components.inspectable.nameoverride = "licking"

    --print("   locomotor")
    inst:AddComponent("locomotor")
    inst.components.locomotor.walkspeed = 14
    inst.components.locomotor.runspeed = 14

    --print("   follower")
    inst:AddComponent("follower")
    inst:ListenForEvent("stopfollowing", OnStopFollowing)
    inst:ListenForEvent("startfollowing", OnStartFollowing)
if IsDLC2 then 
	inst.components.follower:SetFollowExitDestinations({EXIT_DESTINATION.LAND,EXIT_DESTINATION.WATER})
end
    --print("   knownlocations")
    inst:AddComponent("knownlocations")

    --print("   burnable")
    MakeSmallBurnableCharacter(inst, "licking_body")

    --("   container")
    inst:AddComponent("container")
    inst.components.container:WidgetSetup("chester")
    inst.components.container.onopenfn = OnOpen
    inst.components.container.onclosefn = OnClose

    --print("   sleeper")
    inst:AddComponent("sleeper")
    inst.components.sleeper:SetResistance(3)
    inst.components.sleeper.testperiod = GetRandomWithVariance(6, 2)
    inst.components.sleeper:SetSleepTest(ShouldSleep)
    inst.components.sleeper:SetWakeTest(ShouldWakeUp)
	
    inst:AddComponent("named")

--    MakeHauntableDropFirstItem(inst)
--    AddHauntableCustomReaction(inst, function(inst, haunter)
--        if math.random() <= TUNING.HAUNT_CHANCE_ALWAYS then
--            inst.components.hauntable.panic = true
--            inst.components.hauntable.panictimer = TUNING.HAUNT_PANIC_TIME_SMALL
--            inst.components.hauntable.hauntvalue = TUNING.HAUNT_SMALL
--            return true
--        end
--        return false
 --   end, false, false, true)

    local brain = require "brains/lickingbrain"
    inst:SetBrain(brain)
    inst:SetStateGraph("SGchester")
    inst.sg:GoToState("idle")

    inst.lickingState = "NORMAL"
    inst.MorphChester = Morphlicking
    inst.CanMorph = CanMorph	
--    inst:WatchWorldState("isfullmoon", CheckForMorph) 
    inst:ListenForEvent("nighttime", function() CheckForMorph(inst) end, GetWorld())
    inst:ListenForEvent("onclose", CheckForMorph)
	
    inst.sounds = sounds

    inst.OnSave = OnSave
    inst.OnPreLoad = OnPreLoad
			
    return inst
end

return Prefab("common/personal_licking", create_licking, assets, prefabs)
