--
-- bigBear
-- Specialization for bigBear
-- largely based on LS13 combine specialization by Giants (Stefan Geiger)

-- @author upsidedown
-- @start of project: 29.08.2013
-- @date  25.10.2013


bigBear = {};

function bigBear.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Fillable, specializations);
end;


function bigBear:load(xmlFile)

    self.pipeScrollers = {};
    self.pipeScrollersActive = false;
    bigBear.loadScrollers(self, xmlFile, "vehicle.pipeScrollers.pipeScroller", self.pipeScrollers, true);
    self.findTrailerToUnload = bigBear.findTrailerToUnload;
    self.findTrailerRaycastCallback = bigBear.findTrailerRaycastCallback;
	self.pipeRaycastNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.pipe#raycastNodeIndex"));
    self.pipeRaycastDistance = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pipe#raycastDistance"), 7);
     self.pipeParticleSystemExtraDistance = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.pipeParticleSystems#extraDistance"), 1.5);
 
     self.pipeParticleSystems = {};
 
     -- load the pipe particle system for each fruit type
     local i = 0;
     while true do
         local key = string.format("vehicle.pipeParticleSystems.pipeParticleSystem(%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/wheatParticleSystem.i3d", self.baseDirectory, defaultPipePSNode);
 
             for _, v in ipairs(currentPS) do
                 local normalSpeed,tangentSpeed = getParticleSystemAverageSpeed(v.geometry);
                 v.speed = math.sqrt(normalSpeed*normalSpeed + tangentSpeed*tangentSpeed);
                 v.originalLifespan = getParticleSystemLifespan(v.geometry);
             end
             self.pipeParticleSystems[desc.index] = currentPS;
             if self.defaultPipeParticleSystem == nil then
                 self.defaultPipeParticleSystem = currentPS;
             end;
 
             if self.pipeRaycastNode == nil then
                 self.pipeRaycastNode = particleNode;
             end;
         end;
         i = i + 1;
     end;
     if self.pipeRaycastNode == nil then
         self.pipeRaycastNode = self.components[1].node;
     end;
 
	self.isUnloading = false;
	self.pipeParticleDeactivateTime = 0;
	self.tankUnloadingCapacity = 1222;

	self.trailerRaycastFound = false;
		

	self.pipeUnloadingDistance = 1.5;
		
	self.allowOverload = false;
		
	self.workMode = false;
end;

function bigBear:update(dt)

	

	
	
	local needEvent = false;
	
	 if self:getIsActiveForInput(true) then
		if self.allowOverload  then
			if self.trailerRaycastFound and self.fillLevel > 0 then
				if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA3) then
					self.isUnloading = not self.isUnloading;
					needEvent = true;
					--sent event
				end
			end
		end;	
	end;
	
	
	if self.isServer then --only the server checks for courseplay conditions and sends events accordingly
		if self.attacherVehicle ~= nil and (self.attacherVehicle.isHired or self.attacherVehicle.drive) then
			if self.attacherVehicle.ai_mode ~= nil and self.attacherVehicle.ai_mode == 3 then --CP overload mode

				local isWait = self.attacherVehicle.Waypoints[math.max(1,self.attacherVehicle.recordnumber-1)].wait;
				if isWait ~= self.activeWorkMode then
					self.activeWorkMode = isWait;
					needEvent = true;
				end;
				
				if self.allowOverload and self.trailerRaycastFound and self.fillLevel > 0 then
					if not self.isUnloading then
						self.isUnloading = true;
						needEvent = true;
					end;
				end;
			end;
		end;
	end;
	
	if self.fillLevel > self.capacity/4 then
		self.workMode = true;
		--needEvent = true;
	elseif InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA) and self:getIsActiveForInput(true) and not self.isUnloading then
		self.workMode = not self.workMode;
		needEvent = true;
	end
	
	if self.workMode then
		if true then
			if not self.isUnloading then
				if self:getIsActiveForInput(true) and InputBinding.hasEvent(InputBinding.LOWER_IMPLEMENT) then
					self.activeWorkMode = not self.activeWorkMode;
					needEvent = true;
				end
			end
		end
	else
		self.activeWorkMode = false;
	end;

	if needEvent then
		if g_server ~= nil then
			g_server:broadcastEvent(bigBearOperator_Event:new(self, self.isUnloading,self.workMode,self.activeWorkMode), nil, nil, self);
		else
			g_client:getServerConnection():sendEvent(bigBearOperator_Event:new(self, self.isUnloading,self.workMode,self.activeWorkMode));
		end;	
	end;	 
