require "prefabutil"

local assets =
{
    Asset("ANIM", "anim/dispenser.zip"),
    Asset("ANIM", "anim/dispenser_meter.zip"),

    Asset("ANIM", "anim/esentry_item.zip"),
}

local prefabs =
{
    "collapse_small",
    "ehealfx",
    "scrap",
}

local fuel =
{
    twigs = 1,
    cutgrass = 1,
    log = 1,
    charcoal = .5,
}
local mineral =
{
    flint = 1,
    rocks = 1,
    nitre = .3,
    marble = .1,
}
local night =
{
    lightbulb = .2,
    wormlight = .1,
    nightmarefuel = .1,
}
local rare =
{
    goldnugget = 1,
    gunpowder = .5,
    gears = .3,
    livinglog = .1,
}

local function onbuilt(inst, builder)
    inst.AnimState:PlayAnimation("place")
    inst.AnimState:PushAnimation("idle", true)
    inst.SoundEmitter:PlaySound("dontstarve/common/lightning_rod_craft")
    inst:DoTaskInTime(.3, function()
	inst.SoundEmitter:PlaySound("dontstarve/common/lightningrod")
    end)
end

local function upgrade(inst)
    if inst.upgradelevel == 30 or inst.upgradelevel == 70 then
	inst.SoundEmitter:PlaySound("dontstarve/characters/wx78/levelup", "sound")
        inst:DoTaskInTime(.75, function()
	    inst.SoundEmitter:KillSound("sound")
        end)
    end
    if inst.upgradelevel >= 30 and inst.upgradelevel < 70 then
	inst:AddTag("lvl2")
	inst:RemoveTag("lvl1")
	inst.components.named:SetName("Dispenser lvl 2")
	inst.AnimState:PlayAnimation("upgrade2")
	inst.AnimState:PushAnimation("idle_2", true)
    end
    if inst.upgradelevel >= 70 then
	inst:AddTag("lvl3")
	inst:RemoveTag("lvl1")
	inst:RemoveTag("lvl2")
	inst.components.named:SetName("Dispenser lvl 3")
	inst.AnimState:PlayAnimation("upgrade3")
	inst.AnimState:PushAnimation("idle_3", true)
	inst.components.sanityaura.aura = TUNING.SANITYAURA_TINY
    end
end

local function setmeterlevl(inst)
    if inst.components.fueled.currentfuel == 0 then
	inst.AnimState:OverrideSymbol("placer", "dispenser_meter", 0)
    elseif inst.components.fueled.currentfuel == 1 then
	inst.AnimState:OverrideSymbol("placer", "dispenser_meter", 25)
    elseif inst.components.fueled.currentfuel == 2 then
	inst.AnimState:OverrideSymbol("placer", "dispenser_meter", 50)
    elseif inst.components.fueled.currentfuel == 3 then
	inst.AnimState:OverrideSymbol("placer", "dispenser_meter", 75)
    elseif inst.components.fueled.currentfuel == 4 then
	inst.AnimState:OverrideSymbol("placer", "dispenser_meter", 100)
    end
end

local function IsScrap(item)
    return item.prefab == "scrap"
end

local function workup(inst, worker)
    local scrapstack = worker.components.inventory:FindItem(IsScrap)
    if scrapstack ~= nil then
	worker.components.inventory:ConsumeByName("scrap", 1)
	inst.upgradelevel = inst.upgradelevel + 1
	if inst.upgradelevel == 30 or inst.upgradelevel == 70 then
	    upgrade(inst)
	end
    end
end

local function onhammered(inst)
    inst.components.lootdropper:DropLoot()
    local fx = SpawnPrefab("collapse_small")
    fx.Transform:SetPosition(inst.Transform:GetWorldPosition())
    inst:Remove()
    inst.healfx:Remove()
end

local function hitanims(inst)
    if inst:HasTag("lvl1") then
	inst.AnimState:PlayAnimation("hit")
    elseif inst:HasTag("lvl2") then
	inst.AnimState:PlayAnimation("hit_2")
    elseif inst:HasTag("lvl3") then
	inst.AnimState:PlayAnimation("hit_3")
    end
end

