--
-- Ropa PR-XL
--
-- @author: 	Burner
-- @date: 		29.04.2013
--

PR_XL = {};

function PR_XL.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Cutter, specializations) and SpecializationUtil.hasSpecialization(FruitPreparer, specializations);
end;

function PR_XL:load(xmlFile)
	self.getIsFoldAllowed = Utils.overwrittenFunction(self.getIsFoldAllowed, PR_XL.getIsFoldAllowed);
	self.attachToTrailer = PR_XL.attachToTrailer;
	self.detachFromTrailer = PR_XL.detachFromTrailer;
	self.isThreshing = false;
	self.cutterSpeedRotatingPartsNew = self.cutterSpeedRotatingParts;
	self.cutterSpeedRotatingParts = {};
	self.transportAttacherJoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.transportAttacherJoint#index"));
	self.trailerJoint = {};
	self.lastTrailer = nil;
	self.isAttachedToTrailer = false;
	self.first = true;
	self.trailerToAttachFromSaveId = nil;
	self.trailerToAttachFromSave = {};
	self.trailerToAttachFromSave.id = nil;
	self.trailerToAttachFromSave.vehicle = nil;
	self.trailerToAttachFromSave.time = 0;
	
	self.threshingParticleSystems = {};
    local i = 0;
    while true do
        local namei = string.format("vehicle.threshingParticleSystems.threshingParticleSystem(%d)", i);
		local nodei = Utils.indexToObject(self.components, getXMLString(xmlFile, namei .. "#index"));
		if nodei == nil then
			break;
		end;
		local isStatic = Utils.getNoNil(getXMLBool(xmlFile, namei.."#static"), false);
		if isStatic then
			StaticParticleSystem.loadParticleSystem(xmlFile, self.threshingParticleSystems, namei, nodei, false, nil, self.baseDirectory);
		else
			Utils.loadParticleSystem(xmlFile, self.threshingParticleSystems, namei, nodei, false, nil, self.baseDirectory);
		end;
		Utils.setEmittingState(self.threshingParticleSystems,false);
		i = i +1;		
    end;
end;

function PR_XL:getSaveAttributesAndNodes(nodeIdent)
	local trailerId = 0;
	if self.trailerJoint.vehicle ~= nil then
		for k, vehicle in pairs(g_currentMission.attachables) do
			if vehicle == self.trailerJoint.vehicle then
				trailerId = k;
			end;
		end
	end
	local attributes = 'attachedTrailerId="'.. tostring(trailerId) ..'"';
	return attributes, nil;
end;

function PR_XL:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	local trailerId =  Utils.getNoNil(getXMLInt(xmlFile, key.."#attachedTrailerId"),0);
	if trailerId ~= 0 then
		self.trailerToAttachFromSave.id = trailerId;
	end;
	return BaseMission.VEHICLE_LOAD_OK;
end;

function PR_XL:readStream(streamId, connection)
	local isAttachedToTrailer = streamReadBool(streamId);
	if isAttachedToTrailer then
		local vehicleId = streamReadInt32(streamId);
		vehicleId = networkGetObject(vehicleId);
		self:attachToTrailer(vehicleId, true);
	end;
end;

function PR_XL:writeStream(streamId, connection)
	streamWriteBool(streamId, self.isAttached);
	if self.isAttachedToTrailer then
		streamWriteInt32(streamId, networkGetObjectId(self.trailerJoint.vehicle));
	end;
end;

function PR_XL:delete()
end;

function PR_XL:readStream(streamId, connection)  
end;

function PR_XL:writeStream(streamId, connection)  
end;

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

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

function PR_XL:update(dt)
	if self.trailerToAttachFromSave.id ~= nil and self.isServer then
		for k, vehicle in pairs(g_currentMission.attachables) do
			if k == self.trailerToAttachFromSave.id then
				self.trailerToAttachFromSave.mass = getMass(vehicle.rootNode);
				setMass(vehicle.rootNode, 50);
				self:attachToTrailer(vehicle);
				self.trailerToAttachFromSave.vehicle = vehicle;
				self.trailerToAttachFromSave.id = nil;
			end;
		end
	end;
	
	if self.trailerToAttachFromSave.vehicle ~= nil and self.isServer then
		self.trailerToAttachFromSave.time = self.trailerToAttachFromSave.time + dt;
		if self.trailerToAttachFromSave.time > 1000 then
			setMass(self.trailerToAttachFromSave.vehicle.rootNode, self.trailerToAttachFromSave.mass);
			self.trailerToAttachFromSave = {};
		end;
	end;
	
	if self:getIsActiveForInput(false) then
		if self.lastTrailer ~= nil then 
			if not self.isAttachedToTrailer then
				if InputBinding.hasEvent(InputBinding.RopaEuroTiger_AttachToTrailer) then					
					self:attachToTrailer(self.lastTrailer);
				end;
			end;
		else
			if self.isAttachedToTrailer then
				if InputBinding.hasEvent(InputBinding.RopaEuroTiger_AttachToTrailer) then	
					self:detachFromTrailer();
				end;
			end;
		end;
	end;
end;

