-- specialisation for beet cutter
--
-- by upsidedown 14.9.2014
-- based mostly on shovel-skript by GIANTS.
--
-- developed for LS13: Holaras BB2500H by Farmer 14
-- feel free to use in other mods, but I really do appreciate it if I am asked for permission and comments before someone is changing parts of my work. Thanks!

BeetCutter = {}
source("dataS/scripts/vehicles/specializations/SetTurnedOnEvent.lua")


function BeetCutter.prerequisitesPresent(specializations)
  return SpecializationUtil.hasSpecialization(Fillable, specializations)
end
function BeetCutter:load(xmlFile)
  self.findTrailerRaycastCallbackBC = BeetCutter.findTrailerRaycastCallbackBC

  self.getBeetCutterEmptyingSpeed = BeetCutter.getBeetCutterEmptyingSpeed;
  
  self.setIsTurnedOn = BeetCutter.setIsTurnedOn;
  self.isTurnedOn = false

  
  self.updateBeetCutterParticleSystems = SpecializationUtil.callSpecializationsFunction("updateBeetCutterParticleSystems")
  
  self.BeetCutterTipReferenceNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.BeetCutter#tipReferenceNode"))
  self.BeetCutterTipRaycastDistance = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.BeetCutter#tipRaycastDistance"), 10)
  
  self.BeetCutterRollerNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.BeetCutter#rollerNode"));
  self.BeetCutterRollerSpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.BeetCutter#rollerSpeed"), 10);
  
  self.BeetCutterEmptySpeed = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.BeetCutter#emptySpeed"), self.capacity / 2) * 0.001

  if self.isClient then
    self.emptyParticleSystemsBC = {}
    local i = 0
    while true do
      do
        local key = string.format("vehicle.emptyParticleSystemsBC.emptyParticleSystem(%d)", i)
        local t = getXMLString(xmlFile, key .. "#type")
        if t == nil then
          break
        end
        local fillType = Fillable.fillTypeNameToInt[t]
        if fillType ~= nil then
          local currentPS = {}
          local particleNode = Utils.loadParticleSystem(xmlFile, currentPS, key, self.components, false, nil, self.baseDirectory)
          self.emptyParticleSystemsBC[fillType] = currentPS
        end
        i = i + 1
      end
    end;
	

    -- load on/off sound
    self.BeetCutterOnOffSound = false;
    local BeetCutterOnOffSound = getXMLString(xmlFile, "vehicle.BeetCutterOnOffSound#file");
    if BeetCutterOnOffSound ~= nil and BeetCutterOnOffSound ~= "" then
        BeetCutterOnOffSound = Utils.getFilename(BeetCutterOnOffSound, self.baseDirectory);
        self.BeetCutterOnOffSound = createSample("BeetCutterOnOffSound");
        loadSample(self.BeetCutterOnOffSound, BeetCutterOnOffSound, false);
        self.BeetCutterOnOffSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.BeetCutterOnOffSound#pitchOffset"), 0);
        self.BeetCutterOnOffSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.BeetCutterOnOffSound#volume"), 1.0);
        setSamplePitch(self.BeetCutterOnOffSound, self.BeetCutterOnOffSoundPitchOffset);
    end;
	self.BeetCutterOnOffSoundEnabled = false;
	
	-- load cutter sound
    self.BeetCutterChoppingSound = false;
    local BeetCutterChoppingSound = getXMLString(xmlFile, "vehicle.BeetCutterChoppingSound#file");
    if BeetCutterChoppingSound ~= nil and BeetCutterChoppingSound ~= "" then
        BeetCutterChoppingSound = Utils.getFilename(BeetCutterChoppingSound, self.baseDirectory);
        self.BeetCutterChoppingSound = createSample("BeetCutterChoppingSound");
        loadSample(self.BeetCutterChoppingSound, BeetCutterChoppingSound, false);
        self.BeetCutterChoppingSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.BeetCutterChoppingSound#pitchOffset"), 0);
        self.BeetCutterChoppingSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.BeetCutterChoppingSound#volume"), 1.0);
        setSamplePitch(self.BeetCutterChoppingSound, self.BeetCutterChoppingSoundPitchOffset);
    end;
	self.BeetCutterChoppingSoundEnabled = false;
   
  end
 
  self.lastBeetCutterEmptyTime = -10000
  
  
  
  if Bga.addBGAfillType ~= nil then
    if Fillable.NUM_FILLTYPES < 64 then
		local desc = Fillable.fillTypeIndexToDesc[Fillable.FILLTYPE_SUGARBEET];
		local newFillType = Fillable.registerFillType("sugarbeet_cut", desc.nameI18N, desc.pricePerLiter*1.3, false, desc.hudOverlayFilename)
		if newFillType ~= nil then
			Bga.addBGAfillType(Fillable.FILLTYPE_SUGARBEET_CUT,0.23,111*0.51*1.3,1.5,false)	
			print("added sugarBeet_Cut to BGA")
		end;
	end;
	
  else
    --print("no complexBGA-Mod found or fillTypes full!")
  end;
  
