  --
  -- FergRake
  -- Class for all windrowers
  -- Note: the animation is not perfectly synchronized, thus do not attach any gameplay relevant stuff to the animation
  --
  -- @author  Stefan Geiger
  -- @date  11/05/08
  --
  -- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.
  
source("dataS/scripts/vehicles/specializations/SetTurnedOnEvent.lua");
  
FergRake = {};
  
function FergRake.prerequisitesPresent(specializations)
      return true;
end;
  
function FergRake:load(xmlFile)
  
      self.setIsTurnedOn = SpecializationUtil.callSpecializationsFunction("setIsTurnedOn");
  
      self.groundReferenceThreshold = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.groundReferenceNode#threshold"), 0.2);
      self.groundReferenceNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.groundReferenceNode#index"));
      if self.groundReferenceNode == nil then
          self.groundReferenceNode = self.components[1].node;
      end;

  
      local numWindrowerDropAreas = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.windrowerDropAreas#count"), 0);
      if numWindrowerDropAreas == 0 then
          print("Warning: No drop areas specified in '"..self.configFileName.."'");
      else
          if numWindrowerDropAreas ~= 1 and numWindrowerDropAreas ~= table.getn(self.cuttingAreas) then
              print("Warning: Number of cutting areas and drop areas should be equal in '"..self.configFileName.."'");
          end;
      end;
      self.windrowerDropAreas = {}
      for i=1, numWindrowerDropAreas do
          self.windrowerDropAreas[i] = {};
          local areanamei = string.format("vehicle.windrowerDropAreas.windrowerDropArea%d", i);
          self.windrowerDropAreas[i].start = Utils.indexToObject(self.components, getXMLString(xmlFile, areanamei .. "#startIndex"));
          self.windrowerDropAreas[i].width = Utils.indexToObject(self.components, getXMLString(xmlFile, areanamei .. "#widthIndex"));
          self.windrowerDropAreas[i].height = Utils.indexToObject(self.components, getXMLString(xmlFile, areanamei .. "#heightIndex"));
      end;
  
      local numCuttingAreas = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.cuttingAreas#count"), 0);
      self.accumulatedCuttingAreaValues = {};
      self.accumulatedFruitType = FruitUtil.FRUITTYPE_UNKNOWN;
      for i=1, numCuttingAreas do
          self.accumulatedCuttingAreaValues[i] = 0;
      end;
	  
	self.rotateSpinners = {};
	local i=0;
	while true do
		local baseName = string.format("vehicle.rotateSpinners.node(%d)", i);
		local index = getXMLString(xmlFile, baseName.. "#index");
		local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, baseName.. "#rotationSpeed"));
		local rotationSpeed = {x,y,z};
		local runOutTime = Utils.getNoNil(getXMLFloat(xmlFile, baseName.. "#runOutTime"), 2)*1000;
		if index == nil or rotationSpeed == nil or runOutTime == nil then
			break;
		end;
		local node = Utils.indexToObject(self.components, index);
		if node ~= nil then
			local entry = {};
			entry.node = node;
			entry.runOutTime = runOutTime;
			entry.rotationSpeedMax = rotationSpeed;
			entry.rotationSpeedMin = {0,0,0};
			entry.rotationSpeedCurrent = {0,0,0};
			table.insert(self.rotateSpinners, entry);
		end;
		i = i+1;
	end;	
	
	local rotarySound = getXMLString(xmlFile, "vehicle.rotarySound#file");
	if rotarySound ~= nil and rotarySound ~= "" then
		rotarySound = Utils.getFilename(rotarySound, self.baseDirectory);
		self.rotarySound = createSample("rotarySound");
		loadSample(self.rotarySound, rotarySound, false);
		self.rotarySoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.rotarySound#pitchOffset"), 0);
		self.rotarySoundVolume = 0.0;
		self.rotarySoundVolumeMin = 0.0;
		self.rotarySoundVolumeMax = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.rotarySound#volume"), 1.0);
		self.rotarySoundEnabled = false;
	end;
	  
	self.soundOffset = 0;
	self.isTurnedOn = false;

    self.wasToFast = false;
	self.lastArea = 0;
	self.lastAreaBiggerZero = self.lastArea > 0;  
    self.windrowerGroundFlag = self:getNextDirtyFlag();
	
    self.setVehicleRpmUp = SpecializationUtil.callSpecializationsFunction("setVehicleRpmUp");
    self.saveMinRpm = 0; 
    self.printWarningTime = 0;
end;
  
function FergRake:delete()
	if self.rotarySound ~= nil then
		delete(self.rotarySound);
	end;
end;
  
function FergRake:mouseEvent(posX, posY, isDown, isUp, button)
end;
  
function FergRake:keyEvent(unicode, sym, modifier, isDown)
end;
  
