TOOL.Category		= "Wire Extras/Other"
TOOL.Name			= "PID"
TOOL.Command		= nil
TOOL.ConfigName		= ""
TOOL.Tab			= "Wire"

/* Con vars for this stool */
TOOL.ClientConVar[ "pgain" ] = "0"
TOOL.ClientConVar[ "igain" ] = "0"
TOOL.ClientConVar[ "dgain" ] = "0"
TOOL.ClientConVar[ "dcut" ] = "1000"
TOOL.ClientConVar[ "ilim" ] = "1000"
TOOL.ClientConVar[ "limit" ] = "1000"

TOOL.Model = "models/jaanus/wiretool/wiretool_siren.mdl"

cleanup.Register( "wire_pids" )

/* If we're running on the client, setup the description strings */
if ( CLIENT ) then
    language.Add( "Tool.wire_pid.name", "PID Tool (Wire)" )
    language.Add( "Tool.wire_pid.desc", "Spawns a PID Loop." )
    language.Add( "Tool.wire_pid.0", "Primary: Create/Update Controller   Secondary: Copy Settings" )
    language.Add( "undone_Wire PID", "Undone Wire PID" )
end


function TOOL:LeftClick( trace )
	/* Everything is server except the trace */
	if (!SERVER) then return true end
	
	/* Setup all of our local variables */
	local ply = self:GetOwner()
	local pgain = self:GetClientNumber("pgain")
	local igain = self:GetClientNumber("igain")
	local dgain = self:GetClientNumber("dgain")
	local dcut = self:GetClientNumber("dcut")
	local ilim = self:GetClientNumber("ilim")
	local limit = self:GetClientNumber("limit")

	/* If we're just updating, call the PID's SetupGains and exit */
	if ( trace.Entity:IsValid() && trace.Entity:GetClass() == "gmod_wire_pid") then
		trace.Entity:SetupGains(pgain, igain, dgain, dcut, ilim, limit)
		return true
	end

	/* Don't want to put one on a player */
	if (trace.Entity:IsPlayer()) then return end

	/* Normal to hit surface */
	local Ang = trace.HitNormal:Angle()
	Ang.pitch = Ang.pitch + 90

	/* Make the PID loop */
	local ent = MakeWirePID(ply, self.Model, trace.HitPos, Ang, pgain, igain, dgain, dcut, ilim, limit)
	
	local min = ent:OBBMins()
	ent:SetPos( trace.HitPos - trace.HitNormal * min.z )

	/* Weld it to the surface, as long as it isn't the ground */
	if (!trace.HitWorld) then
		local const = WireLib.Weld(ent, trace.Entity, trace.PhysicsBone, true)
	end

	/* Add us to the undo list */
	undo.Create("Wire PID")
		undo.AddEntity(ent)
		if (!(const == nil)) then
			undo.AddEntity(const)
		end
		undo.SetPlayer(ply)
	undo.Finish()

	ply:AddCleanup( "wire_pids", ent )
	return true
end

function TOOL:RightClick( trace )
	
	/* Get our player */
	local ply = self:GetOwner()

	/* If we hit a PID loop that's ours, get its settings and change the tool's to match */
	if ( trace.Entity:IsValid() && trace.Entity:GetClass() == "gmod_wire_pid" && trace.Entity:GetPlayer() == ply ) then
		local pgain, igain, dgain, dcut, ilim, limit = trace.Entity.p, trace.Entity.i, trace.Entity.d, trace.Entity.dcut, trace.Entity.ilim, trace.Entity.limit
		local ply = self:GetOwner()
		ply:ConCommand("wire_pid_pgain "..pgain)
		ply:ConCommand("wire_pid_igain "..igain)
		ply:ConCommand("wire_pid_dgain "..dgain)
		ply:ConCommand("wire_pid_dcut "..dcut)
		ply:ConCommand("wire_pid_ilim "..ilim)
		ply:ConCommand("wire_pid_limit "..limit)

		return true
	end
end

if (SERVER) then
	/* Makes a PID loop */
	function MakeWirePID(pl, Model, Pos, Ang, p, i, d, dcut, ilim, limit, nocollide, Vel, aVel, frozen)
		local ent = ents.Create("gmod_wire_pid")
		ent:SetAngles(Ang)
		ent:SetPos(Pos)
		ent:SetModel(Model)
		ent:Spawn()
		ent:SetupGains(p, i, d, dcut, ilim, limit)
		ent:SetPlayer(pl)
		return ent
	end
	
	/* Register us for duplicator compatibility */
	duplicator.RegisterEntityClass("gmod_wire_pid", MakeWirePID, "Model", "Pos", "Ang", "p", "i", "d", "dcut", "ilim", "limit", "nocollide", "Vel", "aVel", "frozen")
end

function TOOL:UpdateGhostWirePID( ent, player )
	if ( !ent ) then return end
	if ( !ent:IsValid() ) then return end

	local tr 	= util.GetPlayerTrace( player, player:GetAimVector() )
	local trace 	= util.TraceLine( tr )
	if (!trace.Hit) then return end

	if (trace.Entity && trace.Entity:GetClass() == "gmod_wire_pid" || trace.Entity:IsPlayer()) then
		ent:SetNoDraw( true )
		return
	end

	local Ang = trace.HitNormal:Angle()
	Ang.pitch = Ang.pitch + 90

	local min = ent:OBBMins()
	ent:SetPos( trace.HitPos - trace.HitNormal * min.z )
	ent:SetAngles( Ang )

	ent:SetNoDraw( false )
end


function TOOL:Think()
	if (!self.GhostEntity || !self.GhostEntity:IsValid() || self.GhostEntity:GetModel() != self.Model ) then
		self:MakeGhostEntity( self.Model, Vector(0,0,0), Angle(0,0,0) )
	end

	self:UpdateGhostWirePID( self.GhostEntity, self:GetOwner() )
end

function TOOL.BuildCPanel( panel )
	panel:AddControl("Header", { 
		Text = "#Tool.wire_pid.name", 
		Description = "#Tool.wire_pid.desc" 
	})

	panel:AddControl("Slider", {
		Label = "P Gain",
		Type = "Float", 
		Min = "0", 
		Max = "1000", 
		Command = "wire_pid_pgain"
	})
	panel:AddControl("Slider", {
		Label = "I Gain",
		Type = "Float", 
		Min = "0", 
		Max = "10", 
		Command = "wire_pid_igain"
	})
	panel:AddControl("Slider", {
		Label = "D Gain",
		Type = "Float", 
		Min = "0", 
		Max = "1000", 
		Command = "wire_pid_dgain"
	})
	panel:AddControl("Slider", {
		Label = "D Cutoff for Integral",
		Type = "Float", 
		Min = "0", 
		Max = "1000", 
		Command = "wire_pid_dcut"
	})
	panel:AddControl("Slider", {
		Label = "Integral Limit",
		Type = "Float", 
		Min = "0", 
		Max = "10000", 
		Command = "wire_pid_ilim"
	})
	panel:AddControl("Slider", {
		Label = "Output Limit",
		Type = "Float", 
		Min = "0", 
		Max = "10000", 
		Command = "wire_pid_limit"
	})
end
