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)
	self:SetCustomCollisionCheck(true)
	local phys = self:GetPhysicsObject()

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

	self:UseClientSideAnimation()
	self:sv_CreateCart()
	self.svCartModel:SetBodygroup(0, 0)
	self.PhysgunDisabled = false
	self.PublicEntity = false
	self.InWorldResource = {}
	self:SetCurrentState("CLOSED")
	self.Connected_ResourceOre = nil
end

function ENT:sv_CreateCart()
	self.svCartModel = ents.Create("zrms_minecart")
	self.svCartModel:SetPos(self:GetAttachment(1).Pos)
	local ang = self:GetAttachment(1).Ang
	ang:RotateAroundAxis(self:GetAttachment(1).Ang:Up(), 90)
	self.svCartModel:SetAngles(ang)
	self.svCartModel:Spawn()
	self.svCartModel:Activate()
	self.svCartModel:SetParent(self, 1)

	timer.Simple(0.4, function()
		if (IsValid(self)) then
			self.svCartModel:CPPISetOwner(self:CPPIGetOwner())
			local ply = zrmine.f.GetOwner(self)
			zrmine.f.SetOwnerID(self.svCartModel, ply)
		end
	end)
end

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

		return
	end

	if self.PublicEntity then return end

	if (self:GetCurrentState() == "CLOSED") then
		self:OpenMine()
	elseif (self:GetCurrentState() == "WAITING_FOR_ORDER") then
		self.svCartModel:SetNoDraw(true)
		zrmine.f.CreateEffectTable(nil, "zrmine_sfx_connect_refinery", self, self:GetAngles(), self:GetPos())
		self:Mine_Close()
		self.Connected_ResourceOre = nil
		self:SetConnectedOre(nil)
		self:SetMineResourceType("Nothing")
	end
end

function ENT:OpenMine()
	local validMine = self:SearchOreMine()

	if (IsValid(validMine)) then
		--self:DropToFloor()
		self.svCartModel:SetNoDraw(false)
		self.Connected_ResourceOre = validMine
		zrmine.f.CreateEffectTable("zrms_ore_mine", "zrmine_sfx_connect_refinery", self.Connected_ResourceOre, self.Connected_ResourceOre:GetAngles(), self.Connected_ResourceOre:GetPos())
		self:SetConnectedOre(validMine)
		self:SetMineResourceType(validMine:GetResourceType())
		self:Mine_Open()
	else
		zrmine.f.Notify(activator, zrmine.language.Mine_NoOre, 1)
	end
end

function ENT:SearchOreMine()
	local validOreMine = nil
	local ores = {}

	for k, v in pairs(ents.FindInSphere(self:GetPos(), 100 + zrmine.config.Mine_SearchDistance)) do
		if (IsValid(v) and string.sub(v:GetClass(), 1, 8) == "zrms_ore") then
			table.insert(ores, v)
		end
	end

	local nearestEnt = self:Ore_FindNearestEntity(ores, self:GetPos(), zrmine.config.Mine_SearchDistance)

	if (IsValid(nearestEnt)) then
		validOreMine = nearestEnt
	end

	return validOreMine
end

function ENT:Ore_FindNearestEntity(aents, pos, range)
	local nearestEnt

	for i, entity in ipairs(aents) do
		local distance = pos:Distance(entity:GetPos())

		if (distance <= range) then
			nearestEnt = entity
			range = distance
		end
	end

	return nearestEnt
end

function ENT:Mine_Close()
	local phys = self:GetPhysicsObject()

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

	self.PhysgunDisabled = false
	self:SetCurrentState("CLOSING")
	self:CreateAnim_Table("door_close", 10)

	timer.Simple(1, function()
		if (IsValid(self)) then
			self:SetIsClosed(true)
			self:SetHideCart(true)
			self:SetCurrentState("CLOSED")
		end
	end)
end

function ENT:Mine_Open()
	local phys = self:GetPhysicsObject()

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

	self.PhysgunDisabled = true
	self:SetCurrentState("OPENING")
	self:SetIsClosed(false)
	self:CreateAnim_Table("door_open", 1)
	self.svCartModel:SetBodygroup(0, 0)
	self.svCartModel:EmitSound("zrmine_sfx_mine_door_move")
	self:SetHideCart(true)

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

