--
-- Leboulch
-- @poc@lypse
-- 
Leboulch = {};

function Leboulch.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Trailer, specializations);
end;

function Leboulch:load(xmlFile) 
    self.toggleSupport = SpecializationUtil.callSpecializationsFunction("toggleSupport");  
    self.manualSupportAnimation = getXMLString(xmlFile, "vehicle.manualSupport#animationName");
    self.supportRangeIndex = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.manualSupport#rangeIndex"));
    self.isInRangeSupport = false;
    self.isSupportDown = true;

    self.elevation = false;
    self.sendElevation = false;
    self.barre = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.barre#index"));
    setVisibility(self.barre, true);

    self.barreElevation = Utils.indexToObject(self.rootNode, getXMLString(xmlFile, "vehicle.barreElevation#index"));
    setVisibility(self.barreElevation, false);

   
   self.smokeParticleSystems = {};
    local entry = {};
      entry.ps = {};
      Utils.loadParticleSystem(xmlFile, entry.ps, "vehicle.smokeParticleSystem", self.components, false, nil, self.baseDirectory);
      if table.getn(entry.ps) > 0 then
          entry.isActive = false;
          table.insert(self.smokeParticleSystems, entry);
      end
      local i=0;
      while true do
          local baseName = string.format("vehicle.smokeParticleSystems.smokeParticleSystem(%d)", i);
          if not hasXMLProperty(xmlFile, baseName) then
              break;
          end;
          local entry = {};
          entry.ps = {};
          Utils.loadParticleSystem(xmlFile, entry.ps, baseName, self.components, false, nil, self.baseDirectory);
          if table.getn(entry.ps) > 0 then
              entry.isActive = false;
             entry.cuttingArea = i+1;
              table.insert(self.smokeParticleSystems, entry);
          end
          i = i+1;
      end;
end;


function Leboulch:delete()
for _, entry in ipairs(self.smokeParticleSystems) do
          Utils.deleteParticleSystem(entry.ps);
          entry.isActive = false;
end;   
end;

function Leboulch:readStream(streamId, connection)
        self.elevation = streamReadBool(streamId);
        local isSupportDown = streamReadBool(streamId);
	self:toggleSupport(isSupportDown, true);
end;

function Leboulch:writeStream(streamId, connection)       
        streamWriteBool(streamId, self.elevation);
        streamWriteBool(streamId, self.isSupportDown);
end;

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

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

function Leboulch:update(dt) 
         if self:getIsActive() then		
		if self.isClient and self:getIsActiveForInput(false) and not self:hasInputConflictWithSelection() then
			-- Show warning about the support being down
			if self.isSupportDown then
				g_currentMission:addWarning(string.format(g_i18n:getText("BJR_SUPPORT_WARNING")), 0.018, 0.033);
			end;
		end;
	end;
         if self.supportRangeIndex then
		-- Manage key events for inrange support --
		if self.isInRangeSupport then
			if InputBinding.hasEvent(InputBinding.LOWER_IMPLEMENT) then
				if self.isSupportDown then
					self:toggleSupport(false);
				else
					self:toggleSupport(true);
				end;
			end;
			-- Display key when in range --
			if self.isSupportDown then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("BJR_RAISE_SUPPORT")), InputBinding.LOWER_IMPLEMENT);
			else
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("BJR_LOWER_SUPPORT")), InputBinding.LOWER_IMPLEMENT);
			end;
		end;
	end;


if self.sendElevation ~= self.elevation then
    self.sendElevation = self.elevation;
    ElevationEvent:sendEvent(self, self.elevation);
end;
 if self:getIsActive() and self.isClient and self:getIsActiveForInput() then 

      if not self.PTOId then
		if InputBinding.hasEvent(InputBinding.LEBOULCH_ELEVATION) then
			self.elevation = not self.elevation;    
		end;
      end;
 end;

if self.animationParts[1].currentPosition < 0.00001 and not self.elevation then
 setVisibility(self.barre, true);
 setVisibility(self.barreElevation, false); 
end;


if self.animationParts[1].currentPosition > 0.00001 and self.elevation then
 setVisibility(self.barre, false);
 setVisibility(self.barreElevation, true); 
 self:onEndTip(false);
end;



if self.elevation then 
                self:setAnimationTime(1, self.animationParts[1].animDuration);
else
		self:setAnimationTime(1, self.animationParts[1].startPosition);                                       
end;

if self.PTOId then
 self:onEndTip(false);
end;

end;

