-- cylinders
-- Spezi für einfache Hydraulikcylinders oder cylinders aller Arten
-- Ebenfalls sind einfache setDirections möglich

-- V2 Rotations die von einem Objekt ausgehend die Bewegung auf ein anderes übertragen sind nun auch möglich.
-- Damit kann man nun die komplette Animation einer Lenkung oder einer Heckhydraulik hierüber laufen lassen!

-- by modelleicher


cylinderedV3 = {};

function cylinderedV3.prerequisitesPresent(specializations)
    return true;
end;


function cylinderedV3.registerEventListeners(vehicleType)
	SpecializationUtil.registerEventListener(vehicleType, "onLoad", cylinderedV3);
	SpecializationUtil.registerEventListener(vehicleType, "onUpdate", cylinderedV3);
end;


function cylinderedV3:onLoad(savegame)
	self.updateCylinderedV3 = cylinderedV3.updateCylinderedV3;
	
	self.spec_cylinderedV3 = {};  -- creating the table where all the variables are stored in
	local spec = self.spec_cylinderedV3; 

	local xmlFile = self.xmlFile;
	
	local path = "vehicle.cylinderedV3.";
	
	spec.cylinders = {};
	local i = 0;
	while true do
		local cyl = {};
		cyl.dir1 = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, path.."cylinders.cylinder("..i..")#dir1"), self.i3dMappings);
		cyl.dir2 = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, path.."cylinders.cylinder("..i..")#dir2"), self.i3dMappings);
		if cyl.dir1 ~= nil and cyl.dir2 ~= nil then
			table.insert(spec.cylinders, cyl);
		else
			break;
		end;
		i = i+1;
	end;
		
    spec.rotations = {};
	i = 0;
	while true do	
		local rot = {};
		local path1 = path.."rotations.rotation("..i..")"
		rot.index = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, path1 .. "#node"), self.i3dMappings);
		if rot.index == nil or rot.index == "" then
			break;
		end;		
		rot.ref = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, path1 .. "#ref"), self.i3dMappings);
		rot.addDegrees = Utils.getNoNil(getXMLFloat(xmlFile, path1 .. "#addDegrees"), 0.0);
		rot.rotAxis = string.lower(Utils.getNoNil(getXMLString(xmlFile, path1 .. "#rotAxis"), "x"));
		rot.getRotAxis = string.lower(Utils.getNoNil(getXMLString(xmlFile, path1 .. "#getRotAxis"), "y"));
		rot.lengthMultiplicator = Utils.getNoNil(getXMLFloat(xmlFile, path1 .. "#lengthMultiplicator"), 1);		
		table.insert(spec.rotations, rot);
		i = i+1;
	end;

        
		
    spec.directions = {};
	i = 0;
	while true do	
		local dir = {};
		local path1 = path.."directions.direction("..i..")"
		dir.index = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, path1 .. "#node"), self.i3dMappings);
		if dir.index == nil or dir.index == "" then
			break;
		end;		
		dir.ref = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, path1 .. "#ref"), self.i3dMappings);
		dir.doScaleBool = Utils.getNoNil(getXMLBool(xmlFile, path1 .. "#doScaleBool"));
		if dir.doScaleBool == true then
			dir.scaleRef = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, path1 .. "#scaleRef"), self.i3dMappings);            
			local ax, ay, az = getWorldTranslation(dir.index);
			local bx, by, bz = getWorldTranslation(dir.scaleRef);
			dir.scaleDistance = MathUtil.vector3Length(ax-bx, ay-by, az-bz);    
		end;
		table.insert(spec.directions, dir);
		i = i+1;
    end;
	
	spec.scaleOnlys = {};
	i = 0;
	while true do
		local scaleOnly = {};
		local path1 = path.."scaleOnlys.scaleOnly("..i..")"	
		scaleOnly.index = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, path1 .. "#node"), self.i3dMappings);
		scaleOnly.ref = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, path1 .. "#ref"), self.i3dMappings);
		if scaleOnly.index == nil or scaleOnly.index == "" then
			break;
		end;	
		local ax, ay, az = getWorldTranslation(scaleOnly.index);
		local bx, by, bz = getWorldTranslation(scaleOnly.ref);
		scaleOnly.scaleDistance = MathUtil.vector3Length(ax-bx, ay-by, az-bz);
		table.insert(spec.scaleOnlys, scaleOnly);
		i = i+1;		
	end;	
	
		
	self:updateCylinderedV3();
	
end;