function FergRake:readStream(streamId, connection)
    local isTurnedOn = streamReadBool(streamId);
    self:setIsTurnedOn(isTurnedOn, true);
	self.lastAreaBiggerZero = streamReadBool(streamId);
end;
  
function FergRake:writeStream(streamId, connection)
    streamWriteBool(streamId, self.isTurnedOn);
	streamWriteBool(streamId, self.lastAreaBiggerZero);
end;
  
function FergRake:readUpdateStream(streamId, timestamp, connection)
	if connection:getIsServer() then
		self.lastAreaBiggerZero = streamReadBool(streamId);
	end;
end;
  
function FergRake:writeUpdateStream(streamId, connection, dirtyMask)
	if not connection:getIsServer() then
		streamWriteBool(streamId, self.lastAreaBiggerZero);
	end;
end;
  
function FergRake:update(dt)
  
    if self.isClient then
        if self:getIsActiveForInput() then
			if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA) and not self.PTOId then
				  self:setIsTurnedOn(not self.isTurnedOn);
			end;
			if InputBinding.isPressed(InputBinding.IMPLEMENT_EXTRA) and self.PTOId then
				self.printWarningTime = self.time + 1000;
			end;	
        end;
    end;
end;
  
function FergRake:updateTick(dt)
    self.wasToFast = false;
	self.lastArea = 0;	
      if self:getIsActive() then
		if self.PTOId then
			self.isTurnedOn = false;
		end;
		local isKeyEvent = false;	
		if self.isTurnedOn then
 			isKeyEvent = true;	
		else
 			isKeyEvent = false;	
		end;
		self:setVehicleRpmUp(dt, isKeyEvent);		
		local volume = Utils.getMovedLimitedValues({self.rotarySoundVolume}, {self.rotarySoundVolumeMax}, {self.rotarySoundVolumeMin}, 1, 1200, dt, not self.isTurnedOn);
		self.rotarySoundVolume = volume[1];
			if self.isTurnedOn and not self.PTOId then
				if not self.rotarySoundEnabled and self:getIsActiveForSound() then
					playSample(self.rotarySound, 0, self.rotarySoundVolume, 0);
					setSamplePitch(self.rotarySound, self.rotarySoundPitchOffset);
					self.rotarySoundEnabled = true;
				end;
				if self.rotarySoundVolume < self.rotarySoundVolumeMax then
					setSampleVolume(self.rotarySound, self.rotarySoundVolume);
				end;
				else
				if self.rotarySoundEnabled then
					if self.rotarySoundVolume <= self.rotarySoundVolumeMin then
						stopSample(self.rotarySound);
						self.rotarySoundEnabled = false;
					else
						setSampleVolume(self.rotarySound, self.rotarySoundVolume);
					end;
				end;
			end;	
			for k, spinner in pairs(self.rotateSpinners) do
				local values = Utils.getMovedLimitedValues(spinner.rotationSpeedCurrent, spinner.rotationSpeedMax, spinner.rotationSpeedMin, 3, spinner.runOutTime, dt, not self.isTurnedOn);
				spinner.rotationSpeedCurrent = values;
				rotate(spinner.node, unpack(spinner.rotationSpeedCurrent));
			end;
          if self.isTurnedOn then
              if self.isServer then
                  local toFast = self:doCheckSpeedLimit() and self.lastSpeed*3600 > 31;
                  if not toFast then
                      local x,y,z = getWorldTranslation(self.groundReferenceNode);
                      local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, 0, z);
                      if terrainHeight+self.groundReferenceThreshold >= y then
                          local numDropAreas = table.getn(self.windrowerDropAreas);
                          local numAreas = table.getn(self.cuttingAreas);
                          if numDropAreas > 0 and numAreas > 0 then
                              local cuttingAreasSend = {};
                              local dropAreasSend = {};
                              for i=1, numAreas do
                                  local cuttingArea = self.cuttingAreas[i];
                                  if self:getIsAreaActive(cuttingArea) then
                                      local x,_,z = getWorldTranslation(cuttingArea.start);
                                      local x1,_,z1 = getWorldTranslation(cuttingArea.width);
                                      local x2,_,z2 = getWorldTranslation(cuttingArea.height);
  
                                      table.insert(cuttingAreasSend, {x,z,x1,z1,x2,z2});
                                  end;
                              end;
                              for i=1, numDropAreas do
                                  local dropArea = self.windrowerDropAreas[i];
                                  local dx,dy,dz = getWorldTranslation(dropArea.start);
                                  local dx1,dy1,dz1 = getWorldTranslation(dropArea.width);
                                  local dx2,dy2,dz2 = getWorldTranslation(dropArea.height);
                                  table.insert(dropAreasSend, {dx, dz, dx1, dz1, dx2, dz2});
                              end;
                              if table.getn(cuttingAreasSend) > 0 then
                                  local cuttingAreasSend, dropAreasSend, fruitType, bitType = WindrowAreaEvent.runLocally(cuttingAreasSend, dropAreasSend, self.accumulatedCuttingAreaValues, self.accumulatedFruitType);
							  
                                  if table.getn(cuttingAreasSend) > 0 or table.getn(dropAreasSend) > 0 then
									self.lastArea = numAreas;
									self.lastAreaBiggerZero = (self.lastArea > 0);									  
                                      self.accumulatedFruitType = fruitType
                                      g_server:broadcastEvent(WindrowAreaEvent:new(cuttingAreasSend, dropAreasSend, fruitType, bitType));
                                  end;
                              end;
                          end;
                      end;
                  end;
  
                  self.wasToFast = toFast;
              end;
          end;
      end;
  end;
  
