--
-- Lexion770
-- Specialization for Lexion770
--
-- @author  	Manuel Leithner (SFM-Modding)
-- @version 	v1.0
-- @date  		14/12/11
-- @history:	v1.0 - Initial version
--
-- free for noncommerical-usage
--

Lexion770 = {};

function Lexion770.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(ChopperSwitcher, specializations);
end;

function Lexion770:load(xmlFile)
	
	self.setChopperWidthState = SpecializationUtil.callSpecializationsFunction("setChopperWidthState");
	self.getNewChopperRot = Lexion770.getNewChopperRot;
	
	self.maxRotTimeBackup = self.maxRotTime;
	self.minRotTimeBackup = self.minRotTime;
	for _, wheel in pairs(self.wheels) do
		wheel.rotMaxBackup = wheel.rotMax;
		wheel.rotMinBackup = wheel.rotMin;
	end;
	
	self.chopperRotatingParts = {};
	self.chopperRotatingParts.rotationParts = {};
	local i = 0;
	while true do
		local key = string.format("vehicle.chopperRotatingParts.rotationPart(%d)", i);
		local node = getXMLString(xmlFile, key .. "#node");
		if node == nil then
			break;
		end;
		local part = {};
		part.node = Utils.indexToObject(self.components, node);
		part.rotSpeed = getXMLFloat(xmlFile, key .. "#speed") * 1000;
		table.insert(self.chopperRotatingParts.rotationParts, part);
		i = i + 1;
	end;
	
	self.chopperRotatingParts.chopperParts = {};
	local i = 0;
	while true do
		local key = string.format("vehicle.chopperRotatingParts.chopperPart(%d)", i);
		local node = getXMLString(xmlFile, key .. "#node");
		if node == nil then
			break;
		end;
		local part = {};
		part.node = Utils.indexToObject(self.components, node);
		part.inverse = Utils.getNoNil(getXMLBool(xmlFile, key .. "#inverse"), false);
		part.states = {};
		part.currentMinRot = nil;
		part.currentMaxRot = nil;
		local j = 0;
		while true do
			local stateKey = string.format(key .. ".state(%d)", j);
			local minRot = getXMLFloat(xmlFile, stateKey .. "#minRot");
			if minRot == nil then
				break;
			end;
			local state = {};
			state.minRot = {math.rad(minRot)};
			if part.currentMinRot == nil then
				part.currentMinRot = {state.minRot[1]};
			end;
			state.maxRot = {math.rad(getXMLInt(xmlFile, stateKey .. "#maxRot"))};
			
			if part.currentMaxRot == nil then
				part.currentMaxRot = {state.maxRot[1]};
			end;
			state.speed = getXMLFloat(xmlFile, stateKey .. "#speed") * 1000;
			state.i18n = getXMLString(xmlFile, stateKey .. "#i18n");
			table.insert(part.states, state);
			j = j + 1;				
		end;		
		table.insert(self.chopperRotatingParts.chopperParts, part);
		i = i + 1;
	end;	
	self.radsPerMS = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.chopperRotatingParts#degreePerSecond"), 5) / 1000);
	self.chopperWidthState = 0;
	self.currentChopperDirection = -1;
	self.numChopperWidthStates = table.getn(self.chopperRotatingParts.chopperParts[1].states);
	self.chopperLeftDirectionTime = self.chopperRotatingParts.chopperParts[1].states[1].speed;
	
	
	
	-- chopper particle system
	self.addChopperParticleSystems = {};
	local i = 0;
	while true do
		local key = string.format("vehicle.addChopperParticleSystems.chopperParticleSystem(%d)", i);
		local t = getXMLString(xmlFile, key .. "#type");
		if t == nil then
			break;
		end;
		local desc = FruitUtil.fruitTypes[t];
		if desc ~= nil then
			local currentPS = {};

			local particleNode = Utils.loadParticleSystem(xmlFile, currentPS, key, self.components, false, "$data/vehicles/particleSystems/threshingChopperParticleSystem.i3d", self.baseDirectory);
			self.addChopperParticleSystems[desc.index] = currentPS;
			if self.addDefaultChopperParticleSystem == nil then
				self.addDefaultChopperParticleSystem = currentPS;
			end;
		end;
		i = i + 1;
	end;
	
	-- chopper dust particle system
	self.chopperDustParticleSystems = {};
	local i = 0;
	while true do
		local key = string.format("vehicle.chopperDustParticleSystems.chopperDustParticleSystem(%d)", i);
		local t = getXMLString(xmlFile, key .. "#type");
		if t == nil then
			break;
		end;
		local desc = FruitUtil.fruitTypes[t];
		if desc ~= nil then
			local currentPS = {};

			local particleNode = Utils.loadParticleSystem(xmlFile, currentPS, key, self.components, false, "$data/vehicles/particleSystems/threshingChopperParticleSystem.i3d", self.baseDirectory);
			self.chopperDustParticleSystems[desc.index] = currentPS;
			if self.defaultChopperDustParticleSystem == nil then
				self.defaultChopperDustParticleSystem = currentPS;
			end;
		end;
		i = i + 1;
	end;
	
	
	self.collector = {};
	self.collector.part = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.collector#index"));
	for _, part in pairs(self.movingParts) do
		if part.node == self.collector.part then
			self.collector.part = part;
		end;
	end;
	self.collector.partBackup = nil;
	self.collector.ref = nil;	
	
	self.specialJoint = {};
	self.specialJoint.index = getXMLInt(xmlFile, "vehicle.specialJoint#index");
	self.specialJoint.node = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.specialJoint#node"));
	self.specialJoint.rotNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.specialJoint#rotationNode"));
	self.specialJoint.rotNode2 = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.specialJoint#rotationNode2"));
	local joint = self.attacherJoints[self.specialJoint.index];
	self.specialJoint.rotNodeBackup = joint.rotationNode;
	self.specialJoint.rotNode2Backup = joint.rotationNode2;
	self.specialJoint.minRotBackup = joint.minRot;
	self.specialJoint.maxRotBackup = joint.maxRot;
	self.specialJoint.maxRotLimitBackup = joint.maxRotLimit;
	self.specialJoint.backup = joint.jointTransform;
	local x, y, z = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.specialJoint#maxRotLimit"));
	self.specialJoint.maxRotLimit = {};
	self.specialJoint.maxRotLimit[1] = math.rad(math.abs(Utils.getNoNil(x, 0)));
	self.specialJoint.maxRotLimit[2] = math.rad(math.abs(Utils.getNoNil(y, 0)));
	self.specialJoint.maxRotLimit[3] = math.rad(math.abs(Utils.getNoNil(z, 0)));	
	
	self.attachedCutter = {};
	
	self.threshingScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.threshingScale#value"), self.threshingScale);
	self.chopperLeftDirection = false;	
	
	self.lastStrawPSState = false;
	self.lastChopperPSState = false;
	self.maxNumRealLights = 3;
	
	self.isSelectable = true;
