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()

	local sendTable = {}

	local filterType
	if (self.FilterType == 0) then
		filterType = "Coal"
	elseif (self.FilterType == 1) then
		filterType = "Iron"
	elseif (self.FilterType == 2) then
		filterType = "Bronze"
	elseif (self.FilterType == 3) then
		filterType = "Silver"
	elseif (self.FilterType == 4) then
		filterType = "Gold"
	end

	local sendFilter = zrmine.f.Calculate_AmountCap(self.StoredResource[filterType], self.WorkAmount)

	// Do we have a module for the Filter load?
	if (IsValid(self.connected_module01) and sendFilter > 0) then
		self.StoredResource[filterType] = self.StoredResource[filterType] - sendFilter

		sendTable[filterType] = sendFilter
		self.connected_module01:Receive_Resources(sendTable)
		zrmine.f.CreateInsertEffect(self.connected_module01, filterType)
	end


	local rtype = self:FindValidResource()
	local sendother = 0

	if(rtype)then
		sendother = zrmine.f.Calculate_AmountCap(self.StoredResource[rtype], self.WorkAmount)
	end

	// Do we have a module for the other load?
	if (rtype and IsValid(self.connected_module02) and sendother > 0) then

		self.StoredResource[rtype] = self.StoredResource[rtype] - sendother

		sendTable[rtype] = sendother
		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_Resource()
	local HasResource = false

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

	return HasResource
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

	local filterType
	if (self.FilterType == 0) then
		filterType = "Coal"
	elseif (self.FilterType == 1) then
		filterType = "Iron"
	elseif (self.FilterType == 2) then
		filterType = "Bronze"
	elseif (self.FilterType == 3) then
		filterType = "Silver"
	elseif (self.FilterType == 4) then
		filterType = "Gold"
	end


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

		if (sendAmount > 0 and k ~= filterType) 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)
		local mClass = amodule:GetClass()
	if (mClass == "zrms_conveyorbelt_n" or mClass == "zrms_conveyorbelt_c_right" or mClass == "zrms_conveyorbelt_c_left" or mClass == "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("output01"))
	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)
		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)
		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)
		local ang = self:GetAngles()
		ang:RotateAroundAxis(self:GetUp(), -90)
		amodule:SetAngles(ang)
		amodule:SetPos(pos)
	end

	amodule:SetBuildMode(false)
	amodule.sorterPos = 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:UpdateSorter()
end

function ENT:ConnectModule02(amodule)
	local attach = self:GetAttachment(self:LookupAttachment("output02"))
	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)
		local ang = self:GetAngles()
		ang:RotateAroundAxis(self:GetUp(), 180)
		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)
		local ang = self:GetAngles()
		ang:RotateAroundAxis(self:GetUp(), 180)
		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)
		local ang = self:GetAngles()
		ang:RotateAroundAxis(self:GetUp(), 180)
		amodule:SetAngles(ang)
		amodule:SetPos(pos)
	end

	amodule:SetBuildMode(false)
	amodule.sorterPos = 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:UpdateSorter()
end

function ENT:UpdateSorter()
	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


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_Resource()) 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("FILTERING")

	-- Plays the wheel animation
	local wheel_animtime = (1 / self.SorterSpeed) * 2
	self:CreateAnim_Table("wheel", wheel_animtime)

	-- Sends the gravel to the connected module
	timer.Simple(self.SorterSpeed, function()
		if (IsValid(self)) then

			-- Here we send the resources
			self:Send_Resources()

			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