-- Logic
function ENT:MineCart_Down(ply)
	if (self:GetValidResourceCount() > zrmine.config.Mine_MaxEntCount) then
		zrmine.f.Notify(ply, zrmine.language.Mine_EntLimit, 1)

		return
	end

	if (self.Connected_ResourceOre:HasResource() == false) then
		zrmine.f.Notify(ply, zrmine.language.Mine_Empty, 1)

		return
	end

	-- Returns the OreAmount we gonna take from the Mine
	local OreAmount = math.random(zrmine.config.Min_MiningAmount, zrmine.config.Max_MiningAmount)

	if (IsValid(self.Connected_ResourceOre)) then
		local CRO_Amount = self.Connected_ResourceOre:GetResourceAmount()

		if (OreAmount > CRO_Amount) then
			OreAmount = CRO_Amount
		end

		self.Connected_ResourceOre:DecreaseOre(OreAmount)
	end

	self:SetHideCart(false)
	self:SetCurrentState("MINING")
	self.svCartModel:Minecart_RollDown()
	self:CreateAnim_Table("door_close", 1)
	local mineTime = zrmine.config.MiningTime[self.Connected_ResourceOre:GetResourceType()]
	self:SetMinningTime(mineTime)
	self:SetStartMinningTime(CurTime())
	self.svCartModel:EmitSound("zrmine_sfx_minecratemove")

	timer.Simple(3.4, function()
		if (IsValid(self)) then
			self.svCartModel:EmitSound("zrmine_sfx_mine_door_move")

			timer.Simple(1, function()
				if (IsValid(self)) then
					self.svCartModel:StopSound("zrmine_sfx_minecratemove")
					self.svCartModel:EmitSound("zrmine_sfx_mine_door_stop")
				end
			end)
		end
	end)

	timer.Simple(5, function()
		if (IsValid(self)) then
			self:SetIsClosed(true)
			self:CreateAnim_Table("wheel_roll", 0.5)

			timer.Simple(mineTime, function()
				if (IsValid(self)) then
					self:MineCart_SpawnResource(OreAmount)
				end
			end)
		end
	end)
end

function ENT:GetValidResourceCount()
	local validEnts = 0

	for k, v in pairs(self.InWorldResource) do
		if (IsValid(v)) then
			validEnts = validEnts + 1
		end
	end

	return validEnts
end

function ENT:GetRandomOre()
	local OreChancePool = {}

	for k, v in pairs(zrmine.config.Mine_ResourceChance) do
		for i = 1, v do
			table.insert(OreChancePool, k)
		end
	end

	return table.Random(OreChancePool)
end

function ENT:MineCart_SpawnResource(OreAmount)
	self:MineCart_Up()
	local Big_JunkAmount = math.random(0, 2)
	local Small_JunkAmount = math.random(1, 2)
	local JunkCount = Big_JunkAmount + Small_JunkAmount
	local FoundResourcesTable = {}
	local foundResource
	local bJunks = Big_JunkAmount
	local bOrePerJunk = (OreAmount * 0.6) / Big_JunkAmount
	local sOrePerJunk = (OreAmount * 0.4) / Small_JunkAmount

	for i = 1, JunkCount do
		if (self:GetMineResourceType() == "Random") then
			foundResource = self:GetRandomOre()
		else
			foundResource = self:GetMineResourceType()
		end

		if (foundResource ~= "Nothing") then
			table.insert(FoundResourcesTable, i, foundResource)
		end
	end

	timer.Simple(1, function()
		if (IsValid(self)) then
			self.svCartModel:Minecart_Unload()
		end
	end)

	timer.Simple(1.4, function()
		if (IsValid(self)) then
			--Vrondakis
			if (LevelSystemConfiguration or manolis) then
				local ply = zrmine.f.GetOwner(self)

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

			local y = 0
			local delay = 0.1

			for k, v in pairs(FoundResourcesTable) do
				y = y + 15
				delay = delay + 0.1

				if (bJunks > 0) then
					self:Resource_OffsetSpawn(y, delay, bOrePerJunk, 1, v)
				else
					self:Resource_OffsetSpawn(y, delay, sOrePerJunk, 0, v)
				end

				bJunks = bJunks - 1
			end

			timer.Simple((JunkCount * 0.1) + 0.1, function()
				if (IsValid(self)) then
					self:SetCurrentState("WAITING_FOR_ORDER")
				end
			end)
		end
	end)
