AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")

------------------------------//
function ENT:SpawnFunction(ply, tr)
	if (not tr.Hit) then return end
	local SpawnPos = tr.HitPos + tr.HitNormal * 1
	local ent = ents.Create(self.ClassName)
	local angle = ply:GetAimVector():Angle()
	angle = Angle(0, angle.yaw, 0)
	angle:RotateAroundAxis(angle:Up(), 180)
	ent:SetAngles(angle)
	ent:SetPos(SpawnPos)
	ent:Spawn()
	ent:Activate()
	zrmine.f.SetOwnerID(ent, ply)

	return ent
end

function ENT:Initialize()
	self:SetModel(self.Model)
	self:PhysicsInit(SOLID_VPHYSICS)
	self:SetMoveType(MOVETYPE_VPHYSICS)
	self:SetSolid(SOLID_VPHYSICS)
	self:SetUseType(SIMPLE_USE)
	local phys = self:GetPhysicsObject()

	if (phys:IsValid()) then
		phys:Wake()
		phys:EnableMotion(true)
		phys:EnableDrag(true)
		phys:SetDragCoefficient(1)
	end

	self:UseClientSideAnimation()
	self.PhysgunDisabled = false
	self.connected_module = nil
	self:Spawn_OutputGravel()
	self.StoredResource = {}
	self.StoredResource["Coal"] = 0
	self.StoredResource["Iron"] = 0
	self.StoredResource["Bronze"] = 0
	self.StoredResource["Silver"] = 0
	self.StoredResource["Gold"] = 0
end

function ENT:Spawn_OutputGravel()
	self.outputgravel = ents.Create("zrms_gravelanim")
	self.outputgravel:SetAngles(self:GetAngles())
	self.outputgravel:SetPos(self:GetPos() + self:GetForward() * -55)
	self.outputgravel:Spawn()
	self.outputgravel:Activate()
	self.outputgravel:SetParent(self)
	self.outputgravel:SetNoDraw(true)
end

function ENT:Use(activator, caller)
	if IsValid(caller) and caller:IsPlayer() then
		if not zrmine.f.IsOwner(activator, self) then
			zrmine.f.Notify(activator, zrmine.language.Module_DontOwn, 1)

			return
		end

		if (zrmine.f.IsAdmin(activator) == false and self.IsPipeLineEntity) then return end

		if (IsValid(self) and self:GetCurrentState() == "WAITING_FOR_ORDER" and self.connected_module == nil and self:GetHasChild() == false and self:GetBuildMode() == false) then
			self:SetBuildMode(true)
			self.PhysgunDisabled = false
			local phys = self:GetPhysicsObject()

			if (phys:IsValid()) then
				phys:Wake()
				phys:EnableMotion(true)
			end
		end
	end
end

-- Logic
function ENT:Add_Resource(gravel, ply)
	if (IsValid(gravel)) then
		if (self:Return_StoredAmount() >= zrmine.config.Crusher_Capacity) then
			if (IsValid(ply)) then
				zrmine.f.Notify(ply, zrmine.language.Crusher_Full, 1)
			end

			return
		end

		local rType = gravel:GetResourceType()
		self.StoredResource[rType] = self.StoredResource[rType] + gravel:GetResourceAmount()
		gravel:Remove()
	else
		for k, v in pairs(gravel) do
			self.StoredResource[k] = self.StoredResource[k] + v
		end
	end

	zrmine.f.CreateEffectTable(nil, "zrmine_sfx_addgravel", self, self:GetAngles(), self:GetPos())
	self:NET_UpdateResource()
end