end;

function Lexion770:delete()
    for k,v in pairs(self.addChopperParticleSystems) do
        Utils.deleteParticleSystem(v);
    end;
	for k,v in pairs(self.chopperDustParticleSystems) do
        Utils.deleteParticleSystem(v);
    end;
end;

function Lexion770:readStream(streamId, connection)
	local state = streamReadInt8(streamId);
	self:setChopperWidthState(state, true);
end;

function Lexion770:writeStream(streamId, connection)
	streamWriteInt8(streamId, self.chopperWidthState);
end;

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

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

function Lexion770:update(dt)
	if self:getIsActive() then
		if self:getIsActiveForInput() and not self:hasInputConflictWithSelection() then
			if not self.isStrawActive and self.isThreshing then
				if InputBinding.hasEvent(InputBinding.SWITCH_CHOPPER_WIDTH) then			
					self:setChopperWidthState((self.chopperWidthState + 1) % (self.numChopperWidthStates));		
				end;
			end;
		end;	
	
		if self.collector.ref ~= nil then
			Cylindered.updateMovingPart(self, self.collector.part);	
		end;
	end;
end;

function Lexion770:updateTick(dt)
	if self:getIsActive() then
	
		for key, particle in pairs(self.addChopperParticleSystems) do
			Utils.setEmittingState(particle, Utils.getNoNil(self.chopperParticleSystems[key].isEmitting, false));
		end;
		for key, particle in pairs(self.chopperDustParticleSystems) do
			Utils.setEmittingState(particle, Utils.getNoNil(self.chopperParticleSystems[key].isEmitting, false));
		end;
		
		for _, part in pairs(self.movingParts) do
			Cylindered.updateMovingPart(self,  part);	
		end;
		
		if not self.isStrawActive and self.isThreshing then
			self.chopperLeftDirectionTime = self.chopperLeftDirectionTime - dt;
			
			for _, rotationPart in pairs(self.chopperRotatingParts.rotationParts) do
				rotate(rotationPart.node, 0, dt*rotationPart.rotSpeed, 0);
			end;
		
			for k, chopperPart in pairs(self.chopperRotatingParts.chopperParts) do
				local state = chopperPart.states[self.chopperWidthState+1];
				local x, y, z = getRotation(chopperPart.node);
				local dir = self.chopperLeftDirection;
				if chopperPart.inverse then
					dir = not self.chopperLeftDirection;
				end;
				local newRot = unpack(Utils.getMovedLimitedValues({y}, chopperPart.currentMaxRot, chopperPart.currentMinRot, 1, state.speed, dt, dir));
				setRotation(chopperPart.node, x, newRot, z);				
				chopperPart.currentMinRot[1] = self:getNewChopperRot(chopperPart.currentMinRot[1], state.minRot[1], dt);
				chopperPart.currentMaxRot[1] = self:getNewChopperRot(chopperPart.currentMaxRot[1], state.maxRot[1], dt);
				if k == 1 then
					if self.chopperLeftDirectionTime < 0 then
						self.chopperLeftDirection = not self.chopperLeftDirection;
						self.chopperLeftDirectionTime = state.speed;
					end;
				end;
			end;
		end;
	end;	