end
function BeetCutter:delete()
  if self.isClient then
    for _, particleSystem in pairs(self.emptyParticleSystemsBC) do
      Utils.deleteParticleSystem(particleSystem)
    end
  end
  
  if self.BeetCutterOnOffSound ~= nil then
      delete(self.BeetCutterOnOffSound);
      self.BeetCutterOnOffSound = nil;
  end;
  
  if self.BeetCutterChoppingSound ~= nil then
      delete(self.BeetCutterChoppingSound);
      self.BeetCutterChoppingSound = nil;
  end;  
end

function BeetCutter:onDetach()
	BeetCutter.onDeactivate(self);   
end;


function BeetCutter:mouseEvent(posX, posY, isDown, isUp, button)
end
function BeetCutter:keyEvent(unicode, sym, modifier, isDown)
end

function BeetCutter:update(dt)
  if self.isClient and self:getIsActiveForInput() and InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA) then
    self:setIsTurnedOn(not self.isTurnedOn)
  end
end

function BeetCutter:updateTick(dt)
  if self:getIsActive() and self.isServer then
    local emptySpeed = self:getBeetCutterEmptyingSpeed()
    if emptySpeed > 0 then
      if 0 < self.fillLevel and self.BeetCutterTipReferenceNode ~= nil then
        self.trailerFoundBC = nil
        self.objectFoundBC = nil
        local x, y, z = getWorldTranslation(self.BeetCutterTipReferenceNode)
        raycastAll(x, y, z, 0, -1, 0, "findTrailerRaycastCallbackBC", self.BeetCutterTipRaycastDistance, self)
        local delta = math.min(self.fillLevel, emptySpeed * dt)
		local fillType = self.currentFillType;
		local fillTypeRatio = 1.0;
		
        if self.trailerFoundBC ~= nil or self.objectFoundBC ~= nil then
          if self.trailerFoundBC ~= nil and self.trailerFoundBCSupported then
		    if self.trailerFoundBC:allowFillType(Fillable.FILLTYPE_SILAGE) then
				fillType = Fillable.FILLTYPE_SILAGE;
				fillTypeRatio = 0.8;
			end;
		  
            self.trailerFoundBC:resetFillLevelIfNeeded(fillType)
            do
              local oldFillLevel = self.trailerFoundBC:getFillLevel(fillType)
              self.trailerFoundBC:setFillLevel(oldFillLevel + delta, fillType)
              delta = self.trailerFoundBC:getFillLevel(fillType) - oldFillLevel
            end
          elseif self.objectFoundBC ~= nil and self.objectFoundBCSupported then
		  
			  if self.objectFoundBC:getAllowShovelFillType(Fillable.FILLTYPE_SUGARBEET_CUT) then
				fillType = Fillable.FILLTYPE_SUGARBEET_CUT;
			  elseif self.objectFoundBC:getAllowShovelFillType(Fillable.FILLTYPE_SILAGE) then
				fillType = Fillable.FILLTYPE_SILAGE;
				fillTypeRatio = 0.8;
			  end;
			  
			  local delta1 = self.objectFoundBC:addShovelFillLevel(self, delta, fillType)
			  if delta1 ~= nil then
				delta = delta1
			  end
			
          else
            delta = 0
          end       
        end
        if delta ~= 0 then
          local fillType = self.currentFillType
          local oldFillLevel = self.fillLevel
          self:setFillLevel(oldFillLevel - delta*fillTypeRatio, fillType)
          self:updateBeetCutterParticleSystems(self.fillLevel - oldFillLevel, fillType)
          self.lastBeetCutterEmptyTime = self.time
        end
      end   
    end
  end
  
	if self.isClient then
		if self:getIsActive() and self.BeetCutterRollerNode~= nil then
			if self.isTurnedOn then
				rotate(self.BeetCutterRollerNode,self.BeetCutterRollerSpeed*180/math.pi*dt/1000,0,0)
			end;
		end;
		
		if not self.isServer then --server has better code to determine if PS is needed
			if self.isTurnedOn then				
				self:updateBeetCutterParticleSystems(-self.fillLevel, self.currentFillType)				
			end;
		end;
		
		if self.isTurnedOn and self:getIsActiveForSound() then
			if not self.BeetCutterOnOffSoundEnabled then
				playSample(self.BeetCutterOnOffSound, 0, self.BeetCutterOnOffSoundVolume, 0);
				self.BeetCutterOnOffSoundEnabled = true;
			end
			
			if self.fillLevel > 0.0001 and not self.BeetCutterChoppingSoundEnabled then
				playSample(self.BeetCutterChoppingSound, 0, self.BeetCutterChoppingSoundVolume, 0);
				self.BeetCutterChoppingSoundEnabled = true;		
			end;
			
			if self.fillLevel <= 0.0001 and self.BeetCutterChoppingSoundEnabled then
				stopSample(self.BeetCutterChoppingSound)
				self.BeetCutterChoppingSoundEnabled = false;
			end;
			
		else
			if self.BeetCutterOnOffSoundEnabled then
				stopSample(self.BeetCutterOnOffSound)
				self.BeetCutterOnOffSoundEnabled = false;
			end;
			
			if self.BeetCutterChoppingSoundEnabled then
				stopSample(self.BeetCutterChoppingSound)
				self.BeetCutterChoppingSoundEnabled = false;
			end;
		end;	
	end;
