--
-- LemkenAchatZ8
-- Specialization for deep control, changable tine direction, "work" forces (based on PES 4ever's lua)
--
-- @author  	Stefan Maurus
-- @version 	v1.0
-- @date  		25.03.2014
--

LemkenAchatZ8 = {};

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

function LemkenAchatZ8:load(xmlFile)
	self.getIsAreaActive = Utils.overwrittenFunction(self.getIsAreaActive, LemkenAchatZ8.getIsAreaActive);	
	self.changeTineDir = SpecializationUtil.callSpecializationsFunction("changeTineDir");

	self.changePoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tines#changePoint"));
	self.isInRange = false;
	self.startRot = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.tines#startRot"), 0));
	self.endRot = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.tines#endRot"), 180));
	self.startTrans = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.tines#startTrans"), 0);
	self.endTrans = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.tines#endTrans"), 0);
	self.isChanged = false;
	
	local i = 0;
	self.tines = {};
	while true do
        local key = string.format("vehicle.tines.tine(%d)", i);
		if not hasXMLProperty(xmlFile, key) then
			break;
		end;
		local index = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));

		table.insert(self.tines, {index=index});
		i = i + 1;
	end;

	self.topArmBaseNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.attacherJoints.attacherJoint.topArm#baseNode"));	
	setVisibility(self.topArmBaseNode, false);
	
	self.dirtGroundParticleSystem = {};
    local i = 0;
    while true do
        local systemi = string.format("vehicle.dirtGroundParticleSystem.system(%d)", i);
		local indexi = Utils.indexToObject(self.components, getXMLString(xmlFile, systemi .. "#index"));
		if indexi == nil then
			break;
		end; 
        Utils.loadStaticParticleSystem(xmlFile, self.dirtGroundParticleSystem, systemi, indexi, false, nil, self.baseDirectory)		
		i = i +1;		
    end;
end;

function LemkenAchatZ8:delete()
end;

function LemkenAchatZ8:readStream(streamId, connection)
	self:changeTineDir(streamReadBool(streamId), true);
end;

function LemkenAchatZ8:writeStream(streamId, connection) 
	streamWriteBool(streamId, self.isChanged); 
end;

function LemkenAchatZ8:changeTineDir(bool, noEventSend)	
	self.isChanged = bool;
	if self.isChanged then
		for _, tine in pairs(self.tines) do
			local x, _, z = getRotation(tine.index);
			setRotation(tine.index, x, self.endRot, z);
			local x1,y,_ = getTranslation(tine.index);
			setTranslation(tine.index, x1, y, self.endTrans);
		end;
		setRotation(self.groundReferenceNodes[1].depthNode, 0,math.rad(180),0)
	else
		for _, tine in pairs(self.tines) do
			local x, _, z = getRotation(tine.index);
			setRotation(tine.index, x, self.startRot, z);
			local x1,y,_ = getTranslation(tine.index);
			setTranslation(tine.index, x1, y, self.startTrans);
		end;
		setRotation(self.groundReferenceNodes[1].depthNode, 0,math.rad(0),0)
	end;
	ChangeTineDirEvent.sendEvent(self, bool, noEventSend);
end;

function LemkenAchatZ8:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	self:changeTineDir(Utils.getNoNil(getXMLBool(xmlFile, key .. "#tineDir"), false));

	return BaseMission.VEHICLE_LOAD_OK;
end;
 
function LemkenAchatZ8:getSaveAttributesAndNodes(nodeIdent)
	local attributes = 'tineDir="'..tostring(self.isChanged)..'"';
	return attributes, nil;
end;

function LemkenAchatZ8:mouseEvent(posX, posY, isDown, isUp, button)
end;

function LemkenAchatZ8:keyEvent(unicode, sym, modifier, isDown)
end;

function LemkenAchatZ8:getIsAreaActive(superFunc, area)
    if superFunc ~= nil then
        return superFunc(self, area) and ((self.isChanged and self.movingDirection < 1) or (not self.isChanged and self.movingDirection > -1));
    end;
	return ((self.isChanged and self.movingDirection < 0) or (not self.isChanged and self.movingDirection > 0));
end;

function LemkenAchatZ8:update(dt)
	if self.isInRange then
		g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SWITCH_TINES")), InputBinding.IMPLEMENT_EXTRA2);
		if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then
			self:changeTineDir(not self.isChanged);	
		end;
	end;
end;