local function onhit(inst, worker)
    if worker and worker.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS).prefab == "tf2wrench" then
	inst.components.workable:SetWorkLeft(4)
	local scrapstack = worker.components.inventory:FindItem(IsScrap)
	if scrapstack ~= nil and inst.components.fueled.currentfuel ~= inst.components.fueled.maxfuel then
	    worker.components.inventory:ConsumeByName("scrap", 1)
	    if inst.components.fueled.currentfuel < inst.components.fueled.maxfuel then
		inst.SoundEmitter:PlaySound("dontstarve/common/birdcage_craft")
		inst.components.fueled.currentfuel = inst.components.fueled.currentfuel + 1
	    end
	elseif scrapstack ~= nil and inst.components.fueled.currentfuel == inst.components.fueled.maxfuel then
	    if not inst:HasTag("lvl3") then
	        inst.tick = 0
                while inst.tick ~= 5 and not inst:HasTag("lvl3") do
                    workup(inst, worker)
	            inst.tick = inst.tick + 1
                end
	    end
	end
    end
    hitanims(inst)
    setmeterlevl(inst)
end

local function dispensescrap(inst)
    inst.components.lootdropper:SpawnLootPrefab("scrap")
    inst.components.lootdropper:SpawnLootPrefab("scrap")
    if math.random() < .33 then
	inst.components.lootdropper:SpawnLootPrefab("scrap")
    end
end

local function dispensenightitem(inst)
    if inst.components.fueled.currentfuel ~= 0 then
        inst:DoTaskInTime(5, function()
	    inst.SoundEmitter:PlaySound("dontstarve/characters/wx78/levelup")
	    inst.components.fueled.currentfuel = inst.components.fueled.currentfuel - 1
	    onhit(inst)
	    if inst:HasTag("lvl3") then
		dispensescrap(inst)
		local item1 = weighted_random_choice(fuel)
		local item2 = weighted_random_choice(mineral)
		inst.components.lootdropper:SpawnLootPrefab(item1)
		inst.components.lootdropper:SpawnLootPrefab(item1)
		inst.components.lootdropper:SpawnLootPrefab(item2)
		inst.components.lootdropper:SpawnLootPrefab(item2)
		if math.random() < .33 then
		    local nightrare = weighted_random_choice(night)
		    inst.components.lootdropper:SpawnLootPrefab(nightrare)
		    inst.components.lootdropper:SpawnLootPrefab(nightrare)
		    local item3 = weighted_random_choice(rare)
		    inst.components.lootdropper:SpawnLootPrefab(item3)
		end
	    end
	end)
    end
end

local function dispenseduskitem(inst)
    if inst.components.fueled.currentfuel ~= 0 then
        inst:DoTaskInTime(5, function()
	    inst.SoundEmitter:PlaySound("dontstarve/characters/wx78/levelup")
	    inst.components.fueled.currentfuel = inst.components.fueled.currentfuel - 1
	    onhit(inst)
	    local item1 = weighted_random_choice(fuel)
	    local item2 = weighted_random_choice(mineral)
	    if inst:HasTag("lvl2") then
		dispensescrap(inst)
		inst.components.lootdropper:SpawnLootPrefab(item1)
		inst.components.lootdropper:SpawnLootPrefab(item1)
		inst.components.lootdropper:SpawnLootPrefab(item2)
		inst.components.lootdropper:SpawnLootPrefab(item2)
    	    elseif inst:HasTag("lvl3") then
		dispensescrap(inst)
		inst.components.lootdropper:SpawnLootPrefab(item1)
		inst.components.lootdropper:SpawnLootPrefab(item1)
		inst.components.lootdropper:SpawnLootPrefab(item2)
		inst.components.lootdropper:SpawnLootPrefab(item2)
		if math.random() < .33 then
	  	    local item3 = weighted_random_choice(rare)
		    inst.components.lootdropper:SpawnLootPrefab(item3)
		end
	    end
	end)
    end
end

local function dispensedayitem(inst)
    if inst.components.fueled.currentfuel ~= 0 then
        inst:DoTaskInTime(5, function()
	    inst.SoundEmitter:PlaySound("dontstarve/characters/wx78/levelup")
	    inst.components.fueled.currentfuel = inst.components.fueled.currentfuel - 1
	    onhit(inst)
	    local item1 = weighted_random_choice(fuel)
	    local item2 = weighted_random_choice(mineral)
	    dispensescrap(inst)
	    if inst:HasTag("lvl1") then
		inst.components.lootdropper:SpawnLootPrefab(item1)
		inst.components.lootdropper:SpawnLootPrefab(item2)
	    elseif inst:HasTag("lvl2") then
		inst.components.lootdropper:SpawnLootPrefab(item1)
		inst.components.lootdropper:SpawnLootPrefab(item1)
		inst.components.lootdropper:SpawnLootPrefab(item2)
		inst.components.lootdropper:SpawnLootPrefab(item2)
    	    elseif inst:HasTag("lvl3") then
		inst.components.lootdropper:SpawnLootPrefab(item1)
		inst.components.lootdropper:SpawnLootPrefab(item1)
		inst.components.lootdropper:SpawnLootPrefab(item2)
		inst.components.lootdropper:SpawnLootPrefab(item2)
		if math.random() < .33 then
	  	    local item3 = weighted_random_choice(rare)
		    inst.components.lootdropper:SpawnLootPrefab(item3)
		end
	    end
	end)
    end