end;

-- function bigBear:postUpdate(dt)
	-- renderText(0.5,0.5,0.015,tostring(self.trailerRaycastFound))
	-- renderText(0.5,0.55,0.015,tostring(self.isUnloading))
	-- renderText(0.5,0.6,0.015,tostring(self.pipeUnloadingDistance))
	-- renderText(0.5,0.65,0.015,"allow: " .. tostring(self.allowOverload))
	-- renderText(0.5,0.75,0.015,tostring(self.workMode))
	-- renderText(0.5,0.8,0.015,tostring(self.activeWorkMode))	
	-- renderText(0.5,.9,.03,tostring(self.tipState))
-- end;
				
				
function bigBear:updateTick(dt)
		
		local isTipping = (self.tipState == Trailer.TIPSTATE_OPENING or self.tipState == Trailer.TIPSTATE_OPEN)
	
		self.allowFillFromAir = self.workMode;
		--self.allowTipDischarge  = self.activeWorkMode;
		
		if self.isServer then
			if isTipping and not self.activeWorkMode then
				self:onEndTip(false);
			end;
		end;
 

		if self.isServer then
			local wasUnloading = self.isUnloading;
			local newAllow = false;
			local wasTrailerRaycastFound = self.trailerRaycastFound;
			local needEvent = false;
			
			if false then
				local _,_,rz = getRotation(self.movingTools[2].node);
				rz = math.deg(rz);
				self.activeWorkMode = self.workMode and (rz < 15);
			end;
			
			if self.animParts[1].toMax and not self.animParts[1].move and self.animParts[2].toMax and not self.animParts[2].move and self.activeWorkMode then ----self.animParts[3].toMax and not self.animParts[3].move then
				newAllow = true;
			end;
			
			newAllow = newAllow and self.workMode and self.activeWorkMode and not isTipping;
			if newAllow ~= self.allowOverload then 
				needEvent = true;--sent event
			end;
			self.allowOverload = newAllow;
			if not self.allowOverload then
				self.isUnloading = false;
			end;
			
			
			if (self:getIsActive() or self.isUnloading) and self.allowOverload then
				
                if true then --self.isUnloading or self:getIsActiveForInput(true) or isCoursePlay or not self.isClient then
                    if self.fillLevel > 0 then
						
						local trailer, trailerDistance = self:findTrailerToUnload(self.currentFillType); 
						if trailer ~= nil then
							if not self.trailerRaycastFound then
								self.trailerRaycastFound = true;
								needEvent = true;								
							end
							
							if self.isUnloading then
								trailer:resetFillLevelIfNeeded(self.currentFillType);

								local deltaLevel = math.min(self.fillLevel, self.tankUnloadingCapacity*dt/1000.0);
								--deltaLevel = math.min(deltaLevel, trailer.capacity - trailer.fillLevel);
								if deltaLevel > (trailer.capacity - trailer.fillLevel) then
									deltaLevel = (trailer.capacity - trailer.fillLevel);
									self.isUnloading = false;
									self.trailerRaycastFound = false;
									needEvent = true;
								end;
								
								if deltaLevel > 0 then
									self.pipeUnloadingDistance = trailerDistance;
									trailer:setFillLevel(trailer.fillLevel+deltaLevel, self.currentFillType);
									self:setFillLevel(self.fillLevel-deltaLevel, self.currentFillType);
									
								else
									self.isUnloading = false;
									self.trailerRaycastFound = false;
									needEvent = true;
								end;								
																
							end;
						else -- no trailer
							if self.trailerRaycastFound then
								self.trailerRaycastFound = false;
								needEvent = true;--sent event
								self.isUnloading = false;
							end;
						end;
					else
						self.isUnloading = false;
					end;
				end;
			end;
			
			if wasTrailerRaycastFound ~= self.trailerRaycastFound or wasUnloading ~= self.isUnloading then
				needEvent = true;--sent event
			end;
			
			if needEvent then 
				if g_server ~= nil then
					g_server:broadcastEvent(bigBearOverload_Event:new(self, self.trailerRaycastFound, self.isUnloading, self.pipeUnloadingDistance, self.allowOverload), nil, nil, self);
				else
					g_client:getServerConnection():sendEvent(bigBearOverload_Event:new(self, self.trailerRaycastFound, self.isUnloading, self.pipeUnloadingDistance, self.allowOverload));
				end;	
			end;
		end


        if self.isClient then
			if self.isUnloading or isTipping then
				self.pipeParticleDeactivateTime = self.time;
				
				local currentFruitType = FruitUtil.fillTypeToFruitType[self.currentFillType]
				
				local currentPipeParticleSystem = self.pipeParticleSystems[currentFruitType];
				if currentPipeParticleSystem == nil then
					currentPipeParticleSystem = self.defaultPipeParticleSystem;
				end;
				if currentPipeParticleSystem ~= self.currentPipeParticleSystem then
					Utils.setEmittingState(self.currentPipeParticleSystem, false);
	
					self.currentPipeParticleSystem = currentPipeParticleSystem;
					Utils.setEmittingState(self.currentPipeParticleSystem, true);
				end
	
				if self.currentPipeParticleSystem ~= nil then
					for _, v in ipairs(self.currentPipeParticleSystem) do
						local lifespan = math.min(v.originalLifespan, (self.pipeUnloadingDistance+self.pipeParticleSystemExtraDistance)/v.speed);
						setParticleSystemLifespan(v.geometry, lifespan, true);
					end
				end
			
			
				local currentPipeScrollers = self.pipeScrollers[currentFruitType];
				if currentPipeScrollers ~= self.currentPipeScrollers and self.currentPipeScrollers ~= nil then
					for _, scroller in pairs(self.currentPipeScrollers) do
						if scroller.toggleVisibility then
							setVisibility(scroller.node, false);
						end
					end
				end
				self.currentPipeScrollers = currentPipeScrollers;
				if self.currentPipeScrollers ~= nil then
					for _, scroller in pairs(self.currentPipeScrollers) do
						scroller.scrollPosition = (scroller.scrollPosition + dt*scroller.scrollSpeed) % scroller.scrollLength;
						if scroller.shaderParameterComponent == 1 then
							setShaderParameter(scroller.node, scroller.shaderParameterName, scroller.scrollPosition,0,0,0, false);
						else
							setShaderParameter(scroller.node, scroller.shaderParameterName, 0,scroller.scrollPosition,0,0, false);
						end
						if scroller.toggleVisibility then
							setVisibility(scroller.node, true);
						end
					end
				end				
			
			
			else
			
				if self.pipeParticleDeactivateTime >= 0 and self.pipeParticleDeactivateTime <= self.time then
					self.pipeParticleDeactivateTime = 0;
					if self.currentPipeParticleSystem ~= nil then
					  Utils.setEmittingState(self.currentPipeParticleSystem, false);
					  self.currentPipeParticleSystem = nil;
					end

					if self.currentPipeScrollers ~= nil then
					  for _, scroller in pairs(self.currentPipeScrollers) do
						  if scroller.toggleVisibility then
							  setVisibility(scroller.node, false);
						  end
					  end
					  self.currentPipeScrollers = nil
					end
				end
			end;		
		end
