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(), -90)
	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)
	self:SetCollisionGroup(COLLISION_GROUP_WEAPON)
	local phys = self:GetPhysicsObject()

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

	self.PhysgunDisabled = false
	self:UseClientSideAnimation()
	self.StoredResource = {}
	self.StoredResource["Coal"] = 0
	self.StoredResource["Iron"] = 0
	self.StoredResource["Bronze"] = 0
	self.StoredResource["Silver"] = 0
	self.StoredResource["Gold"] = 0
	self.connected_module01 = nil
	self.connected_module02 = nil
	self.connected_Parent = nil
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:GetHasChild() == false and self:GetBuildMode() == false) then
			self:EmitSound("zrmine_sfx_placecrate")

			if (self:Return_StoredAmount() > 0) then
				local effectPos = self:GetAttachment(self:LookupAttachment("input")).Pos + self:GetUp() * 5
				local effectAng = self:GetAngles()
				effectAng:RotateAroundAxis(self:GetUp(), -90)
				self:CreateEffect_Table("zrms_refiner_dirt", "zrmine_sfx_refinerdirt", self, effectAng, effectPos)
				self:Clear_Resources()
			end

			self:Detach_Self()
		end
	end
end

-- Logic
-- Here we Receive from our Parent to send resources
function ENT:Receive_Resources(rTable)
	self:CreateEffect_Table(nil, "zrmine_sfx_addgravel", self, self:GetAngles(), self:GetPos())

	for k, v in pairs(rTable) do
		self.StoredResource[k] = self.StoredResource[k] + v
	end

	self:NET_UpdateResource()
end

-- Here we send resources to our Children
function ENT:Send_Resources(rtype)
	local sendTable = {}
	local sendAmount = zrmine.f.Calculate_AmountCap(self.StoredResource[rtype], self.WorkAmount)
	self.StoredResource[rtype] = self.StoredResource[rtype] - sendAmount
	local sendA = 0
	local sendB = 0

	if (sendAmount <= 1) then
		sendA = sendAmount
		sendB = 0
	else
		sendA = sendAmount / 2
		sendB = sendAmount / 2
	end

	if (IsValid(self.connected_module01) and sendA > 0) then
		sendTable[rtype] = sendA
		self.connected_module01:Receive_Resources(sendTable)
		zrmine.f.CreateInsertEffect(self.connected_module01, rtype)
	end

	if (IsValid(self.connected_module02) and sendB > 0) then
		sendTable[rtype] = sendB
		self.connected_module02:Receive_Resources(sendTable)
		zrmine.f.CreateInsertEffect(self.connected_module02, rtype)
	end

	self:NET_UpdateResource()
end

-- Gives us how much resources we have stored
function ENT:Return_StoredAmount()
	local StoredAmount
	StoredAmount = self.StoredResource["Coal"] + self.StoredResource["Iron"] + self.StoredResource["Bronze"]
	StoredAmount = StoredAmount + self.StoredResource["Silver"] + self.StoredResource["Gold"]

	return StoredAmount
end

-- Returns true if we have enough of a resource type in the inv too split it
function ENT:Has_SplittableResource()
	local HasSplittableResource = false

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

	return HasSplittableResource
end

-- Updates our net Resource vars
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

-- Removes all stored Resources
function ENT:Clear_Resources()
	self:CreateEffect_Table(nil, "zrmine_sfx_addgravel", self, self:GetAngles(), self:GetPos())
	self.StoredResource = self.StoredResource or {}
	self.StoredResource["Coal"] = 0
	self.StoredResource["Iron"] = 0
	self.StoredResource["Bronze"] = 0
	self.StoredResource["Silver"] = 0
	self.StoredResource["Gold"] = 0
	self:NET_UpdateResource()
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, self.WorkAmount)

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

	return validResource
end

-- Construction
function ENT:ConnectModule(amodule)
	if (amodule:GetClass() == "zrms_conveyorbelt_c_right" and self.connected_module01 == nil) then
		self:ConnectModule01(amodule)
	elseif (amodule:GetClass() == "zrms_conveyorbelt_c_left" and self.connected_module02 == nil) then
		self:ConnectModule02(amodule)
	elseif (amodule:GetClass() == "zrms_conveyorbelt_n" or amodule:GetClass() == "zrms_conveyorbelt_s") then
		if (self.connected_module01 == nil) then
			self:ConnectModule01(amodule)
		elseif (self.connected_module02 == nil) then
			self:ConnectModule02(amodule)
		end
	end
end