function cylinderedV3:updateCylinderedV3()

	local spec = self.spec_cylinderedV3;

	if #spec.cylinders > 0 then
		for i=1, #spec.cylinders do
			if spec.cylinders[i].dir1 ~= nil and spec.cylinders[i].dir2 ~= nil then
			local ax, ay, az = getWorldTranslation(spec.cylinders[i].dir1);
			local bx, by, bz = getWorldTranslation(spec.cylinders[i].dir2);
			x, y, z = worldDirectionToLocal(getParent(spec.cylinders[i].dir1), bx-ax, by-ay, bz-az);
			local upx, upy, upz = 0,1,0;
			if math.abs(y) > 0.99*MathUtil.vector3Length(x, y, z) then
				upy = 0;
				if y > 0 then
					upy = 1;
				else
					upy = -1;
				end;
			end;
			setDirection(spec.cylinders[i].dir1, x, y, z, upx, upy, upz);
			local ax2, ay2, az2 = getWorldTranslation(spec.cylinders[i].dir2);
			local bx2, by2, bz2 = getWorldTranslation(spec.cylinders[i].dir1);
			x2, y2, z2 = worldDirectionToLocal(getParent(spec.cylinders[i].dir2), bx2-ax2, by2-ay2, bz2-az2);
			local upx2, upy2, upz2 = 0,1,0;
			if math.abs(y2) > 0.99*MathUtil.vector3Length(x, y, z) then
				upy2 = 0;
				if y2 > 0 then
					upy2 = 1;
				else
					upy2 = -1;
				end;
			end;
			setDirection(spec.cylinders[i].dir2, x2, y2, z2, upx, upy, upz); 
			end;
		end;
	end;
	
	
	if #spec.rotations > 0 then
		for i=1, #spec.rotations do
			--print("rotations count");
			if spec.rotations[i].index ~= nil and spec.rotations[i].ref ~= nil then
				local rx, ry, rz = getRotation(spec.rotations[i].ref);
				local rw = 0;
				if spec.rotations[i].getRotAxis == "y" then -- ask first for y because it is the most used in this case (for performance reasons)
					rw = ry*spec.rotations[i].lengthMultiplicator;
				elseif spec.rotations[i].getRotAxis == "x" then
					rw = rx*spec.rotations[i].lengthMultiplicator;
				elseif spec.rotations[i].getRotAxis == "z" then
					rw = rz*spec.rotations[i].lengthMultiplicator;
				end;
				if spec.rotations[i].rotAxis == "x" then -- ask first for x because it is the most used in this case(for performance reasons)
					setRotation(spec.rotations[i].index, rw+math.rad(spec.rotations[i].addDegrees), 0, 0);
				elseif spec.rotations[i].rotAxis == "y" then
					setRotation(spec.rotations[i].index, 0, rw+math.rad(spec.rotations[i].addDegrees), 0);
				elseif spec.rotations[i].rotAxis == "z" then
					setRotation(spec.rotations[i].index, 0, 0, rw+math.rad(spec.rotations[i].addDegrees));
				end;
			end;
		end;
	end;
	if #spec.directions > 0 then
		for i=1, #spec.directions do
			if spec.directions[i].index ~= nil and spec.directions[i].ref ~= nil then
				local ax, ay, az = getWorldTranslation(spec.directions[i].index);
				local bx, by, bz = getWorldTranslation(spec.directions[i].ref);
				x, y, z = worldDirectionToLocal(getParent(spec.directions[i].index), bx-ax, by-ay, bz-az);
				local upx, upy, upz = 0,1,0;
				if math.abs(y) > 0.99*MathUtil.vector3Length(x, y, z) then
					upy = 0;
					if y > 0 then
						upy = 1;
					else
						upy = -1;
					end;
				end;
				setDirection(spec.directions[i].index, x, y, z, upx, upy, upz);
				if spec.directions[i].doScaleBool == true and spec.directions[i].scaleRef ~= nil then
					local distance = MathUtil.vector3Length(ax-bx, ay-by, az-bz);
					local scaleX, scaleY, scaleZ = getScale(spec.directions[i].index);
					local setScaleWert = scaleZ * (distance / spec.directions[i].scaleDistance);
					setScale(spec.directions[i].index, 1, 1, setScaleWert);
				end;
			end;
		end;
	end;
	if #spec.scaleOnlys > 0 then
		for i=1, #spec.scaleOnlys do
			if spec.scaleOnlys[i].index ~= nil and spec.scaleOnlys[i].ref ~= nil then
				local ax, ay, az = getWorldTranslation(spec.scaleOnlys[i].index);
				local bx, by, bz = getWorldTranslation(spec.scaleOnlys[i].ref);
				local scaleDistance = MathUtil.vector3Length(ax-bx, ay-by, az-bz);
				setScale(spec.scaleOnlys[i].index, 1, 1/(spec.scaleOnlys[i].scaleDistance/scaleDistance), 1);
			end;
		end;
	end;	

end;

function cylinderedV3:onUpdate(dt) 
	if self:getIsActive() then
		self:updateCylinderedV3();
	end;
end;