end

local function onsave(inst, data)
    data.upgradelevel = inst.upgradelevel
end

local function onload(inst, data)
    inst.upgradelevel = data.upgradelevel 
    upgrade(inst)
    setmeterlevl(inst)
end

local function oninit(inst)
    local x,y,z = inst.Transform:GetWorldPosition()
    inst.healfx = SpawnPrefab("ehealfx")
    inst.healfx.Transform:SetPosition(x,1,z)
    inst.healfx:Hide()
end

local function fn(inst, self, range)
    local inst = CreateEntity()
    local trans = inst.entity:AddTransform()
    local anim = inst.entity:AddAnimState()

    inst.entity:AddSoundEmitter()
    inst.entity:AddMiniMapEntity()

    MakeObstaclePhysics(inst, .5)

    inst.MiniMapEntity:SetIcon("dispenser.tex")

    inst:AddTag("structure")
    inst:AddTag("dispenser")
    inst:AddTag("lvl1")

    inst.AnimState:SetBank("dispenser")
    inst.AnimState:SetBuild("dispenser")
    inst.AnimState:PlayAnimation("idle")
    inst.AnimState:OverrideSymbol("placer", "dispenser_meter", 100)

    inst:AddComponent("inspectable")

    inst:AddComponent("lootdropper")

    inst:AddComponent("named")

    inst:AddComponent("engieworkable")
    inst.components.engieworkable:SetWorkAction(ACTIONS.ENGIEWORK)
    inst.components.engieworkable:SetOnWorkCallback(onhit)

    inst:AddComponent("sanityaura")

    inst:AddComponent("fueled")
    inst.components.fueled.fueltype = "PIGTORCH"
    inst.components.fueled:InitializeFuelLevel(4)
    inst.components.fueled.accepting = false

    inst:AddComponent("workable")
    inst.components.workable:SetWorkAction(ACTIONS.HAMMER)
    inst.components.workable:SetWorkLeft(4)
    inst.components.workable:SetMaxWork(4)
    inst.components.workable:SetOnFinishCallback(onhammered)
    inst.components.workable:SetOnWorkCallback(onhit)

    inst.upgradelevel = 0

    inst.OnSave = onsave
    inst.OnLoad = onload
    inst:ListenForEvent( "onbuilt", onbuilt)

    inst:DoTaskInTime(0, oninit)

    inst:DoPeriodicTask(1, function()
	inst.healfx:Hide() 
	FindEntity(inst, TUNING.DISP_RANGE, function(guy)
	    if (guy and guy:HasTag("player")) or (guy and guy.components.follower and guy.components.follower.leader ~= nil and guy.components.follower.leader:HasTag("player")) then
		if guy.components.health and guy.components.health.currenthealth ~= guy.components.health.maxhealth then
		    inst.healfx:Show()
		    if inst:HasTag("lvl1") then
			guy.components.health:DoDelta(1 / TUNING.DISP_HEALING, true, nil, true)
		    elseif inst:HasTag("lvl2") then
			guy.components.health:DoDelta(2 / TUNING.DISP_HEALING, true, nil, true)
		    elseif inst:HasTag("lvl3") then
			guy.components.health:DoDelta(3 / TUNING.DISP_HEALING, true, nil, true)
		    end
		end
	    end
	end)
    end)

    inst:ListenForEvent("dusktime", function() dispenseduskitem(inst) end, GetWorld())
    inst:ListenForEvent("daytime", function() dispensedayitem(inst) end , GetWorld())
    inst:ListenForEvent("nighttime", function() dispensenightitem(inst) end, GetWorld())

    return inst
end

local function healfxfn()
    local inst = CreateEntity()
    local trans = inst.entity:AddTransform()
    local anim = inst.entity:AddAnimState()

    inst.entity:AddPhysics()

    inst:AddTag("NOBLOCK")
    inst:AddTag("NOCLICK")
    inst:AddTag("FX")

    inst.AnimState:SetBank("fireflies")
    inst.AnimState:SetBuild("fireflies")
    inst.AnimState:PlayAnimation("swarm_loop", true)

    inst.persists = false
    inst.AnimState:SetMultColour( 200/255, 50/255, 50/255, 1 )

    return inst
end

return Prefab("common/dispenser", fn, assets, prefabs),
	Prefab("ehealfx", healfxfn, assets),
	MakePlacer("common/dispenser_placer", "esentry_item", "esentry_item", "idle")