end

function ENT:MineCart_Up()
	self:SetIsClosed(false)
	self:CreateAnim_Table("door_open", 1)
	self.svCartModel:SetBodygroup(0, 1)
	self:SetMinningTime(-1)
	self:SetStartMinningTime(-1)
	local mineType = self:GetMineResourceType()

	if (mineType == "Random") then
		self.svCartModel:SetSkin(0)
	elseif (mineType == "Coal") then
		self.svCartModel:SetSkin(5)
	elseif (mineType == "Iron") then
		self.svCartModel:SetSkin(1)
	elseif (mineType == "Bronze") then
		self.svCartModel:SetSkin(2)
	elseif (mineType == "Silver") then
		self.svCartModel:SetSkin(3)
	elseif (mineType == "Gold") then
		self.svCartModel:SetSkin(4)
	end

	self.svCartModel:EmitSound("zrmine_sfx_mine_door_move")

	timer.Simple(0.3, function()
		if (IsValid(self)) then
			self.svCartModel:EmitSound("plats/elevator_stop.wav", 75, 100, 1, CHAN_AUTO)
			self.svCartModel:EmitSound("zrmine_sfx_mine_door_stop")
		end
	end)

	self:SetHideCart(true)
end

-- Damage Stuff
function ENT:OnTakeDamage(dmg)
	self:TakePhysicsDamage(dmg)
	local damage = dmg:GetDamage()
	local entHealth = zrmine.config.Damageable["MineEntrance"].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

-- Utility Spawn Resource
function ENT:Resource_OffsetSpawn(y, delay, OrePerJunk, bg, rtype)
	timer.Simple(delay, function()
		if (IsValid(self)) then
			local pos = self.svCartModel:GetPos() + self.svCartModel:GetForward() * 30
			pos = pos + self.svCartModel:GetUp() * 10 + self.svCartModel:GetRight() * 1
			pos = pos + self.svCartModel:GetUp() * y
			local ent = self:SpawnResource(pos, OrePerJunk, bg, rtype)
			zrmine.f.CreateEffectTable("mine_res_spawn01", "zrmine_sfx_spawnresource", self, ent:GetAngles(), ent:GetPos())
		end
	end)
end

function ENT:SpawnResource(pos, oreamount, bg, rType)
	local ent = ents.Create("zrms_resource")
	ent:SetAngles(Angle(math.random(0, 360), math.random(0, 360), math.random(0, 360)))
	ent:SetPos(pos)
	ent:Spawn()
	ent:Activate()
	ent:SetBodygroup(0, bg)

	if (rType == "Iron") then
		ent:SetSkin(0)
	elseif (rType == "Bronze") then
		ent:SetSkin(1)
	elseif (rType == "Silver") then
		ent:SetSkin(2)
	elseif (rType == "Gold") then
		ent:SetSkin(3)
	elseif (rType == "Coal") then
		ent:SetSkin(4)
	end

	table.insert(self.InWorldResource, ent)
	ent:SetResourceType(tostring(rType))
	ent:SetResourceAmount(oreamount)

	if (zrmine.config.Resource_Share) then
		ent:CPPISetOwner(self:CPPIGetOwner())
		ent:SetOwner(self:CPPIGetOwner())
	end

	return ent
end

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

hook.Add("ShouldCollide", "zrms_mine_ShouldCollide", function(ent1, ent2)
	if (IsValid(ent1) and IsValid(ent2) and ent1:GetClass() == "zrms_mineentrance_base" and ent2:GetClass() == "zrms_ore") then return false end

	return true
end)
