--
-- FAP_ConnectedVehicle
--
-- @autor nilBrain
-- @date 09/01/2021
-- Copyright (C) nilBrain, Confidential, All Rights Reserved.


FAP_ConnectedVehicle = {};

FAP_ConnectedVehicle.modName = FapRegister.modName;
FAP_ConnectedVehicle.modDir = FapRegister.modDir;
FAP_ConnectedVehicle.DEFAULT_CONNECTOR_XML = FAP_ConnectedVehicle.modDir .. "assets/fapConnector.xml";

function FAP_ConnectedVehicle.prerequisitesPresent(specializations)
	return SpecializationUtil.hasSpecialization(ManureBarrel, specializations);
end;

function FAP_ConnectedVehicle.registerFunctions(vehicleType)
	SpecializationUtil.registerFunction(vehicleType, "loadFapConector", FAP_ConnectedVehicle.loadFapConector);
	SpecializationUtil.registerFunction(vehicleType, "loadFapFromDefaultXML", FAP_ConnectedVehicle.loadFapFromDefaultXML);
	SpecializationUtil.registerFunction(vehicleType, "setFapPump", FAP_ConnectedVehicle.setFapPump);
	SpecializationUtil.registerFunction(vehicleType, "canCoppleFapHose", FAP_ConnectedVehicle.canCoppleFapHose);
	SpecializationUtil.registerFunction(vehicleType, "getFapManureReferenceNode", FAP_ConnectedVehicle.getFapManureReferenceNode);
	SpecializationUtil.registerFunction(vehicleType, "getFapHydraulicReferenceNode", FAP_ConnectedVehicle.getFapHydraulicReferenceNode);
end;

function FAP_ConnectedVehicle.registerEventListeners(vehicleType)
	SpecializationUtil.registerEventListener(vehicleType, "onLoad", FAP_ConnectedVehicle);
	SpecializationUtil.registerEventListener(vehicleType, "onPostAttach", FAP_ConnectedVehicle);
	SpecializationUtil.registerEventListener(vehicleType, "onPostDetach", FAP_ConnectedVehicle);
end;

function FAP_ConnectedVehicle.initSpecialization()
	local schema = Vehicle.xmlSchema

	schema:setXMLSpecializationType("FAP_ConnectedVehicle")
	--schema:register(XMLValueType.STRING, "vehicle.fapConnectedVehicle#fapManureReferenceNode", "Target actions on given nodes");
	--schema:register(XMLValueType.STRING, "vehicle.fapConnectedVehicle#fapHydraulcReferenceNode", "Target actions on given nodes");


	schema:register(XMLValueType.NODE_INDEX, "vehicle.fapConnectedVehicle#fapManureReferenceNode", "GuidanceSteering rootNode");
    schema:register(XMLValueType.VECTOR_TRANS, "vehicle.fapConnectedVehicle#manureNodeOffset", "Offset");
	schema:register(XMLValueType.STRING, "vehicle.fapConnectedVehicle#connectorXml", "Offset");
	schema:register(XMLValueType.NODE_INDEX, "vehicle.fapConnectedVehicle#fapHydraulcReferenceNode", "GuidanceSteering rootNode");
	schema:register(XMLValueType.VECTOR_TRANS, "vehicle.fapConnectedVehicle#hydraulicNodeOffset", "Offset");

    schema:setXMLSpecializationType();
end;

function FAP_ConnectedVehicle:onLoad(savegame)
	self.spec_fapConnectedVehicle = self["spec_" .. FAP_ConnectedVehicle.modName .. ".fapConnectedVehicle"];
	if self.spec_fapConnectedVehicle == nil then
		self.spec_fapConnectedVehicle = self["spec_fapConnectedVehicle"];
	end;

	local spec = self.spec_fapConnectedVehicle;
	spec.fapPump = nil;
	spec.fapManureHoseRefNode = nil;
	spec.fapHydraulicHoseRefNode = nil;
	spec.connectorXml = FAP_ConnectedVehicle.DEFAULT_CONNECTOR_XML;
	spec.fapManureReference = {};
	spec.fapHydraulicReference = {};

	local xmlFile = nil
local _xmlPath = "TempFile"
if fileExists(_xmlPath) then
    xmlFile =  ( fileExists(_xmlPath) and loadXMLFile("TempFile", _xmlPath) or nil )