end;

function Lexion770:draw()	
	if self:getIsActive() then
		if self:getIsActiveForInput() then
			if not self.isStrawActive and self.isThreshing then
				local width = self.chopperRotatingParts.chopperParts[1].states[self.chopperWidthState+1].i18n;
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("SWITCH_CHOPPER_WIDTH_TEXT"), g_i18n:getText(width)), InputBinding.SWITCH_CHOPPER_WIDTH);
			end;
		end;
	end;
end;

function Lexion770:getNewChopperRot(currentRot, newRot, dt)
	if newRot < currentRot then
		return math.max(newRot, currentRot - (dt * self.radsPerMS));
	else
		return math.min(newRot, currentRot + (dt * self.radsPerMS));
	end;
end;

function Lexion770:setChopperWidthState(state, noEventSend)
	ChopperWidthEvent.sendEvent(self, state, noEventSend);	
	self.chopperWidthState = math.max(0, math.min(self.numChopperWidthStates - 1, state));
end;

function Lexion770:detachImplement(implementIndex)
	local object = self.attachedImplements[implementIndex].object;
	if object.attacherJoint.jointType == Vehicle.JOINTTYPE_CUTTER then
		object.speedLimit = self.attachedCutter.speedBackup;
		if object.vario1200 ~= nil then
			self.collector.ref = nil;
			self.collector.part.referencePoint = self.collector.part.node;
		end;		
		self.attachedCutter = {};
	end;
end;

function Lexion770:attachImplement(implement)
	local object  = implement.object;
	if object.attacherJoint.jointType == Vehicle.JOINTTYPE_CUTTER then
		self.attachedCutter.implement = object;
		self.attachedCutter.speedBackup = object.speedLimit;
		if object.vario1200 ~= nil then
			self.collector.ref = object.vario1200.fixpoint;
			self.collector.part.referencePoint = self.collector.ref;
		end;
	end;
end;

function Lexion770:onDeactivate()
    for k,v in pairs(self.addChopperParticleSystems) do
        Utils.setEmittingState(v, false);
    end;
	for k,v in pairs(self.chopperDustParticleSystems) do
        Utils.setEmittingState(v, false);
    end;
end;

function Lexion770:startThreshing()
	if self.numAttachedCutters > 0 then
		self.maxRotTime = self.maxRotTimeBackup / 0.75;
		self.minRotTime = self.minRotTimeBackup / 0.75;
		for _,wheel in pairs(self.wheels) do
			wheel.rotMax = wheel.rotMaxBackup / 0.75;
			wheel.rotMin = wheel.rotMinBackup / 0.75;
		end;
	end;