end;


function bigBear:delete()
	
end;

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

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

function bigBear:draw()
	if self:getIsActiveForInput(true) then
		if self.allowOverload  then
			if self.trailerRaycastFound and self.fillLevel > 0 then
				if self.isUnloading then
					g_currentMission:addHelpButtonText(g_i18n:getText("ROPA_ULW_3a"), InputBinding.IMPLEMENT_EXTRA3);
				else
					g_currentMission:addHelpButtonText(g_i18n:getText("ROPA_ULW_3b"), InputBinding.IMPLEMENT_EXTRA3);
				end;
			end
		end
		
		if self.fillLevel > self.capacity/4 or self.isUnloading then
			
		elseif self.workMode then
			g_currentMission:addHelpButtonText(g_i18n:getText("ROPA_ULW_1a"), InputBinding.IMPLEMENT_EXTRA);
		else
			g_currentMission:addHelpButtonText(g_i18n:getText("ROPA_ULW_1b"), InputBinding.IMPLEMENT_EXTRA);
		end
		
		if false then
			g_currentMission:addExtraPrintText(g_i18n:getText("ROPA_ULW_2a"));
		end
		if true then --frontloader
			if self.workMode then
				if self.activeWorkMode then
					if not self.isUnloading then
						g_currentMission:addHelpButtonText(g_i18n:getText("ROPA_ULW_2b"), InputBinding.LOWER_IMPLEMENT);
					end;
				else
					g_currentMission:addHelpButtonText(g_i18n:getText("ROPA_ULW_2a"), InputBinding.LOWER_IMPLEMENT);
				end
			end
		end
	 end

end;

function bigBear:onAttach()
end; 	

