
TOOL.Category		= "Construction"
TOOL.Name			= "#Wheel"
TOOL.Command		= nil
TOOL.ConfigName		= nil


TOOL.ClientConVar[ "torque" ] 		= "3000"
TOOL.ClientConVar[ "friction" ] 	= "1"
TOOL.ClientConVar[ "nocollide" ] 	= "1"
TOOL.ClientConVar[ "forcelimit" ] 	= "0"
TOOL.ClientConVar[ "fwd" ] 			= "8"	// Forward key
TOOL.ClientConVar[ "bck" ] 			= "5"	// Back key
TOOL.ClientConVar[ "toggle" ] 		= "0"	// Togglable
TOOL.ClientConVar[ "model" ] 		= "models/props_vehicles/carparts_wheel01a.mdl"
TOOL.ClientConVar[ "rx" ] 			= "90"
TOOL.ClientConVar[ "ry" ] 			= "0"
TOOL.ClientConVar[ "rz" ] 			= "90"

cleanup.Register( "wheels" )

/*---------------------------------------------------------
   Places a wheel
---------------------------------------------------------*/
function TOOL:LeftClick( trace )

	if ( trace.Entity && trace.Entity:IsPlayer() ) then return false end
	
	// If there's no physics object then we can't constraint it!
	if ( SERVER && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end
	
	if (CLIENT) then return true end
	
	local ply = self:GetOwner()

	if ( !self:GetSWEP():CheckLimit( "wheels" ) ) then return false end

	local targetPhys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone )
	
	// Get client's CVars
	local torque		= self:GetClientNumber( "torque" )
	local friction 		= self:GetClientNumber( "friction" )
	local nocollide		= self:GetClientNumber( "nocollide" )
	local limit			= self:GetClientNumber( "forcelimit" )
	local toggle		= self:GetClientNumber( "toggle" ) != 0
	local model			= self:GetClientInfo( "model" )
	
	local fwd			= self:GetClientNumber( "fwd" )
	local bck			= self:GetClientNumber( "bck" )
	
	if ( !util.IsValidModel( model ) ) then return false end
	if ( !util.IsValidProp( model ) ) then return false end

	// Create the wheel
	local wheelEnt = MakeWheel( ply, trace.HitPos, Angle(0,0,0), model, nil, nil, nil, fwd, bck )
	
	// Make sure we have our wheel angle
	self.wheelAngle = Angle( tonumber(self:GetClientInfo( "rx" )), tonumber(self:GetClientInfo( "ry" )), tonumber(self:GetClientInfo( "rz" )) )
	
	local TargetAngle = trace.HitNormal:Angle() + self.wheelAngle	
	wheelEnt:SetAngles( TargetAngle )
	
	local CurPos = wheelEnt:GetPos()
	local NearestPoint = wheelEnt:NearestPoint( CurPos - (trace.HitNormal * 512) )
	local wheelOffset = CurPos - NearestPoint
		
	wheelEnt:SetPos( trace.HitPos + wheelOffset + trace.HitNormal )
	
	// Wake up the physics object so that the entity updates
	wheelEnt:GetPhysicsObject():Wake()
	
	local TargetPos = wheelEnt:GetPos()
			
	// Set the hinge Axis perpendicular to the trace hit surface
	local LPos1 = wheelEnt:GetPhysicsObject():WorldToLocal( TargetPos + trace.HitNormal )
	local LPos2 = targetPhys:WorldToLocal( trace.HitPos )
	
	local constraint, axis = constraint.Motor( wheelEnt, trace.Entity, 0, trace.PhysicsBone, LPos1,	LPos2, friction, torque, 0, nocollide, toggle, ply, limit )
	
	undo.Create("Wheel")
	undo.AddEntity( axis )
	undo.AddEntity( constraint )
	undo.AddEntity( wheelEnt )
	undo.SetPlayer( ply )
	undo.Finish()

	
	ply:AddCleanup( "wheels", axis )
	ply:AddCleanup( "wheels", constraint )
	ply:AddCleanup( "wheels", wheelEnt )
	
	wheelEnt:GetTable():SetMotor( constraint )
	wheelEnt:GetTable():SetDirection( constraint:GetTable().direction )
	wheelEnt:GetTable():SetAxis( trace.HitNormal )
	wheelEnt:GetTable():SetToggle( toggle )
	wheelEnt:GetTable():DoDirectionEffect()
	wheelEnt:GetTable():SetBaseTorque( torque )

	return true

end