function ENT:Add_GravelCrate(crate, ply)
	if (self:Return_StoredAmount() >= zrmine.config.Crusher_Capacity) then return end

	if (IsValid(crate)) then
		local coal = crate:GetcCoal()
		local iron = crate:GetcIron()
		local bronze = crate:GetcBronze()
		local silver = crate:GetcSilver()
		local gold = crate:GetcGold()
		local gTable = {}
		gTable["Coal"] = coal
		gTable["Iron"] = iron
		gTable["Bronze"] = bronze
		gTable["Silver"] = silver
		gTable["Gold"] = gold

		for k, v in pairs(gTable) do
			if (v > 0) then
				local needAmount = zrmine.config.Crusher_Capacity - self:Return_StoredAmount()
				local addAmount = 0

				if (v > needAmount) then
					addAmount = needAmount
				else
					addAmount = v
				end

				if (self:Return_StoredAmount() > zrmine.config.Crusher_Capacity) then
					if (IsValid(ply)) then
						zrmine.f.Notify(ply, zrmine.language.Crusher_Full, 1)
					end

					break
				end

				self.StoredResource[k] = self.StoredResource[k] + addAmount

				if (k == "Coal") then
					crate:Decrease_Resource(addAmount, "Coal")
				elseif (k == "Iron") then
					crate:Decrease_Resource(addAmount, "Iron")
				elseif (k == "Bronze") then
					crate:Decrease_Resource(addAmount, "Bronze")
				elseif (k == "Silver") then
					crate:Decrease_Resource(addAmount, "Silver")
				elseif (k == "Gold") then
					crate:Decrease_Resource(addAmount, "Gold")
				end
			end
		end
	end

	zrmine.f.CreateEffectTable(nil, "zrmine_sfx_addgravel", self, self:GetAngles(), self:GetPos())
	self:NET_UpdateResource()
end

function ENT:Send_Resources(rtype)
if (IsValid(self.connected_module)) then
	local sendTable = {}
	local sendAmount = zrmine.f.Calculate_AmountCap(self.StoredResource[rtype], zrmine.config.Crusher_WorkAmount)
	self.StoredResource[rtype] = self.StoredResource[rtype] - sendAmount
	sendTable[rtype] = sendAmount
	self.connected_module:Receive_Resources(sendTable)
	self:NET_UpdateResource()
	zrmine.f.CreateEffectTable(nil, "zrmine_sfx_crush_expo", self, self:GetAngles(), self:GetPos())
end
end

function ENT:Return_StoredAmount()
	local StoredAmount = 0

	for k, v in pairs(self.StoredResource) do
		if (v > 0) then
			StoredAmount = StoredAmount + v
		end
	end

	return StoredAmount
end

function ENT:NET_UpdateResource()
	self:SetInMachine_Coal(self.StoredResource["Coal"] or 0)
	self:SetInMachine_Iron(self.StoredResource["Iron"] or 0)
	self:SetInMachine_Bronze(self.StoredResource["Bronze"] or 0)
	self:SetInMachine_Silver(self.StoredResource["Silver"] or 0)
	self:SetInMachine_Gold(self.StoredResource["Gold"] or 0)
end

-- This returns the id of a valid resource
function ENT:FindValidResource()
	local validResource = nil

	for k, v in pairs(self.StoredResource) do
		local sendAmount = zrmine.f.Calculate_AmountCap(v, zrmine.config.Crusher_WorkAmount)

		if (sendAmount > 0) then
			validResource = k
			break
		end
	end

	return validResource
end

-- Plays the give gravel anim
function ENT:Play_GravelGive_anim(speed, resettime, rtype)
	zrmine.f.CreateEffectTable("zrms_refiner_refine", nil, self, self:GetAngles(), self:GetPos() + self:GetForward() * -30 + self:GetUp() * 15)
	zrmine.f.CreateAnimTable(self.outputgravel, "output", speed)

	if (rtype == "Iron") then
		self.outputgravel:SetSkin(1)
	elseif (rtype == "Bronze") then
		self.outputgravel:SetSkin(2)
	elseif (rtype == "Silver") then
		self.outputgravel:SetSkin(3)
	elseif (rtype == "Gold") then
		self.outputgravel:SetSkin(4)
	elseif (rtype == "Coal") then
		self.outputgravel:SetSkin(0)
	else
		self.outputgravel:SetSkin(0)
	end

	timer.Simple(0.1, function()
		if (IsValid(self)) then
			self.outputgravel:SetNoDraw(false)
		end
	end)

	timer.Simple(resettime, function()
		if (IsValid(self)) then
			self.outputgravel:SetNoDraw(true)
		end
	end)
end

