---
-- throttleRPM
-- Specialization for throttleRPM
--
-- @author Claus G. Pedersen (Satis)
-- @date 04-01-13 03:29
--
-- Copyright Satis (C) 2013
-- Copyright Note: You are allowed to redistribute, use and edit it as long I'm credited for the original script.
throttleRPM = {};

function throttleRPM.prerequisitesPresent(specializations)
  return SpecializationUtil.hasSpecialization(Motorized, specializations);
end;

function throttleRPM:load(xmlFile)
  self.throttleRPM = {};
  ---
  -- Debugging values
  -- 0 = turn off debug
  -- 1 = Show Work RPM and Current RPM. Used by modders to implement throttleRPM to one of there attacheable items.
  -- 2 = Mod throttleRPM test. Used when editing this mod to manually controll it with out any attachables.
  self.throttleRPM.debug = 0;

  -- Set specialization functions
  self.setThrottleRPM = SpecializationUtil.callSpecializationsFunction("setThrottleRPM");
  self.getMaxThrottleRPM = throttleRPM.getMaxThrottleRPM;

  -- Set variables
  self.throttleRPM.originalMinRPM = self.motor.minRpm;
  self.throttleRPM.workRPM = self.throttleRPM.originalMinRPM;
  self.throttleRPM.RPMList = {};
  self.throttleRPM.tempWorkRPM = 800;
  self.throttleRPM.RPM = 0;
  self.throttleRPM.jumpDown = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.throttleRPM#jumpDownRpm"), 50);
  self.throttleRPM.incRpmPrSec = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.throttleRPM#increaseRpmPrSec"), 1500);
  self.throttleRPM.isWorking = false;
  self.throttleRPM.justStarted = true;
end;

function throttleRPM:delete()
end;

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

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

function throttleRPM:readStream(streamId, connection)
  self.throttleRPM.workRPM = streamReadInt16(streamId);
  self.throttleRPM.isWorking = streamReadBool(streamId);
end;

function throttleRPM:writeStream(streamId, connection)
  streamWriteInt16(streamId, self.throttleRPM.workRPM);
  streamWriteBool(streamId, self.throttleRPM.isWorking);
end;

function throttleRPM:draw()
  if self.throttleRPM.debug > 0 then
    if self.throttleRPM.debug > 1 then
      g_currentMission:addHelpButtonText("Increase Throttle RPM", InputBinding.throttleRPM_PLUS);
      g_currentMission:addHelpButtonText("Lower Throttle RPM", InputBinding.throttleRPM_MINUS);
      g_currentMission:addHelpButtonText("Set Throttle RPM", InputBinding.IMPLEMENT_EXTRA2);
      g_currentMission:addHelpButtonText("Clear Throttle RPM", InputBinding.IMPLEMENT_EXTRA3);
      g_currentMission:addExtraPrintText(("Throttle RPM to set: %d"):format(self.throttleRPM.tempWorkRPM));
    end;

    if self.throttleRPM.debug > 0 then
      local string = "Not Set";
      if self.throttleRPM.workRPM > self.throttleRPM.originalMinRPM then string = tostring(self.throttleRPM.workRPM); end;
      g_currentMission:addExtraPrintText(("Throttle RPM: %s"):format(string));
      g_currentMission:addExtraPrintText(("Current RPM: %d"):format(self.lastRoundPerMinute));
    end;
  end;
end;

function throttleRPM:update(dt)
  -- Debug
  if self.throttleRPM.debug > 1 then
    if self.isClient and self:getIsActiveForInput(false) and not self:hasInputConflictWithSelection() then
      if InputBinding.hasEvent(InputBinding.throttleRPM_PLUS) then
        self.throttleRPM.tempWorkRPM = math.min(self.throttleRPM.tempWorkRPM + 50, self.motor.maxRpm[3]);
      end;
      if InputBinding.hasEvent(InputBinding.throttleRPM_MINUS) then
        self.throttleRPM.tempWorkRPM = math.max(self.throttleRPM.tempWorkRPM - 50, self.throttleRPM.originalMinRPM);
      end;
      if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA2) then
        self:setThrottleRPM(self, self.throttleRPM.tempWorkRPM);
      end;
      if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA3) then
        self:setThrottleRPM(self);
      end;
    end;
  end;

  -- Handle RPM
  if self.throttleRPM.isWorking and self.isMotorStarted then
    if self.throttleRPM.justStarted then
      self.throttleRPM.justStarted = false;
      self.motor.minRpm = -(self.throttleRPM.originalMinRPM - self.throttleRPM.jumpDown);
    else
      self.throttleRPM.RPM = math.max(self.throttleRPM.workRPM - self.motor.lastMotorRpm, -self.throttleRPM.originalMinRPM);

      if self.motor.minRpm ~= -self.throttleRPM.RPM then
        local workRPM = (self.throttleRPM.RPM + self.throttleRPM.jumpDown + (self.throttleRPM.originalMinRPM*2));
        self.motor.minRpm = math.max(self.motor.minRpm - (workRPM / (workRPM / self.throttleRPM.incRpmPrSec) * (dt/1000.0)), -self.throttleRPM.RPM);
      end;
    end;
  else
    if self.throttleRPM.isWorking then self.throttleRPM.isWorking = false; end;
    if not self.throttleRPM.justStarted then
      self.throttleRPM.RPM = math.max(self.throttleRPM.workRPM - self.motor.lastMotorRpm, -self.throttleRPM.originalMinRPM);
      if self.motor.minRpm ~= self.throttleRPM.originalMinRPM then
        local workRPM = self.throttleRPM.RPM + (self.throttleRPM.originalMinRPM*2);
        self.motor.minRpm = math.min(self.motor.minRpm + (workRPM / (workRPM / self.throttleRPM.incRpmPrSec / 2) * (dt/1000.0)), self.throttleRPM.originalMinRPM);
      else
        self.throttleRPM.justStarted = true;
      end;
    end;
  end;

  -- Handle RPM sound
  if self.motorSoundRun ~= nil and self.throttleRPM.justStarted == false then
    local input = 0;
    local rpmVolume = 0;
    local maxRpm  = self.motor.maxRpm[3];

    if self.axisForward ~= nil then
      input = self.axisForward;
    end;

    if math.abs(input) > 0.01 or self.motor.speedLevel ~= 0 then
      rpmVolume = Utils.clamp(math.abs(self.lastRoundPerMinute)/((maxRpm - self.motor.minRpm)), 0.0, 1.0);
    elseif self.throttleRPM.isWorking then
      rpmVolume = Utils.clamp(math.abs(self.throttleRPM.workRPM)/((maxRpm - self.motor.minRpm)/1.5), 0.0, 1.0);
    else
      rpmVolume = Utils.clamp(math.abs(self.lastRoundPerMinute)/((maxRpm - self.motor.minRpm)*2), 0.0, 1.0);
    end;

    setSampleVolume(self.motorSoundRun, rpmVolume);
  end;
