/*
	DHD SENT for GarrysMod10
	Copyright (C) 2007  aVoN

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

--################# HEADER #################

--################# Include
AddCSLuaFile("cl_init.lua");
AddCSLuaFile("shared.lua");
include("shared.lua");
-- Defines
ENT.CDSIgnore = true; -- Make it undestroyable by Combad Damage System
function ENT:gcbt_breakactions() end; ENT.hasdamagecase = true; -- GCombat invulnarability!

--################# SENT CODE #################

--################# Initialize @aVoN
function ENT:Initialize()
	self.DialledAddress = {}; -- The address, the DHD shall dial
	self.busy = false;
	util.PrecacheModel(self.Model);
	util.PrecacheSound(self.PlorkSound);
	self.Entity:SetModel(self.Model)
	self.Entity:PhysicsInit(SOLID_VPHYSICS);
	self.Entity:SetMoveType(MOVETYPE_VPHYSICS);
	self.Entity:SetSolid(SOLID_VPHYSICS);
	self.Entity:SetUseType(SIMPLE_USE);
	self.Range = StarGate.CFG:Get("dhd","range",1000);
	local phys = self.Entity:GetPhysicsObject();
	if(phys:IsValid()) then
		phys:EnableMotion(false);
	end
	self:AddActivateButton();
	-- Now, check for near active gates and light up this DHD with the recently called address on this gate
	local e = self:FindGate();
	if(ValidEntity(e) and (e.IsOpen or e.Dialling) and e.DialledAddress) then
		for i=1,11 do
			local chev = e.DialledAddress[i];
			if(not e:GetNWBool("chevron"..i) and chev ~= "DIAL") then break end;
			self:AddChevron(chev,true);
		end
	end
end

--################# Support for the life-support mod/ressource distribute mod @aVoN
function ENT:RessourcesInstalled()
	if(StarGate.use_life_support and RD_AddResource) then
		return true;
	end
	return false;
end

--#################  The big red button in the middle @aVoN
function ENT:AddActivateButton()
	local e = ents.Create("point_spotlight");
	e:SetKeyValue("spotlightwidth",1);
	e:SetKeyValue("spotlightlength",1);
	e:SetKeyValue("rendercolor",self.Color.chevron);
	e:SetKeyValue("spawnflags",2);
	e:SetPos(self.ChevronPositions["DIAL"]+self.Entity:GetPos());
	e:Spawn();
	e:Activate();
	e:SetParent(self.Entity);
	e:SetAngles(Angle(-30,0,0))
	self.DialButton = e;
end

--################# Removes the enlighten shevrons, or they will stay forever, turned on, spamming the map @aVoN
function ENT:OnRemove()
	if(ValidEntity(self.DialButton)) then
		self.DialButton:SetParent();
		self.DialButton:Fire("LightOff","",0);
		self.DialButton:Fire("Kill","",1);
	end
end


--################# Stop lights @aVoN
function ENT:Shutdown(delay)
	local e = self.Entity;
	timer.Simple(delay,
		function()
			if(ValidEntity(e)) then
				e.Entity:SetNetworkedString("ADDRESS","");
				if(ValidEntity(e.DialButton)) then
					e.DialButton:Fire("LightOff","",0);
				end
				e.DialledAddress = {};
				e.Target = nil;
			end
		end
	);
end

--################# Adding address @aVoN
function ENT:AddChevron(btn,nosound)
	if(table.getn(self.DialledAddress) < 8) then
		if(not table.HasValue(self.DialledAddress,btn)) then
			table.insert(self.DialledAddress,btn);
			self.Entity:SetNetworkedString("ADDRESS",string.Implode(",",self.DialledAddress));
			if(btn == "DIAL") then
				self.DialButton:Fire("LightOn","",0);
			end
			if(btn ~= "DIAL" and not nosound) then
				self.Entity:EmitSound(Sound(self.PlorkSound),70,math.random(97,103));
			end
		end
	end
end

--################# Removing one button from address @aVoN
function ENT:RemoveChevron(btn)
	if(table.getn(self.DialledAddress) < 8) then
		local new_t = {};
		for _,v in pairs(self.DialledAddress) do
			if(v ~= btn and v ~= "#") then -- If remove any button, the Chevron 7 will be unlocked automatically!
				table.insert(new_t,v);
			end
		end
		self.DialledAddress=new_t;
		self.Entity:SetNetworkedString("ADDRESS",string.Implode(",",self.DialledAddress));
	end
end

--################# Busy? Don't allow manuall input now @aVoN
function ENT:SetBusy(d)
	local d = d or 0;
	local e = self.Entity;
	local id = "DHD.UnsetBusy."..e:EntIndex();
	self.busy = true;
	if(d > 1) then -- Delay > 1 means, only set this "Client-Side-Busy" if the gate (which already has been dialled) is telling this DHD to activate a chevron (no user shall be able to press this now for about 10 secs mostly)
		-- Tells clientside, that we do not want the overlay do be drawn now
		e:SetNWBool("Busy",true);
	end
	timer.Remove(id);
	timer.Create(id,d,1,
		function()
			if(ValidEntity(e)) then
				e.busy = false
				e:SetNWBool("Busy",false);
			end
		end
	);
end

--################# Finds a gate @aVoN
function ENT:FindGate()
	local gate;
	local dist = self.Range;
	local pos = self.Entity:GetPos();
	for _,v in pairs(ents.FindByClass("stargate_*")) do
		if(v.IsStargate) then
			local sg_dist = (pos - v:GetPos()):Length();
			if(dist >= sg_dist) then
				dist = sg_dist;
				gate = v;
			end
		end
	end
	return gate;
end

--################# Call address @aVoN
function ENT:Use(p)
	--Player is calling the gate and it is not busy
	if(ValidEntity(p) and p:IsPlayer() and not self.busy) then
		local e = self:FindGate();
		if(not ValidEntity(e)) then return end; -- Just necessary to make the hook below not being called if no gate is here to get dialled
		if(hook.Call("StarGate.Player.CanDialGate",GAMEMODE,p,e) == false) then return end;
		self.LastPlayer = p;
		self:PressButton(self:GetCurrentButton(p));
	end
	return false;
end

--################# Press Button @aVoN
-- This function is also used by the USE function and the ConCommand which is getting triggered by the GUI click
function ENT:PressButton(btn)
	local e = self:FindGate();
	local num = table.getn(self.DialledAddress);
	-- #################  Close gates!
	if(btn == "DIAL") then
		-- Old gate still opened. Close it
		if(ValidEntity(self.Target) and self.Target.IsOpen) then
			self.Target:AbortDialling();
			self.Target = nil;
			self:SetBusy(1.5);
			return;
		end
		-- Close our current gate
		if(ValidEntity(e)) then
			if(e.IsOpen) then
				e:AbortDialling();
				self.Target = nil;
				self:SetBusy(1.5);
				return;
			elseif(num == 0) then
				-- Open the dialling menue!
				umsg.Start("StarGate.OpenDialMenuDHD",self.LastPlayer);
				umsg.Entity(e);
				umsg.Entity(self.Entity);
				umsg.End();
				self:SetBusy(0.2);
				return;
			end
		end
	end
	--################# We have lesser than 7 chevrons activated or pressed the dialbutton
	if(btn and ((num < 6 or btn == "DIAL" or (num == 6 and btn == "#")) and not (num < 6 and btn=="#") or table.HasValue(self.DialledAddress,btn))) then
		self:SetBusy(0.2);
		if(table.HasValue(self.DialledAddress,btn)) then
			self:RemoveChevron(btn);
		else
			self:AddChevron(btn);
		end
		-- Dial? Ok, lets dial!
		if(ValidEntity(e)) then
			if(btn == "DIAL") then
				if(e.Dialling and e.Outbound and not e.IsOpen) then -- Only allow outbound gates to get disabled by DHD during a call
					e:AbortDialling();
					self.Target = nil;
					self:SetBusy(1.5);
					self:Shutdown(1.5);
				else
					--##### We got exact 7 chevrons, C7 as chevron7 and dialbutton activated - Lets dial out, holy crap
					if(table.getn(self.DialledAddress) == 8) then
						-- Set address, dialling type and start dialling
						e:DialGate(self.DialledAddress,true);
						-- Send Close UMSG for the dial menu
						umsg.Start("StarGate.DialMenuDHDClose",self.LastPlayer);
						umsg.End();
						self.Target = e; -- Needs to be set, so the gate does not "relightupt" this DHD on dial
					else
						self:Shutdown(0.5);
					end
				end
			end
		else
			self:Shutdown(0.5);
		end
	end
end

--################# Called by the OnScreen click function @aVoN
concommand.Add("_StarGate.DHD.AddSymbol",
	function(_,_,arg)
		local e = ents.GetByIndex(tonumber(arg[1])); -- Entity
		if(ValidEntity(e) and arg[2] and arg[2] ~= "") then
			local num = tonumber(arg[2]);
			if(num) then arg[2] = num end; -- If it is a number, we make this string to a number again
			e:PressButton(arg[2]);
		end
	end
);