function Leboulch:updateTick(dt)
         if self.supportRangeIndex then
		if g_currentMission.player ~= nil then
			-- Getting the distance between the player and the support
			local nearestDistance = 1.5; --max distance allowed
			local px, py, pz = getWorldTranslation(self.supportRangeIndex);
			local vx, vy, vz = getWorldTranslation(g_currentMission.player.rootNode);
			local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);
			if distance < nearestDistance then
				self.isInRangeSupport = true;
			else
				self.isInRangeSupport = false;
			end;
		end;
	else
		self.isInRangeSupport = false;
	end;

               for _, part in pairs(self.movingParts) do
					part.isDirty = true;
		end;

if self.isClient then
               for _,ps in pairs(self.smokeParticleSystems) do                  
                  if self.currentFillType == Fillable.FILLTYPE_MANURE and self.fillLevel > 3000 and self.movingDirection == 0 then                       
                      Utils.setEmittingState(ps.ps, true);
                  else
                      Utils.setEmittingState(ps.ps, false);
                  end
               end
end;
end;

function Leboulch:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	local isSupportDown = Utils.getNoNil(getXMLBool(xmlFile, key .. "#isSupportDown"), false);
	self:toggleSupport(isSupportDown);	
	
    return BaseMission.VEHICLE_LOAD_OK;
end;

function Leboulch:getSaveAttributesAndNodes(nodeIdent)
    local attributes = 'isSupportDown="' .. tostring(self.isSupportDown) .. '"';
    return attributes, nil;
end;

function Leboulch:draw() 
   if self.PTOId then
     g_currentMission:addWarning(g_i18n:getText("turnON_Error"));
   end;
   if not self.PTOId then        
        g_currentMission:addHelpButtonText(string.format(g_i18n:getText("LEBOULCH_ELEVATION"), self.typeDesc), InputBinding.LEBOULCH_ELEVATION); 
   end;       
end;

function Leboulch:toggleSupport(isSupportDown, noEventSend)
	ToggleSupportEvent.sendEvent(self, isSupportDown, noEventSend);	
	
	if not isSupportDown then
		if self.manualSupportAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.manualSupportAnimation, -1, nil, true);
		end;
	else
		if self.manualSupportAnimation ~= nil and self.playAnimation ~= nil then
			self:playAnimation(self.manualSupportAnimation, 1, nil, true);
		end;
	end;
	
	self.isSupportDown = isSupportDown;
end;

ElevationEvent = {};
ElevationEvent_mt = Class(ElevationEvent, Event);

InitEventClass(ElevationEvent, "ElevationEvent");

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

function ElevationEvent:new(object, elevation)
  local self = ElevationEvent:emptyNew();
  self.object = object;
  self.elevation = elevation;
  return self;
end;

function ElevationEvent:readStream(streamId, connection)
  self.object = networkGetObject(streamReadInt32(streamId));
  self.elevation = streamReadBool(streamId);
  self:run(connection);
end;

function ElevationEvent:writeStream(streamId, connection)
  streamWriteInt32(streamId, networkGetObjectId(self.object));
  streamWriteBool(streamId, self.elevation);
end;

function ElevationEvent:run(connection)
  self.object.elevation = self.elevation;  
  if not connection:getIsServer() then
    g_server:broadcastEvent(ElevationEvent:new(self.object, self.elevation), nil, connection, self.object);
  end;
end;

function ElevationEvent:sendEvent(object, elevation, noEventSend)
  if noEventSend == nil or noEventSend == false then
    if g_server ~= nil then
      g_server:broadcastEvent(ElevationEvent:new(object, elevation), nil, nil, object);
    else
      g_client:getServerConnection():sendEvent(ElevationEvent:new(object, elevation));
    end;
  end;
end;

-- Support event

ToggleSupportEvent = {};
ToggleSupportEvent_mt = Class(ToggleSupportEvent, Event);

InitEventClass(ToggleSupportEvent, "ToggleSupportEvent");

function ToggleSupportEvent:emptyNew()
    local self = Event:new(ToggleSupportEvent_mt);
    return self;
end;

function ToggleSupportEvent:new(vehicle, isSupportDown)
    local self = ToggleSupportEvent:emptyNew()
    self.vehicle = vehicle;
	self.isSupportDown = isSupportDown;
    return self;
end;

function ToggleSupportEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.vehicle = networkGetObject(id);
	self.isSupportDown = streamReadBool(streamId);
    self:run(connection);
end;

function ToggleSupportEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));	
	streamWriteBool(streamId, self.isSupportDown);
end;

function ToggleSupportEvent:run(connection)
	self.vehicle:toggleSupport(self.isSupportDown, true);
end;

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