function bigBear:onDetach()
end;


function bigBear:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	if not resetVehicles then
		self.workMode = Utils.getNoNil(getXMLBool(xmlFile, key.."#workMode"),false);
		self.activeWorkMode = Utils.getNoNil(getXMLBool(xmlFile, key.."#activeWorkMode"),false);
	end; 
    return BaseMission.VEHICLE_LOAD_OK;
end;

function bigBear:getSaveAttributesAndNodes(nodeIdent)	
    local attributes = 'workMode="'.. tostring(self.workMode) .. '" activeWorkMode="'.. tostring(self.activeWorkMode) .. '"';
    return attributes, nil;
end;

function bigBear:writeStream(streamId, connection)

	streamWriteBool(streamId, self.isUnloading);
	streamWriteBool(streamId, self.workMode);
	streamWriteBool(streamId, self.activeWorkMode);
	streamWriteBool(streamId, self.trailerRaycastFound);
	--streamWriteBool(streamId, self.isUnloading);
	streamWriteFloat32(streamId, self.pipeUnloadingDistance);
	streamWriteBool(streamId, self.allowOverload);
	
end;


function bigBear:readStream(streamId, connection)
    
	self.isUnloading = streamReadBool(streamId);
	self.workMode = streamReadBool(streamId);
	self.activeWorkMode = streamReadBool(streamId);
	self.trailerRaycastFound = streamReadBool(streamId);
	--self.isUnloading = streamReadBool(streamId);
	self.pipeUnloadingDistance = streamReadFloat32(streamId);
	self.allowOverload = streamReadBool(streamId);
	
end;

function bigBear.loadScrollers(self, xmlFile, baseKey, list, hasFruitTypes)
    local i = 0;
    while true do
        local key = string.format(baseKey.."(%d)", i);
        if not hasXMLProperty(xmlFile, key) then
            break;
        end
        local node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));
        local shaderParameterName = getXMLString(xmlFile, key.."#shaderParameterName");
        local fruitDesc = nil;
        if hasFruitTypes then
            local fruitType = getXMLString(xmlFile, key.."#type");
            if fruitType ~= nil then
                fruitDesc = FruitUtil.fruitTypes[fruitType];
            end
        end
        if node ~= nil and shaderParameterName ~= nil and (fruitDesc ~= nil or not hasFruitTypes) then
            local scrollSpeed = Utils.getNoNil(getXMLFloat(xmlFile, key.."#scrollSpeed"), 1)*0.001;
            local shaderParameterComponent = Utils.getNoNil(getXMLInt(xmlFile, key.."#shaderParameterComponent"), 1);
            local scrollLength = Utils.getNoNil(getXMLFloat(xmlFile, key.."#scrollLength"), 1);
            local toggleVisibility = Utils.getNoNil(getXMLBool(xmlFile, key.."#toggleVisibility"), false);
            if toggleVisibility then
                setVisibility(node, false);
            end

            local insertList = list;
            if hasFruitTypes then
                insertList = list[fruitDesc.index];
                if insertList == nil then
                    insertList = {};
                    list[fruitDesc.index] = insertList;
                end
            end

            table.insert(insertList, {node=node, scrollSpeed=scrollSpeed, scrollPosition=0, scrollLength=scrollLength, shaderParameterName=shaderParameterName, shaderParameterComponent=shaderParameterComponent, toggleVisibility=toggleVisibility});
        end
        i = i + 1;
    end
end


function bigBear:findTrailerToUnload(fillType)

    local x,y,z = getWorldTranslation(self.pipeRaycastNode);
    local dx,dy,dz = localDirectionToWorld(self.pipeRaycastNode, 0,-1,0);

    self.trailerFound = 0;
    self.trailerFoundDistance = 0;
    raycastAll(x, y, z, dx,dy,dz, "findTrailerRaycastCallback", self.pipeRaycastDistance, self);
	
    local trailer = g_currentMission.nodeToVehicle[self.trailerFound];
    if trailer == nil or not trailer:allowFillType(fillType) or trailer.getAllowFillFromAir == nil or not trailer:getAllowFillFromAir() or trailer.fillLevel >= trailer.capacity then
        return nil;
    end;
    return trailer, self.trailerFoundDistance;
end;

function bigBear:findTrailerRaycastCallback(transformId, x, y, z, distance)

    local vehicle = g_currentMission.nodeToVehicle[transformId];
    if vehicle ~= nil then
        if vehicle.exactFillRootNode == transformId then
            self.trailerFound = transformId;
            self.trailerFoundDistance = distance;
            return false;
        end;
    end;

    return true;