end;

function throttleRPM:setThrottleRPM(controller, Rpm, noEventSend)
  local sendEvent = false;
  if controller ~= nil and type(controller) == "table" and controller.rootNode ~= nil then
    if Rpm ~= nil and Rpm ~= false then
      -- only allow to set if not set already or if force is true
      if type(Rpm) == "number" then
        if Rpm ~= self.throttleRPM.RPMList[controller.rootNode] then
          local insetRpm = math.max(Rpm, self.throttleRPM.originalMinRPM);
          self.throttleRPM.RPMList[controller.rootNode] = math.min(insetRpm, self.motor.maxRpm[3]);

          local maxRpm = self:getMaxThrottleRPM();
          self.throttleRPM.isWorking = true;

          if maxRpm ~= self.throttleRPM.workRPM then
            self.throttleRPM.workRPM = maxRpm;
            if self.throttleRPM.workRPM == self.throttleRPM.originalMinRPM then
              self.throttleRPM.isWorking = false;
            end;
            sendEvent = true;
          end;
        end;
      else
        print("ERROR: Rpm in throttleRPM:setThrottleRPM(controller, Rpm) must be a number");
      end;
    else
      if self.throttleRPM.RPMList[controller.rootNode] ~= nil then
        self.throttleRPM.RPMList[controller.rootNode] = nil;
        if next(self.throttleRPM.RPMList) ~= nil then
          local maxRpm = self:getMaxThrottleRPM();

          if maxRpm ~= self.throttleRPM.workRPM then
            self.throttleRPM.workRPM = maxRpm;
            if self.throttleRPM.workRPM == self.throttleRPM.originalMinRPM then
              self.throttleRPM.isWorking = false;
            end;
            sendEvent = true;
          end;
        else
          self.throttleRPM.workRPM = self.throttleRPM.originalMinRPM;
          self.throttleRPM.isWorking = false;
          sendEvent = true;
        end;
      end;
    end;
  else
    print("ERROR: controller in throttleRPM:setThrottleRPM(controller, Rpm) must be an object. Should be the object that uses the function. Normally this will be self.");
  end;

  if sendEvent then
    throttleRPMEvent.sendEvent(self, controller, Rpm, noEventSend);
  end;
end;

function throttleRPM:getMaxThrottleRPM()
  local num = 0;
  for _,v in pairs(self.throttleRPM.RPMList) do
    if v>num then num = v end;
  end;
  return num;
end

function throttleRPM:onLeave()
  if self.deactivateOnLeave then
    self:setThrottleRPM(self);
  end;
end;

---
-- throttleRPMEvent
-- throttleRPM Event Handler for Multiplayer support.
--
-- @author Claus G. Pedersen (Satis)
-- @date 04-01-13 03:29
--
-- Copyright Satis (C) 2013
-- Copyright Note: You are allowed to redistribute, use and edit it as long I'm credited for the original script.
throttleRPMEvent = {};
throttleRPMEvent_mt = Class(throttleRPMEvent, Event);

InitEventClass(throttleRPMEvent, "throttleRPMEvent");

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

function throttleRPMEvent:new(vehicle, controller, workRPM)
  local self = throttleRPMEvent:emptyNew()
  self.vehicle = vehicle;
  self.controller = controller;
  self.workRPM = workRPM;
  return self;
end;

function throttleRPMEvent:readStream(streamId, connection)
  local id = streamReadInt32(streamId);
  local id2 = streamReadInt32(streamId);
	self.workRPM = streamReadInt16(streamId);
  self.vehicle = networkGetObject(id);
  self.controller = networkGetObject(id2);
  self:run(connection);
end;

function throttleRPMEvent:writeStream(streamId, connection)
  streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
  streamWriteInt32(streamId, networkGetObjectId(self.controller));
  streamWriteInt16(streamId, self.workRPM);
end;

function throttleRPMEvent:run(connection)
  self.vehicle:setThrottleRPM(self.controller, self.workRPM, true)
  if not connection:getIsServer() then
    g_server:broadcastEvent(throttleRPMEvent:new(self.vehicle, self.controller, self.workRPM), nil, connection, self.object);
  end;
end;

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