end;
	if xmlFile ~= nil then
		local i = 0
		while true do
			local key = string.format("defaultVehicles.vehicle(%d)", i);
			if not (xmlFile ~= nil and xmlFile:hasProperty(key)) then
				break;
			end;

			local modName = xmlFile:getValue(key.."#modName");
			local vehicleXml = xmlFile:getValue(key.."#vehicleXml");

			if vehicleXml:lower() == self.configFileName:lower() then
				self:loadFapFromDefaultXML(xmlFile, key);
			end;
			i =i + 1;
		end;
	end;
	if xmlFile ~= nil then delete(xmlFile) end

	local fapManureNode = self.xmlFile:getValue("vehicle.fapConnectedVehicle#fapManureReferenceNode", nil, self.components, self.i3dMappings);
	spec.connectorXml =  self.xmlFile:getValue("vehicle.fapConnectedVehicle#connectorXml");
	self:loadFapConector();

	if fapManureNode ~= nil then
		spec.fapManureReference.node = fapManureNode;
		spec.fapManureReference.nodeOffset = self.xmlFile:getValue("vehicle.fapConnectedVehicle#manureNodeOffset");
	end;

	local fapHydraulicNode = self.xmlFile:getValue("vehicle.fapConnectedVehicle#fapHydraulcReferenceNode", nil, self.components, self.i3dMappings);
	if fapHydraulicNode ~= nil then
		spec.fapHydraulicReference.node = fapHydraulicNode;
		spec.fapHydraulicReference.nodeOffset = self.xmlFile:getValue("vehicle.fapConnectedVehicle#hydraulicNodeOffset");
	end;

	if self.spec_connectionHoses ~= nil then
		if self.spec_connectionHoses.targetNodes ~= nil then
			for _, targetNode in pairs(self.spec_connectionHoses.targetNodes) do
				if targetNode.type:upper() == "TRANSFER_HOSE" then
					spec.fantManureAdapterNode = targetNode.node
				end;
			end;
		end;
	end;
	if spec.fantManureAdapterNode ~= nil then
		if spec.fapManureReference.node ~= nil then
			setVisibility(spec.fapManureReference.node, false);
		end;
	end;
end;

function FAP_ConnectedVehicle:onPostAttach()
	local rootVehicle = self:getRootVehicle();
	if rootVehicle ~= nil and rootVehicle.spec_attacherJoints ~= nil then
		local spec = self.spec_fapConnectedVehicle;

		for attacherJointIndex, attacherJoint in pairs(rootVehicle.spec_attacherJoints.attacherJoints) do
			local implement = rootVehicle:getImplementByJointDescIndex(attacherJointIndex);
			if implement ~= nil and implement.object ~= nil and implement.object.spec_fapPump ~= nil then
				spec.fapPump = implement.object;
				spec.fapPump.spec_fapPump.parrentVehicle = self;
				break;
			end;
		end;

		if spec.fapPump ~= nil and self:canCoppleFapHose() then
			spec.fapPump:coppleManureHoseToSlurryTank();
		end;

	end;
end;

function FAP_ConnectedVehicle:onPostDetach()
	local spec = self.spec_fapConnectedVehicle;
	if spec.fapPump ~= nil then
		spec.fapPump:decoppleManureHoseToSlurryTank();
		spec.fapPump = nil;
	end;
end;

function FAP_ConnectedVehicle:loadFapConector()
	local spec = self.spec_fapConnectedVehicle;
	if spec.connectorXml ~= nil and fileExists(spec.connectorXml) then
		local xmlFile = nil
local _xmlPath = "TempFile"
if fileExists(_xmlPath) then
    xmlFile =  ( fileExists(_xmlPath) and loadXMLFile("TempFile", _xmlPath) or nil )