function FergRake:draw()
      if self.isClient then
		if self.printWarningTime > self.time then
			g_currentMission:addWarning(g_i18n:getText("turnON_Error"), 0.018, 0.033);
		end;
          if self:getIsActiveForInput(true) then
              if self.isTurnedOn then
                  g_currentMission:addHelpButtonText(string.format(g_i18n:getText("turn_off_OBJECT"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA);
              else
                  g_currentMission:addHelpButtonText(string.format(g_i18n:getText("turn_on_OBJECT"), self.typeDesc), InputBinding.IMPLEMENT_EXTRA);
              end;
          end
          if self.wasToFast then
              g_currentMission:addWarning(g_i18n:getText("Dont_drive_to_fast") .. "\n" .. string.format(g_i18n:getText("Cruise_control_levelN"), "2"), 0.07+0.022, 0.019+0.029);
          end;
      end;
end;
  
function FergRake:onDetach()
    if self.deactivateOnDetach then
        FergRake.onDeactivate(self);
    else
        FergRake.onDeactivateSounds(self)
    end;
	if self.rotarySoundEnabled then
		stopSample(self.rotarySound);
		self.rotarySoundEnabled = false;
	end;
    for k, steerable in pairs(g_currentMission.steerables) do
        if self.attacherVehicleCopy == steerable then
            steerable.motor.minRpm = self.saveMinRpm;
            self.attacherVehicleCopy = nil;
        end;
    end;
end;

function FergRake:onAttach(attacherVehicle)

    if self.attacherVehicleCopy == nil then
        self.attacherVehicleCopy = self.attacherVehicle;
    end;
    self.saveMinRpm = self.attacherVehicle.motor.minRpm;
end;
  
function FergRake:onLeave()
      if self.deactivateOnLeave then
          FergRake.onDeactivate(self);
      else
          FergRake.onDeactivateSounds(self)
      end; 
end;
  
function FergRake:onDeactivate()
      FergRake.onDeactivateSounds(self)
      self.isTurnedOn = false;
end;
  
function FergRake:onDeactivateSounds()
      if self.isClient then
		if self.rotarySoundEnabled then
			stopSample(self.rotarySound);
			self.rotarySoundEnabled = false;
		end;
     end;
end;
  
function FergRake:setIsTurnedOn(isTurnedOn, noEventSend)
      SetTurnedOnEvent.sendEvent(self, isTurnedOn, noEventSend)
      self.isTurnedOn = isTurnedOn;
  
      if not isTurnedOn then
          for k,_ in pairs(self.accumulatedCuttingAreaValues) do
              self.accumulatedCuttingAreaValues[k] = 0;
          end  
      end;
end;

function FergRake:setVehicleRpmUp(dt, isActive)
    if self.attacherVehicle ~= nil and self.saveMinRpm ~= 0 then
        if dt ~= nil then
            if isActive == true then
                self.attacherVehicle.motor.minRpm = math.max(self.attacherVehicle.motor.minRpm-dt, -1000);
            else
                self.attacherVehicle.motor.minRpm = math.min(self.attacherVehicle.motor.minRpm+dt*2, self.saveMinRpm);
            end;
        else
            self.attacherVehicle.motor.minRpm = self.saveMinRpm;
        end;
        if self.attacherVehicle.isMotorStarted then
            local fuelUsed = 0.000000011*math.abs(self.attacherVehicle.motor.minRpm);
            self.attacherVehicle:setFuelFillLevel(self.attacherVehicle.fuelFillLevel-fuelUsed);
            g_currentMission.missionStats.fuelUsageTotal = g_currentMission.missionStats.fuelUsageTotal + fuelUsed;
            g_currentMission.missionStats.fuelUsageSession = g_currentMission.missionStats.fuelUsageSession + fuelUsed;
        end;
    end;
end;