-- A Helper funcion for placing a module
function ENT:ConnectModule(amodule)
	self.connected_module = amodule
	self.connected_module.connected_Parent = self
	self:SetHasChild(true)
	self:EmitSound("weapons/ar2/ar2_reload_push.wav", 75, 100, 1, CHAN_AUTO)
	amodule:SetPos(self:GetPos() + self:GetForward() * -55)
	amodule:SetAngles(self:GetAngles())
	amodule:SetBuildMode(false)
	self:SetBuildMode(false)
	local rphys = amodule:GetPhysicsObject()

	if (rphys:IsValid()) then
		rphys:Wake()
		rphys:EnableMotion(false)
	end

	local sphys = self:GetPhysicsObject()

	if (sphys:IsValid()) then
		sphys:Wake()
		sphys:EnableMotion(false)
	end

	self.PhysgunDisabled = true
	hook.Run("zrms_Verify_Inserter_connection", self)
end

-- Main function
	function ENT:Think()
		if ((self.lastthink or -1) < CurTime()) then
			self.lastthink = CurTime() + 1
			self:ModuleUpdate()
		end
	end

	function ENT:ModuleUpdate()
		if (self:GetCurrentState() == "WAITING_FOR_ORDER" and self:Return_StoredAmount() > 0) then
			local cm = self.connected_module

			if IsValid(cm) then
				if (string.sub(cm:GetClass(), 1, 17) == "zrms_conveyorbelt" or cm:GetClass() == "zrms_inserter") then
					if (cm:Return_StoredAmount() < cm.HoldAmount) then
						self:Crushing()
					else
						self:CreateAnim_Table("idle", 1)
					end
				elseif (string.sub(cm:GetClass(), 1, 12) == "zrms_refiner") then
					if (cm:Return_StoredAmount() < cm.HoldAmount) then
						self:Crushing()
					else
						self:CreateAnim_Table("idle", 1)
					end
				end
			end
		end
	end

	function ENT:Crushing()
		-- Sets the current state to busy
		self:SetCurrentState("CRUSHING")
		-- Plays the crushing animation
		self:CreateAnim_Table("crushing", 1)
		--Creates the Crush Effect
		zrmine.f.CreateEffectTable("zrms_crusher_crush", "zrmine_sfx_crush", self, self:GetAttachment(self:LookupAttachment("input")).Ang, self:GetAttachment(self:LookupAttachment("input")).Pos)
		-- Returns a valid resource we can send
		local SendResource = self:FindValidResource()

		-- Plays the give gravel animation
		timer.Simple(zrmine.config.Crusher_Time, function()
			if (IsValid(self) and IsValid(self.connected_module)) then
				self:Play_GravelGive_anim(2, 2, SendResource)
			end
		end)

		-- Sends the crushed gravel too the refinery if the refiner is still connected
		timer.Simple(zrmine.config.Crusher_Time + 2, function()
			if (IsValid(self)) then
				if (IsValid(self.connected_module)) then
					self:Send_Resources(SendResource)
					zrmine.f.CreateInsertEffect(self.connected_module, SendResource)

					--Vrondakis
					if (LevelSystemConfiguration or manolis) then
						local ply = zrmine.f.GetOwner(self)

						if IsValid(ply) then
							ply:addXP(zrmine.config.Vrondakis["Crushing"].XP, " ", true)
						end
					end
				end

				if (self:Return_StoredAmount() <= 0) then
					self:CreateAnim_Table("idle", 1)
				end

				zrmine.f.RemoveEffectNamed(self, "zrms_crusher_crush")
				self:SetCurrentState("WAITING_FOR_ORDER")
			end
		end)
	end

	-- Damage Stuff
	function ENT:OnTakeDamage(dmg)
		self:TakePhysicsDamage(dmg)
		local damage = dmg:GetDamage()
		local entHealth = zrmine.config.Damageable["Crusher"].EntityHealth

		if (entHealth > 0) then
			self.CurrentHealth = (self.CurrentHealth or entHealth) - damage

			if (self.CurrentHealth <= 0) then
				self:Destruct()
				self:Remove()
			end
		end
	end

	function ENT:Destruct()
		local vPoint = self:GetPos()
		local effectdata = EffectData()
		effectdata:SetStart(vPoint)
		effectdata:SetOrigin(vPoint)
		effectdata:SetScale(1)
		util.Effect("Explosion", effectdata)
	end

	-- Animation
	function ENT:CreateAnim_Table(anim, speed)
		if (self:LookupSequence(anim) ~= self:GetSequence()) then
			zrmine.f.CreateAnimTable(self, anim, speed)
		end
	end
