GravityValve =
{
	Properties =
	{
		bActive = 1,
		Strength = 10,
		Radius = 10,
		bSpline = 0,
	},

	Server = {},
	Client = {},

	_PhysTableCyl = { Area={}, },
	_PhysTableSph = { Area={}, },
	_PhysTableSpl = { Area={points={},}, },
	_Points = {},
	_Caps = {},

	Editor =
	{
		Icon = "GravitySphere.bmp",
		ShowBounds = 1,
	},
}

-------------------------------------------------------
function GravityValve:OnLoad(table)
	self.bActive = table.bActive
	self._Points = table._Points
	self._Caps = table._Caps
end

-------------------------------------------------------
function GravityValve:OnSave(table)
	table.bActive = self.bActive
	table._Points = self._Points
	table._Caps = self._Caps
end

function GravityValve:OnSpawn()
	self:SetActive( self.Properties.bActive )
end

function GravityValve:OnDestroy()
	local Caps = self._Caps
	while table.getn(Caps)>0 do
		System.RemoveEntity( Caps[1] )
		table.remove( Caps, 1 )
	end
end

-- OnPropertyChange called only by the editor
function GravityValve:OnPropertyChange()
	self:NeedSetup()
end

function GravityValve:OnReset()
	self:NeedSetup()
end

function GravityValve:FillPoints()
	local MAX_POINTS = 50
	local prefix = self:GetName().."_p"
	local name
	local nPoints = 1
	local Points = self._Points

	Points[1] = self

	for i=1,MAX_POINTS do
		name = prefix..tostring(i)
		local ent = System.GetEntityByName( name )
		if not ent then break end
		Points[i+1] = ent
		nPoints = i+1
		Log("npoints "..nPoints);
	end

	while table.getn(Points)>nPoints do
		Log("removed");
		table.remove(Points)
	end

	for i=1, table.getn(Points) do
		Log(".. "..Points[i]:GetName())
	end
end

function GravityValve:CreateCylinderArea( from, to, radius, strength )
	local Area = self._PhysTableCyl.Area
	local axis = DifferenceVectors( to, from )
	Area.type = AREA_CYLINDER
	Area.radius = radius
	Area.height = LengthVector( axis ) * .5
	Area.center = ScaleVector( SumVectors( to, from ), 0.5 )
	Area.axis = NormalizeVector( axis )
	Area.gravity = ScaleVector( Area.axis, strength )
	Area.uniform = 1
	Area.falloff = 0

	return Area
end

function GravityValve:CreateSphereArea( radius, gravity )
	local Area = self._PhysTableSph.Area
	Area.type = AREA_SPHERE
	Area.radius = radius
	Area.uniform = 1
	Area.falloff = 0
	Area.gravity = ScaleVector( gravity, 8 )

	return Area
end

function GravityValve:NeedSetup()
	self.bNeedSetup = 1
	self:Activate(1)
end

function GravityValve:OnChange( index )
	self:NeedSetup()
end

function GravityValve:OnUpdate()
	--Log("GV:OU "..self:GetName())
	if self.bNeedSetup then
		local wasActive = self.bActive
		self:SetActive(0)
		self:SetActive(wasActive)
		self.bNeedSetup = nil
		self:Activate(0)
	end
end

GravityValve.Server.OnUpdate = GravityValve.OnUpdate
GravityValve.Client.OnUpdate = GravityValve.OnUpdate

function GravityValve:SetActive( bActive )
	if bActive == self.bActive then return end
	self:FillPoints()
	local p, n
	local Points = self._Points
	local Caps = self._Caps
	n = table.getn(Points)
	--Log("GravityValve:SetActive "..tostring(bActive).." on valve "..self:GetName())
	if bActive == 1 then
		if (self.Properties.bSpline == 1) then

			local Area = self._PhysTableSpl.Area;
			local splinePoints = self._PhysTableSpl.Area.points;

			for p = 1, n do
				splinePoints[p] = {x=0,y=0,z=0};
				Points[p]:GetWorldPos(splinePoints[p]);
				--Log("Gravity Stream point "..p..":"..Vec2Str(splinePoints[p]));
			end

			Area.type = AREA_SPLINE;
			Area.radius = self.Properties.Radius;
			--Area.uniform = 1;
			Area.falloff = 0;
			Area.gravity = {x=0,y=0,z=self.Properties.Strength};
			Area.damping = 2.0;

			self:Physicalize(0, PE_AREA, self._PhysTableSpl);

			self:SetPhysicParams(PHYSICPARAM_FOREIGNDATA,{foreignData = ZEROG_AREA_ID});
		else
			local params = {}
			params.class = "GravityStreamCap"
			params.orientation = {x=1,y=0,z=0}

			for p = 2, n do
				self:CreateCylinderArea( Points[p-1]:GetPos(), Points[p]:GetPos(), self.Properties.Radius, self.Properties.Strength )
				Points[p]:Physicalize(0, PE_AREA, self._PhysTableCyl)

				Points[p]:SetPhysicParams(PHYSICPARAM_FOREIGNDATA,{foreignData = ZEROG_AREA_ID});

				if p > 2 then
					params.position = Points[p-1]:GetPos()
					local ent = System.SpawnEntity( params )
					table.insert( Caps, ent.id )
					self:CreateSphereArea( self.Properties.Radius, self._PhysTableCyl.Area.gravity )
					ent:Physicalize(0, PE_AREA, self._PhysTableSph)

					ent:SetPhysicParams(PHYSICPARAM_FOREIGNDATA,{foreignData = ZEROG_AREA_ID});
				end
			end
		end
	elseif bActive == 0 and self.bActive then

		self:DestroyPhysics();

		for p = 2, n do
			Points[p]:DestroyPhysics()
		end

		self:OnDestroy()
	end
	self.bActive = bActive
end

function GravityValve:Event_Enable()
	--Log("GravityValve: GetEnable")
	self:SetActive(1)
end

function GravityValve:Event_Disable()
	--Log("GravityValve: GetDisable")
	self:SetActive(0)
end

GravityValve.FlowEvents =
{
	Inputs =
	{
		Disable = { GravityValve.Event_Disable, "bool" },
		Enable = { GravityValve.Event_Enable, "bool" },
	},
	Outputs =
	{
		Disable = "bool",
		Enable = "bool",
	},
}