/*---------------------------------------------------------
   Apply new values to the wheel
---------------------------------------------------------*/
function TOOL:RightClick( trace )

	if ( trace.Entity && trace.Entity:GetClass() != "gmod_wheel" ) then return false end
	if (CLIENT) then return true end
	
	local wheelEnt = trace.Entity
	
	// Only change your own wheels..
	if ( wheelEnt:GetTable():GetPlayer():IsValid() && 
	     wheelEnt:GetTable():GetPlayer() != self:GetOwner() ) then 
		 
		 return false 
		 
	end

	// Get client's CVars
	local torque		= self:GetClientNumber( "torque" )
	local toggle		= self:GetClientNumber( "toggle" ) != 0
	local fwd			= self:GetClientNumber( "fwd" )
	local bck			= self:GetClientNumber( "bck" )
		
	wheelEnt:GetTable():SetTorque( torque )
	wheelEnt:GetTable():SetToggle( toggle )
	
	// Make sure the table exists!
	wheelEnt:GetTable().KeyBinds = wheelEnt:GetTable().KeyBinds or {}
	
	wheelEnt:GetTable().key_f = fwd
	wheelEnt:GetTable().key_r = bck
	
	// Remove old binds
	numpad.Remove( wheelEnt:GetTable().KeyBinds[1] )
	numpad.Remove( wheelEnt:GetTable().KeyBinds[2] )
	numpad.Remove( wheelEnt:GetTable().KeyBinds[3] )
	numpad.Remove( wheelEnt:GetTable().KeyBinds[4] )
	
	// Add new binds
	wheelEnt:GetTable().KeyBinds[1] = numpad.OnDown( 	self:GetOwner(), 	fwd, 	"WheelForward", 	wheelEnt, 	true )
	wheelEnt:GetTable().KeyBinds[2] = numpad.OnUp( 		self:GetOwner(), 	fwd, 	"WheelForward", 	wheelEnt, 	false )
	wheelEnt:GetTable().KeyBinds[3] = numpad.OnDown( 	self:GetOwner(), 	bck, 	"WheelReverse", 	wheelEnt, 	true )
	wheelEnt:GetTable().KeyBinds[4] = numpad.OnUp( 		self:GetOwner(), 	bck, 	"WheelReverse", 	wheelEnt, 	false )

	return true

end

if ( SERVER ) then

	/*---------------------------------------------------------
	   For duplicator, creates the wheel.
	---------------------------------------------------------*/
	function MakeWheel( pl, Pos, Ang, Model, Vel, aVel, frozen, key_f, key_r )

		if ( !pl:CheckLimit( "wheels" ) ) then return false end
	
		local wheel = ents.Create( "gmod_wheel" )
		if ( !wheel:IsValid() ) then return end
		
		wheel:SetModel(Model )
		wheel:SetPos( Pos )
		wheel:SetAngles( Ang )
		wheel:Spawn()
		
		wheel:GetTable():SetPlayer( pl )

		if ( wheel:GetPhysicsObject():IsValid() ) then
		
			Phys = wheel:GetPhysicsObject()
			if Vel then Phys:SetVelocity(Vel) end
			if aVel then Phys:AddAngleVelocity(aVel) end
			Phys:EnableMotion(frozen != true)
			
		end
	
		wheel:GetTable().model = model
		wheel:GetTable().key_f = key_f
		wheel:GetTable().key_r = key_r
		
		wheel:GetTable().KeyBinds = {}
		
		// Bind to keypad
		wheel:GetTable().KeyBinds[1] = numpad.OnDown( 	pl, 	key_f, 	"WheelForward", 	wheel, 	true )
		wheel:GetTable().KeyBinds[2] = numpad.OnUp( 	pl, 	key_f, 	"WheelForward", 	wheel, 	false )
		wheel:GetTable().KeyBinds[3] = numpad.OnDown( 	pl, 	key_r, 	"WheelReverse", 	wheel, 	true )
		wheel:GetTable().KeyBinds[4] = numpad.OnUp( 	pl, 	key_r, 	"WheelReverse", 	wheel, 	false )
		
		pl:AddCount( "wheels", wheel )
		
		return wheel
		
	end

	duplicator.RegisterEntityClass( "gmod_wheel", MakeWheel, "Pos", "Ang", "model", "Vel", "aVel", "frozen", "key_f", "key_r" )

end

function TOOL:UpdateGhostWheel( ent, player )

	if ( !ent ) then return end
	if ( !ent:IsValid() ) then return end
	
	local tr 	= utilx.GetPlayerTrace( player, player:GetCursorAimVector() )
	local trace 	= util.TraceLine( tr )
	if (!trace.Hit) then return end
	
	if ( trace.Entity:IsPlayer() ) then
	
		ent:SetNoDraw( true )
		return
		
	end
	
	local Ang = trace.HitNormal:Angle() + self.wheelAngle
	local CurPos = ent:GetPos()
	local NearestPoint = ent:NearestPoint( CurPos - (trace.HitNormal * 512) )
	local WheelOffset = CurPos - NearestPoint
	
	local min = ent:OBBMins()
	ent:SetPos( trace.HitPos + trace.HitNormal + WheelOffset )
	ent:SetAngles( Ang )
	
	ent:SetNoDraw( false )
	
end

/*---------------------------------------------------------
   Maintains the ghost wheel
---------------------------------------------------------*/
function TOOL:Think()

	if (!self.GhostEntity || !self.GhostEntity:IsValid() || self.GhostEntity:GetModel() != self:GetClientInfo( "model" )) then
		self.wheelAngle = Angle( tonumber(self:GetClientInfo( "rx" )), tonumber(self:GetClientInfo( "ry" )), tonumber(self:GetClientInfo( "rz" )) )
		self:MakeGhostEntity( self:GetClientInfo( "model" ), Vector(0,0,0), Angle(0,0,0) )
	end
	
	self:UpdateGhostWheel( self.GhostEntity, self:GetOwner() )
	
end