function ENT:ConnectModule01(amodule)
	local attach = self:GetAttachment(self:LookupAttachment("split01"))
	local pos

	if (amodule:GetClass() == "zrms_conveyorbelt_n" or amodule:GetClass() == "zrms_conveyorbelt_s") then
		pos = Vector(attach.Pos.x, attach.Pos.y, self:GetPos().z) + self:GetRight() * 10
		local ang = self:GetAngles()
		ang:RotateAroundAxis(self:GetUp(), 90)
		amodule:SetAngles(ang)
		amodule:SetPos(pos)
	elseif (amodule:GetClass() == "zrms_conveyorbelt_c_right") then
		pos = Vector(attach.Pos.x, attach.Pos.y, self:GetPos().z) + self:GetRight() * 10
		local ang = self:GetAngles()
		ang:RotateAroundAxis(self:GetUp(), 90)
		amodule:SetAngles(ang)
		amodule:SetPos(pos)
	elseif (amodule:GetClass() == "zrms_conveyorbelt_c_left") then
		pos = Vector(attach.Pos.x, attach.Pos.y, self:GetPos().z) + self:GetRight() * 10
		local ang = self:GetAngles()
		ang:RotateAroundAxis(self:GetUp(), 90)
		amodule:SetAngles(ang)
		amodule:SetPos(pos)
	end

	amodule:SetBuildMode(false)
	amodule.splitterPos = 1
	self.connected_module01 = amodule
	self.connected_module01.connected_Parent = self
	self:EmitSound("weapons/ar2/ar2_reload_push.wav", 75, 100, 1, CHAN_AUTO)
	local rphys = amodule:GetPhysicsObject()

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

	self:UpdateSplitter()
end

function ENT:ConnectModule02(amodule)
	local attach = self:GetAttachment(self:LookupAttachment("split02"))
	local pos

	if (amodule:GetClass() == "zrms_conveyorbelt_n" or amodule:GetClass() == "zrms_conveyorbelt_s") then
		pos = Vector(attach.Pos.x, attach.Pos.y, self:GetPos().z) + self:GetRight() * 10
		local ang = self:GetAngles()
		ang:RotateAroundAxis(self:GetUp(), 90)
		amodule:SetAngles(ang)
		amodule:SetPos(pos)
	elseif (amodule:GetClass() == "zrms_conveyorbelt_c_right") then
		pos = Vector(attach.Pos.x, attach.Pos.y, self:GetPos().z) + self:GetRight() * 10
		local ang = self:GetAngles()
		ang:RotateAroundAxis(self:GetUp(), 90)
		amodule:SetAngles(ang)
		amodule:SetPos(pos)
	elseif (amodule:GetClass() == "zrms_conveyorbelt_c_left") then
		pos = Vector(attach.Pos.x, attach.Pos.y, self:GetPos().z) + self:GetRight() * 10
		local ang = self:GetAngles()
		ang:RotateAroundAxis(self:GetUp(), 90)
		amodule:SetAngles(ang)
		amodule:SetPos(pos)
	end

	amodule:SetBuildMode(false)
	amodule.splitterPos = 2
	self.connected_module02 = amodule
	self.connected_module02.connected_Parent = self
	self:EmitSound("weapons/ar2/ar2_reload_push.wav", 75, 100, 1, CHAN_AUTO)
	local rphys = amodule:GetPhysicsObject()

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

	self:UpdateSplitter()
end

function ENT:UpdateSplitter()
	if (IsValid(self.connected_module01) or IsValid(self.connected_module02)) then
		self:SetHasChild(true)
		self.PhysgunDisabled = true
	else
		self:SetHasChild(false)
		self.PhysgunDisabled = false
	end
end

function ENT:Detach_Self()
	if (IsValid(self.connected_Parent)) then
		self:EmitSound("zrmine_sfx_placecrate")
		self.connected_Parent.connected_module = nil
		self.connected_Parent:SetHasChild(false)
		self.connected_Parent = nil
		self.PhysgunDisabled = false
		self:SetBuildMode(true)
		local phys = self:GetPhysicsObject()

		if (phys:IsValid()) then
			phys:Wake()
			phys:EnableMotion(true)
		end
	end
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:Has_SplittableResource()) then
			local cm01 = self.connected_module01
			local cm02 = self.connected_module02

			if IsValid(cm01) and IsValid(cm02) and cm01:Return_StoredAmount() < cm01.HoldAmount and cm02:Return_StoredAmount() < cm02.HoldAmount then
				self:Transport()
			end
		end
	end

	function ENT:Transport()
		-- Sets the current state to busy
		self:SetCurrentState("SPLITTING")
		-- Here we find a valid resource do splitt
			local SendResource = self:FindValidResource()
			-- Plays the wheel animation
			local wheel_animtime = (1 / self.SplitingSpeed) * 2
			self:CreateAnim_Table("wheel", wheel_animtime)

			-- Sends the gravel to the connected module
			timer.Simple(self.SplitingSpeed, function()
				if (IsValid(self)) then
					-- Here we send the resources or show the discard gravel effect for module01
					self:Send_Resources(SendResource)

					timer.Simple(0.1, function()
						if (IsValid(self)) then
							self:CreateAnim_Table("idle", 1)
							self:SetCurrentState("WAITING_FOR_ORDER")
						end
					end)
				end
			end)
		end

		function ENT:OnRemove()
			self:Detach_Self()
		end

		-- Damage Stuff
		function ENT:OnTakeDamage(dmg)
			self:TakePhysicsDamage(dmg)
			local damage = dmg:GetDamage()
			local entHealth = zrmine.config.Damageable["Splitter"].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 return end
			zrmine.f.CreateAnimTable(self, anim, speed)
		end

		function ENT:Create_InsertEffect(rtype)
			zrmine.f.CreateInsertEffect(self, rtype)
		end

		--Effects
		function ENT:CreateEffect_Table(effect, sound, parent, angle, position)
			zrmine.f.CreateEffectTable(effect, sound, parent, angle, position)
		end
