/*
	Stargate 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/>.
*/

local PANEL = {};
PANEL.Images = {
	Valid = "gui/silkicons/check_on",
	Invalid = "gui/silkicons/check_off",
	Editing = "gui/silkicons/table_edit",
	Warning = "vgui/notices/error",
	Info = "gui/info",
}
PANEL.Sounds = {
	Warning = Sound("buttons/button2.wav"),
	Info = Sound("buttons/button9.wav"),
}

--################# Init @aVoN
function PANEL:Init()
	self:SetSize(180,80);
	-- Create the Address Field
	self.VGUI = {
		AddressLabel = vgui.Create("DLabel",self),
		AddressTextEntry = vgui.Create("DTextEntry",self),
		StatusLabel = vgui.Create("DLabel",self),
		StatusImage = vgui.Create("DImage",self),
		MessageImage = vgui.Create("DImage",self),
		MessageLabel = vgui.Create("DLabel",self),
	}
	self.VGUI.AddressLabel:SetText("Address:");
	self.VGUI.StatusLabel:SetText("");
	self.VGUI.MessageLabel:SetText("");
	self.Entity = NULL;
	
	--####### Apply Sizes...
	-- The Description above the TextEntry
 	self.VGUI.AddressLabel:SetPos(0,0);
	
	-- The Address TextEntry
	self.VGUI.AddressTextEntry:SetPos(45,0);
	self.VGUI.AddressTextEntry:SetSize(60,self.VGUI.AddressTextEntry:GetTall());
	self.VGUI.AddressTextEntry:SetTooltip("Sets the Address of the current Stargate. It can only contain the letters 0-9,A-Z and @");
	--This function restricts the letters you can enter to a valid address
	self.VGUI.AddressTextEntry.OnTextChanged = function(TextEntry)
		local text = TextEntry:GetValue();
		if(text ~= self.LastAddress) then
			local pos = TextEntry:GetCaretPos();
			local len = text:len();
			local letters = text:upper():gsub("[^0-9A-Z@]",""):TrimExplode(""); -- Upper, remove invalid chars and split!
			local text = ""; -- Wipe
			for _,v in pairs(letters) do
				if(not text:find(v)) then
					text = text..v;
				end
			end
			text = text:sub(1,6);
			self.LastAddress = text;
			TextEntry:SetText(text);
			TextEntry:SetCaretPos(math.Clamp(pos - (len-#letters),0,text:len())); -- Reset the caretpos!
			self:SetStatus(text);
		end
	end
	
	-- Status Label
	self.VGUI.StatusImage:SetPos(110,3);
	self.VGUI.StatusImage:SetSize(16,16);
	self.VGUI.StatusLabel:SetPos(130,0);
	
	-- Message (What went wrong?)
	self.VGUI.MessageImage:SetPos(2,23);
	self.VGUI.MessageImage:SetSize(16,16);
	self.VGUI.MessageLabel:SetPos(22,21);
	self.VGUI.MessageLabel:SetWide(200);
end

-- You should always call SetEntity BEFORE SetText!!!

--################# Setting text on this panel will set the text on the TextEntry instead @aVoN
function PANEL:SetText(s)
	local s = (s or ""):upper();
	self.VGUI.AddressTextEntry:SetText(s);
	self:SetStatus(s,true);
	self.LastAddress = s;
end

-- You should always call SetEntity BEFORE SetText!!!

--################# The necessary Entity, this panel comes along with (the gate) @aVoN
function PANEL:SetEntity(e)
	self.Entity = e;
	self:SetText(e:GetGateAddress());
end

--################# Draw the fading info box @aVoN
function PANEL:Paint()
	-- The box around our notify message
	if(self.Message) then
		-- Fade in/out
		local alpha = math.Clamp(self.MessageCreated+1-CurTime(),0,1);
		if(self.MessageShow) then alpha = 1-alpha end;
		if(alpha > 0) then
			surface.SetFont("Default");
			local w,_ = surface.GetTextSize(self.Message or "");
			draw.RoundedBox(8,0,21,w+20+2,20,Color(16,16,16,160*alpha));
			self.VGUI.MessageLabel:SetAlpha(255*alpha);
			self.VGUI.MessageImage:SetAlpha(255*alpha);
		end
	end
	return true;
end

--################# Get every valid gates @aVoN
function PANEL:GetGates()
	-- Clientside does not support wildcards yet.. Shame on you, garry!
	local sg1 = ents.FindByClass("stargate_sg1");
	local sga = ents.FindByClass("stargate_atlantis");
	--local super = ents.FindByClass("stargate_supergate"); -- FIXME: Should be added, if the supergate is done - and some switch to only find supergates or normal gates
	local gates = {};
	for _,v in pairs(sg1) do
		table.insert(gates,v);
	end
	for _,v in pairs(sga) do
		table.insert(gates,v);
	end
	--[[
	for _,v in pairs(super) do
		table.insert(gates,v);
	end
	--]]
	return gates;
end

--################# Sets the status (Valid/Invalid/Already Exists) @aVoN
function PANEL:SetStatus(s,no_message)
	local s = (s or ""):upper();
	local len = s:len();
	if(len == 6) then
		local letters = s:TrimExplode("");
		local valid = true;
		local set = true;
		for _,v in pairs(self:GetGates()) do
			local address = v:GetGateAddress();
			if(	address:find(letters[1]) and
				address:find(letters[2]) and
				address:find(letters[3]) and
				address:find(letters[4]) and
				address:find(letters[5]) and
				address:find(letters[6])
			) then
				if(v == self.Entity) then -- We have entered the same/similar address we had before - So we haven't changed anything
					set = false;
					break;
				else
					valid = false;
					break;
				end
			end
		end
		-- Valid address?
		if(valid) then
			self.VGUI.StatusImage:SetImage(self.Images.Valid);
			self.VGUI.StatusLabel:SetText("Valid");
			if(not no_message) then
				-- Have we set the address or is it the old from before?
				if(set) then
					self:ShowMessage("Address successfully set!","Info");
				else
					self:ShowMessage("Address remains at: "..s,"Info",true);
				end
			end
			if(self.OnAddressSet) then self.OnAddressSet(self.Entity,s:upper()) end; -- SET THE ADDRESS!
		else
			-- INVALID!
			self.VGUI.StatusImage:SetImage(self.Images.Invalid);
			self.VGUI.StatusLabel:SetText("Invalid");
			self:ShowMessage("Address already exists!","Warning");
		end
	elseif(len == 0) then
		-- Cleared this gate's address
		self.VGUI.StatusImage:SetImage("null");
		self.VGUI.StatusLabel:SetText("");
		if(not no_message) then self:ShowMessage("Address cleared!","Info") end;
		if(self.OnAddressSet) then self.OnAddressSet(self.Entity,"") end; -- CLEAR ADDRESS
	else
		-- Typing address!
		self.VGUI.StatusImage:SetImage(self.Images.Editing);
		self.VGUI.StatusLabel:SetText("Editing...");
		self:ShowMessage();
	end
	-- Clear any previous message
	if(no_message) then 
		-- Instant clear! (Some hacky way w/e)
		self.Message = nil;
		self.MessageShow = false;
		self.VGUI.MessageLabel:SetAlpha(0);
		self.VGUI.MessageImage:SetAlpha(0);
	end
end

--################# Shows a message, what we did now @aVoN
function PANEL:ShowMessage(s,img,nosound)
	if(not s) then -- Stop the Message
		if(self.MessageShow) then
			self.MessageShow = false;
			self.MessageCreated = CurTime();
		end
		return;
	end
	self.VGUI.MessageImage:SetImage(self.Images[img] or "null");
	if(not nosound) then
		surface.PlaySound(self.Sounds[img]);
	end
	self.VGUI.MessageLabel:SetText(s);
	self.Message = s;
	if(not self.MessageShow) then
		self.MessageShow = true;
		self.MessageCreated = CurTime();
	end
end

vgui.Register("SAddressPanel",PANEL,"Panel");


--################# Shows how this thing has to be used @aVoN
function PANEL:GenerateExample()
	local VGUI = vgui.Create("SAddressPanel");
	VGUI:SetSize(180,80);
	VGUI:SetEntity(NULL); -- This defines the stargate this Address Panel is allocated to (Necessary, so we know, what gate we are currently using)
	VGUI.OnAddressSet = function(gate,address) end; -- The function which shall be triggered when the user set the address on this gate
	return VGUI;
end