end;

function Lexion770:stopThreshing()
    for k,v in pairs(self.addChopperParticleSystems) do
        Utils.setEmittingState(v, false);
    end;
	for k,v in pairs(self.chopperDustParticleSystems) do
        Utils.setEmittingState(v, false);
    end;
	self.maxRotTime = self.maxRotTimeBackup;
	self.minRotTime = self.minRotTimeBackup;
	for _,wheel in pairs(self.wheels) do
		wheel.rotMax = wheel.rotMaxBackup;
		wheel.rotMin = wheel.rotMinBackup;
	end;
end;

local oldVehicleAttachImplement = Vehicle.attachImplement;
Vehicle.attachImplement = function(self, object, jointDescIndex, noEventSend, index, startLowered)	
	if self.specialJoint ~= nil then
		if self.specialJoint.index == jointDescIndex and object.specialJoint ~= nil then
			self.specialJoint.attachable = object;
			local joint = self.attacherJoints[self.specialJoint.index];
			joint.jointTransform = self.specialJoint.node;			
			joint.rotationNode = self.specialJoint.rotNode;
			joint.maxRot = { math.rad(33), math.rad(0), math.rad(0) };
			joint.minRot = { math.rad(20), math.rad(0), math.rad(0) };
			joint.rotationNode2 = self.specialJoint.rotNode2;
			joint.maxRotLimit = self.specialJoint.maxRotLimit;
			object.attacherJoint.node = object.specialJoint.node;
		end;
		oldVehicleAttachImplement(self, object, jointDescIndex, noEventSend, index, true);	
	else
		oldVehicleAttachImplement(self, object, jointDescIndex, noEventSend, index, startLowered);
	end;
end;

local oldVehicleDetachImplement = Vehicle.detachImplement;
Vehicle.detachImplement = function(self, implementIndex, noEventSend)
	local implement = self.attachedImplements[implementIndex];
	local index = nil;
	local object = nil;
	if implement ~= nil then
		index = implement.jointDescIndex;
		object = implement.object;
	end;
	oldVehicleDetachImplement(self, implementIndex, noEventSend);
	
	if implement ~= nil then
		if self.specialJoint ~= nil then
			if object.specialJoint ~= nil and self.specialJoint.index == index then
				local joint = self.attacherJoints[self.specialJoint.index];
				joint.jointTransform = self.specialJoint.backup;
				joint.rotationNode = self.specialJoint.rotNodeBackup;
				joint.rotationNode = self.specialJoint.rotNode2Backup;
				joint.maxRotLimit = self.specialJoint.maxRotLimitBackup;
				joint.minRot = self.specialJoint.minRotBackup;
				joint.maxRot = self.specialJoint.maxRotBackup;
				object.attacherJoint.node = object.specialJoint.backup;
			end;
		end;
	end;
end;

--
-- ChopperWidthEvent
-- Networkevent for Lexion770
--
-- @author  	Manuel Leithner (SFM-Modding)
-- @version 	v1.0
-- @date  		14/12/11
-- @history:	v1.0 - Initial version
--
ChopperWidthEvent = {};
ChopperWidthEvent_mt = Class(ChopperWidthEvent, Event);

InitEventClass(ChopperWidthEvent, "ChopperWidthEvent");

function ChopperWidthEvent:emptyNew()
    local self = Event:new(ChopperWidthEvent_mt);
    return self;
end;

function ChopperWidthEvent:new(vehicle, state)
    local self = ChopperWidthEvent:emptyNew()
    self.vehicle = vehicle;
	self.state = state;
    return self;
end;

function ChopperWidthEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.vehicle = networkGetObject(id);
	self.state = streamReadInt8(streamId);
    self:run(connection);
end;

function ChopperWidthEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));	
	streamWriteInt8(streamId, self.state);
end;

function ChopperWidthEvent:run(connection)
	self.vehicle:setChopperWidthState(self.state, true);
	if not connection:getIsServer() then
		g_server:broadcastEvent(ChopperWidthEvent:new(self.vehicle, self.state), nil, connection, self.vehicle);
	end;
end;

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