function PR_XL:updateTick(dt)
	self.isThreshing = self.reelStarted;
	
	if self.cutterAllowCuttingWhileRaised or self:isLowered(true) and self.attacherVehicle ~= nil then
		local foldAnimTime = self.foldAnimTime;
		for k,v in pairs(self.cutterSpeedRotatingPartsNew) do
			if foldAnimTime == nil or (foldAnimTime <= v.foldMaxLimit and foldAnimTime >= v.foldMinLimit) then
				rotate(v.node, v.rotationSpeedScale * self.lastSpeedReal * self.movingDirection * dt, 0, 0);
			end
		end
	end

	if self:getIsActiveForInput(false) and self.transportAttacherJoint ~= nil and not self.isAttachedToTrailer then
		self.lastTrailer = nil;
		for k, attachable in pairs(g_currentMission.attachables) do
			if attachable.transportAttacherJoint ~= nil and attachable ~= self then
				local px, py, pz = getWorldTranslation(self.transportAttacherJoint);
				local vx, vy, vz = getWorldTranslation(attachable.transportAttacherJoint);
				local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
				if distance <= 0.3 then
					self.lastTrailer = attachable;
				end;
			end;
		end;
	end;
	
	if self.attacherVehicle ~= nil then
		for _,light in pairs(self.lights) do
			if light.decoration ~= nil then
				setVisibility(light.decoration, self.attacherVehicle.B3["work"][1].a or self.attacherVehicle.lightsState == 1);
			end
		end
	end;
end;

function PR_XL:attachToTrailer(vehicleId,noEventSend,vehicle)
	attachToTrailerEvent.sendEvent(self, vehicleId, noEventSend);
	local joint = self.trailerJoint;
	joint.vehicle = vehicleId;
	if self:getIsActiveForSound() then
		self:playAttachSound();
	end;
	if self.attacherVehicle ~= nil then
		self.attacherVehicle:detachImplementByObject(self);
	end;
	if self.isServer then
		local constr = JointConstructor:new();					
		constr:setActors(self.rootNode, vehicleId.rootNode);
		constr:setJointTransforms(self.transportAttacherJoint, vehicleId.transportAttacherJoint);
		for i=1, 3 do
			constr:setTranslationLimit(i-1, true, 0, 0);
			constr:setRotationLimit(i-1, 0, 0);
		end;
		joint.index = constr:finalize();
	end;
	self.isAttachedToTrailer = true;
	self.lastTrailer = nil;
end;

function PR_XL:detachFromTrailer(noEventSend)
	detachFromTrailerEvent.sendEvent(self, noEventSend);
	if self.isServer then
		removeJoint(self.trailerJoint.index);	
	end;
	self.trailerJoint = nil;
	self.trailerJoint = {};
	self.isAttachedToTrailer = false;
end;

function PR_XL:getIsFoldAllowed(superFunc)
	local motorStarted = true;
	if self.attacherVehicle ~= nil then
		motorStarted = self.attacherVehicle.isMotorStarted;
	end;
	if superFunc ~= nil then
		return superFunc(self) and not self.reelStarted and motorStarted;
	end
	return not self.reelStarted and motorStarted;
end

function PR_XL:draw()
end;

function PR_XL:onAttach(attacherVehicle)
	if self.isAttachedToTrailer then
		self:detachFromTrailer();
	end;
	self.attacherVehicle.fruitPreparerFruitType = self.fruitPreparerFruitType;
end

attachToTrailerEvent = {};
attachToTrailerEvent_mt = Class(attachToTrailerEvent, Event);

InitEventClass(attachToTrailerEvent, "attachToTrailerEvent");

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

function attachToTrailerEvent:new(object, vehicleId)
    local self = attachToTrailerEvent:emptyNew()
    self.object = object;
	self.vehicleId = vehicleId;
    return self;
end;

function attachToTrailerEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	local vehicleId = streamReadInt32(streamId);
    self.object = networkGetObject(id);
	self.vehicleId = networkGetObject(vehicleId);
    self:run(connection);
end;

function attachToTrailerEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.object));
	streamWriteInt32(streamId, networkGetObjectId(self.vehicleId));
end;

function attachToTrailerEvent:run(connection)   
	self.object:attachToTrailer(self.vehicleId, true, self.object);
    if not connection:getIsServer() then
        g_server:broadcastEvent(attachToTrailerEvent:new(self.object, self.vehicleId), nil, connection, self.object);
    end;
end;

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

detachFromTrailerEvent = {};
detachFromTrailerEvent_mt = Class(detachFromTrailerEvent, Event);

InitEventClass(detachFromTrailerEvent, "detachFromTrailerEvent");

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

function detachFromTrailerEvent:new(object)
    local self = detachFromTrailerEvent:emptyNew()
    self.object = object;
    return self;
end;

function detachFromTrailerEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);	
    self.object = networkGetObject(id);
    self:run(connection);
end;

function detachFromTrailerEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.object));
end;

function detachFromTrailerEvent:run(connection)   
	self.object:detachFromTrailer(true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(detachFromTrailerEvent:new(self.object), nil, connection, self.object);
    end;
end;

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