end

function BeetCutter:onDeactivate()
	
    for _, ps in pairs(self.emptyParticleSystemsBC) do       
		Utils.setEmittingState(ps, false);       
    end;
    self:setIsTurnedOn(false, true);
    
	if self.BeetCutterOnOffSoundEnabled then
		stopSample(self.BeetCutterOnOffSound)
		self.BeetCutterOnOffSoundEnabled = false;
	end;
	
	if self.BeetCutterChoppingSoundEnabled then
		stopSample(self.BeetCutterChoppingSound)
		self.BeetCutterChoppingSoundEnabled = false;
	end;
end;


function BeetCutter:draw()
  if self.isClient 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;
end


function BeetCutter:getBeetCutterEmptyingSpeed()
  if self.BeetCutterTipReferenceNode ~= nil then
    local dx, dy, dz = localDirectionToWorld(self.BeetCutterTipReferenceNode, 0, 0, 1)
    if self.isTurnedOn then
      local scale = 1;
      return self.BeetCutterEmptySpeed * scale
    end
  end
  return 0
end

function BeetCutter:updateBeetCutterParticleSystems(fillLevelDelta, fillType)
  if self.isClient then
    if fillLevelDelta < -1.0E-5 then
      if self.fillLevel > 0 then
        local ps = self.emptyParticleSystemsBC[fillType]
        if ps ~= nil then
          Utils.resetNumOfEmittedParticles(ps)
          Utils.setEmittingState(ps, true)
        end
      end

    end
  end
end

function BeetCutter:findTrailerRaycastCallbackBC(transformId, x, y, z, distance)
  local trailer = g_currentMission.objectToTrailer[transformId]
  if trailer ~= nil and trailer ~= self then
    --if trailer:allowFillType(self.currentFillType) and trailer.getAllowFillFromAir ~= nil and trailer:getAllowFillFromAir() then
    if (trailer:allowFillType(self.currentFillType) or trailer:allowFillType(Fillable.FILLTYPE_SILAGE)) and trailer.getAllowFillFromAir ~= nil and trailer:getAllowFillFromAir() then
      self.trailerFoundBC = trailer
      self.trailerFoundBCSupported = true
    elseif self.trailerFoundBC == nil then
      self.trailerFoundBC = trailer
      self.trailerFoundBCSupported = false
    end
    return false
  end
  local object = g_currentMission:getNodeObject(transformId)
  if object ~= nil and object ~= self and object.addShovelFillLevel ~= nil and object.getAllowShovelFillType ~= nil then
    if object:getAllowShovelFillType(self.currentFillType) or object:getAllowShovelFillType(Fillable.FILLTYPE_SILAGE) or object:getAllowShovelFillType("sugarBeetCut") then
      self.objectFoundBC = object
      self.objectFoundBCSupported = true
      return false
    elseif self.objectFoundBC == nil then
      self.objectFoundBC = object
      self.objectFoundBCSupported = false
    end
  end
  return true
end


function BeetCutter:readStream(streamId, connection)
  local turnedOn = streamReadBool(streamId)
  --local isSprayerFilling = streamReadBool(streamId)
  self:setIsTurnedOn(turnedOn, true)  
end
function BeetCutter:writeStream(streamId, connection)
  streamWriteBool(streamId, self.isTurnedOn)
  --streamWriteBool(streamId, self.isSprayerFilling)
  
end



function BeetCutter:setIsTurnedOn(isTurnedOn, noEventSend)
  --if isTurnedOn ~= self.isTurnedOn and self:getIsTurnedOnAllowed(isTurnedOn) then
  if isTurnedOn ~= self.isTurnedOn then
    SetTurnedOnEvent.sendEvent(self, isTurnedOn, noEventSend)
    self.isTurnedOn = isTurnedOn;   
  end
end