function LemkenAchatZ8:updateTick(dt)
	if self.cultivatorHasGroundContact and self:isLowered() and ((self.isChanged and self.movingDirection < 0) or (not self.isChanged and self.movingDirection > 0)) and self.lastSpeed*3600 > 1 then
		Utils.setEmittingState(self.dirtGroundParticleSystem, true);
	else
		Utils.setEmittingState(self.dirtGroundParticleSystem, false);		
	end;

	if g_currentMission.player ~= nil then
		local nearestDistance = 3;
		local x1, y1, z1 = getWorldTranslation(self.changePoint);
		local x2, y2, z2 = getWorldTranslation(g_currentMission.player.rootNode);
		local distance = Utils.vector3Length(x1-x2, y1-y2, z1-z2);
		if distance < nearestDistance then
			self.isInRange = true;
		else
			self.isInRange = false;
		end;
	end;
end;

function LemkenAchatZ8:draw()
end;

function LemkenAchatZ8:onAttach()
end;

function LemkenAchatZ8:onDetach()	
end; 

function LemkenAchatZ8:detachImplement(implement, implementIndex)
	setVisibility(self.topArmBaseNode, false);
end;

function LemkenAchatZ8:attachImplement(implement, implementIndex, object, jointDescIndex)
	setVisibility(self.topArmBaseNode, true);
end;

Utils.loadStaticParticleSystem = function(xmlFile, psTable, baseString, linkNode, defaultEmittingState, filename, baseDirectory)
	--
	-- Static Particle System
	--
	-- Author:  Heady | www.planet-ls.de
	-- Date: 30.04.2011
	--
	--
	
	local defaultLinkNode = linkNode;
		if type(linkNode) == "table" then
			defaultLinkNode = linkNode[1].node;
		end;
	local linkNode = Utils.getNoNil(Utils.indexToObject(linkNode, getXMLString(xmlFile, baseString .. "#node")), defaultLinkNode);

	local psFile = getXMLString(xmlFile, baseString .. "#file");
	if psFile == nil then
		psFile = filename;
	end;
	if psFile == nil then
		return;
	end;
	psFile = Utils.getFilename(psFile, baseDirectory);  
	local rootNode = loadI3DFile(psFile);
	if rootNode == 0 then
		print("Error: failed to load particle system " .. psFile);
		return;
	end	
	
	link(linkNode, rootNode)	

	local posString = getXMLString(xmlFile, baseString .. "#position");
	if posString ~= nil then
		local posX, posY, posZ = Utils.getVectorFromString(posString);
		setTranslation(rootNode, posX, posY, posZ);
	end;	
	local rotString = getXMLString(xmlFile, baseString .. "#rotation");
	if rotString ~= nil then
		local rotX, rotY, rotZ = Utils.getVectorFromString(rotString);
		rotX = Utils.degToRad(rotX);
		rotY = Utils.degToRad(rotY);
		rotZ = Utils.degToRad(rotZ);
		setRotation(rootNode, rotX, rotY, rotZ);
	end;

	for i=1, getNumOfChildren(rootNode) do
		local child = getChildAt(rootNode, i-1);
		if getClassName(child) == "Shape" then
			local geometry = getGeometry(child);
			if geometry ~= 0 and getClassName(geometry) == "ParticleSystem" then
				table.insert(psTable, {geometry = geometry, shape = child});
				if defaultEmittingState ~= nil then
					setEmittingState(geometry, defaultEmittingState);
				end;
			end;
		end;
	end;

	return rootNode;
end;

----changeTineDir Event----

ChangeTineDirEvent = {};
ChangeTineDirEvent_mt = Class(ChangeTineDirEvent, Event);

InitEventClass(ChangeTineDirEvent, "ChangeTineDirEvent");

function ChangeTineDirEvent:emptyNew()
    local self = Event:new(ChangeTineDirEvent_mt);
    self.className="ChangeTineDirEvent";
    return self;
end;

function ChangeTineDirEvent:new(vehicle, isChanged)
    local self = ChangeTineDirEvent:emptyNew()
    self.vehicle = vehicle;
	self.isChanged = isChanged;
    return self;
end;

function ChangeTineDirEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
    self.vehicle = networkGetObject(id);

	self.isChanged = streamReadBool(streamId);
	self.vehicle:changeTineDir(self.isChanged, true);
	
	if not connection:getIsServer() then
        g_server:broadcastEvent(ChangeTineDirEvent:new(self.vehicle, self.isChanged), nil, connection, self.vehicle);
    end;
end;

function ChangeTineDirEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteBool(streamId, self.isChanged);
end;

function ChangeTineDirEvent.sendEvent(vehicle, isChanged, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(ChangeTineDirEvent:new(vehicle, isChanged), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(ChangeTineDirEvent:new(vehicle, isChanged));
		end;
	end;
end;