end;
		if xmlFile ~= nil then
			spec.Conectori3dFilename = Utils.getFilename(xmlFile:getValue("fapConnector#i3dFile"), FAP_ConnectedVehicle.modDir);

			local i3dNode = g_i3DManager:loadSharedI3DFile(spec.Conectori3dFilename, self.baseDirectory, false, false, false);
			if i3dNode ~= 0 then
				local conectorIndex = -1;
				local node = getChildAt(i3dNode, xmlFile:getValue("fapConnector.manureNode#index"));
				if node ~= nil then
					spec.fapManureReference.node = node;
					spec.fapManureReference.nodeAtCoupled = I3DUtil.indexToObject(i3dNode, xmlFile:getValue("fapConnector.manureNode#nodeAtCoupled"));
					if spec.fapManureReference.nodeAtCoupled ~= nil then
						setVisibility(spec.fapManureReference.nodeAtCoupled, false);
					end;
					spec.fapManureReference.nodeAtDecoupled = I3DUtil.indexToObject(i3dNode, xmlFile:getValue("fapConnector.manureNode#nodeAtDecoupled"));
					spec.fapManureReference.nodeOffset = {string.getVectorN(xmlFile:getValue("fapConnector.manureNode#nodeOffset"), 3)};
					conectorIndex = conectorIndex + 1;
					spec.fapManureReference.index = conectorIndex;
				end;

				spec.fapHydraulicReference.node = getChildAt(i3dNode, xmlFile:getValue("fapConnector.hydraulicNode#index"));
				if spec.fapHydraulicReference.node ~= nil then
					spec.fapHydraulicReference.nodeAtCoupled = I3DUtil.indexToObject(i3dNode, xmlFile:getValue("fapConnector.hydraulicNode#nodeAtCoupled"));
					if spec.fapHydraulicReference.nodeAtCoupled ~= nil then
						setVisibility(spec.fapHydraulicReference.nodeAtCoupled, false);
					end;
					spec.fapHydraulicReference.nodeAtDecoupled = I3DUtil.indexToObject(i3dNode, xmlFile:getValue("fapConnector.hydraulicNode#nodeAtDecoupled"));
					spec.fapHydraulicReference.nodeOffset = {string.getVectorN(xmlFile:getValue("fapConnector.hydraulicNode#nodeOffset"), 3)};
					conectorIndex = conectorIndex + 1;
					spec.fapHydraulicReference.index = conectorIndex;
				end;
				return i3dNode;
			end;
		end;
	end;
	return;
end;

function FAP_ConnectedVehicle:loadFapFromDefaultXML(xmlFile, key)
	local spec = self.spec_fapConnectedVehicle;
	local conectors = self:loadFapConector();

	local moveConnector = function(self, id, xmlFile, key)
		local linkNode = I3DUtil.indexToObject(self.components, xmlFile:getValue(key .. "#linkNode"), self.i3dMappings);
		link(linkNode, id);

		local x, y, z = unpack(string.getVectorN(xmlFile:getValue(key .. "#position"), 3) or {0,0,0});
		if x ~= nil and y ~= nil and z ~= nil then
			print(string.format("x='%s', y='%s', z='%s'", x, y, z))
			setTranslation(id, x, y, z);
		end;
	
		local rotX, rotY, rotZ = unpack(string.getVectorN(xmlFile:getValue(key .. "#rotation"), 3) or {0,0,0});

		if rotX ~= nil and rotY ~= nil and rotZ ~= nil then
			rotX = MathUtil.degToRad(rotX);
			rotY = MathUtil.degToRad(rotY);
			rotZ = MathUtil.degToRad(rotZ);
			setRotation(id, rotX, rotY, rotZ);
		end;
	end;

	if spec.fapManureReference ~= nil and spec.fapManureReference.node ~= nil then
		local childKey = string.format("%s.fapConnector.conectorIndex(%d)", key, spec.fapManureReference.index);
		moveConnector(self, spec.fapManureReference.node, xmlFile, childKey);
	end;

	if spec.fapHydraulicReference ~= nil and spec.fapHydraulicReference.node ~= nil then
		local childKey = string.format("%s.fapConnector.conectorIndex(%d)", key, spec.fapHydraulicReference.index);
		moveConnector(self, spec.fapHydraulicReference.node, xmlFile, childKey);
	end;
end;

function FAP_ConnectedVehicle:canCoppleFapHose()
	local spec = self.spec_fapConnectedVehicle;
	return spec.fapManureReference.node ~= nil or spec.fapHydraulicReference.node ~= nil or spec.fantManureAdapterNode ~= nil;
end;

function FAP_ConnectedVehicle:getFapManureReferenceNode()
	local spec = self.spec_fapConnectedVehicle;
	if spec.fantManureAdapterNode ~= nil then
		return spec.fantManureAdapterNode;
	end;

	return spec.fapManureReference.node;
end;

function FAP_ConnectedVehicle:getFapHydraulicReferenceNode()
	return self.spec_fapConnectedVehicle.fapHydraulicReference.node;
end;

function FAP_ConnectedVehicle:setFapPump(target)
	self.spec_fapConnectedVehicle.fapPump = target;
end;