end;

-----------------------------------------------------
-- self.isUnloading
		-- self.workMode
		-- self.activeWorkMode
		
bigBearOperator_Event = {};
  bigBearOperator_Event_mt = Class(bigBearOperator_Event, Event);
  
  InitEventClass(bigBearOperator_Event, "bigBearOperator_Event");
  
  function bigBearOperator_Event:emptyNew()
      local self = Event:new(bigBearOperator_Event_mt);
      return self;
  end;
  
  function bigBearOperator_Event:new(object, isUnloading,workMode,activeWorkMode)
      local self = bigBearOperator_Event:emptyNew()
      self.isUnloading = isUnloading;
	  self.workMode = workMode;
	  self.activeWorkMode = activeWorkMode;
	 
	  
      self.object = object;
      return self;
  end;
  
  function bigBearOperator_Event:readStream(streamId, connection)
      local id = streamReadInt32(streamId);
      self.isUnloading = streamReadBool(streamId);
	  self.workMode = streamReadBool(streamId);
	  self.activeWorkMode = streamReadBool(streamId);
	 
      
	  
	  self.object = networkGetObject(id);
      self:run(connection);
  end;
  
  function bigBearOperator_Event:writeStream(streamId, connection)
      streamWriteInt32(streamId, networkGetObjectId(self.object));
	  streamWriteBool(streamId, self.isUnloading);
	  streamWriteBool(streamId, self.workMode);
	  streamWriteBool(streamId, self.activeWorkMode);
	  

  end;
  
  function bigBearOperator_Event:run(connection)
	  self.object.isUnloading = self.isUnloading;
	  self.object.workMode = self.workMode;
	  self.object.activeWorkMode = self.activeWorkMode;
	  
	  
      if not connection:getIsServer() then
          g_server:broadcastEvent(bigBearOperator_Event:new(self.object, self.isUnloading, self.workMode, self.activeWorkMode), nil, connection, self.object);
      end;
  end;
  
  
  
  
  -----------------------------------
  
	--trailerRaycastFound
	--isUnloading
	--pipeUnloadingDistance
	--allowOverload
  
  
  
  bigBearOverload_Event = {};
  bigBearOverload_Event_mt = Class(bigBearOverload_Event, Event);
  
  InitEventClass(bigBearOverload_Event, "bigBearOverload_Event");
  
  function bigBearOverload_Event:emptyNew()
      local self = Event:new(bigBearOverload_Event_mt);
      return self;
  end;
  
  function bigBearOverload_Event:new(object, trailerRaycastFound,isUnloading,pipeUnloadingDistance,allowOverload)
      local self = bigBearOverload_Event:emptyNew()
      self.trailerRaycastFound = trailerRaycastFound;
	  self.isUnloading = isUnloading;
	  self.pipeUnloadingDistance = pipeUnloadingDistance;
	  self.allowOverload = allowOverload;
		  
      self.object = object;
      return self;
  end;
  
  function bigBearOverload_Event:readStream(streamId, connection)
      local id = streamReadInt32(streamId);
      self.trailerRaycastFound = streamReadBool(streamId);
	  self.isUnloading = streamReadBool(streamId);
	  self.pipeUnloadingDistance = streamReadFloat32(streamId);
	  self.allowOverload = streamReadBool(streamId);
      
	  
	  self.object = networkGetObject(id);
      self:run(connection);
  end;
  
  function bigBearOverload_Event:writeStream(streamId, connection)
      streamWriteInt32(streamId, networkGetObjectId(self.object));
	  streamWriteBool(streamId, self.trailerRaycastFound);
	  streamWriteBool(streamId, self.isUnloading);
	  streamWriteFloat32(streamId, self.pipeUnloadingDistance);
	  streamWriteBool(streamId, self.allowOverload);
	

  end;
  
  function bigBearOverload_Event:run(connection)
	  self.object.trailerRaycastFound = self.trailerRaycastFound;
	  self.object.isUnloading = self.isUnloading;
	  self.object.pipeUnloadingDistance = self.pipeUnloadingDistance;
	  self.object.allowOverload = self.allowOverload;
	  
	  
      if not connection:getIsServer() then
          g_server:broadcastEvent(bigBearOverload_Event:new(self.object, self.trailerRaycastFound, self.isUnloading, self.pipeUnloadingDistance, self.allowOverload), nil, connection, self.object);
      end;
  end;
  
  