--
-- fertilizerFiller
-- Class for fertilizer filler
--
-- @author  PeterJ_LS-UK modteam
-- @date  20/07/2011
--
-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.
  

fertilizerFiller = {};

function fertilizerFiller.prerequisitesPresent(specializations)
	return SpecializationUtil.hasSpecialization(Fillable, specializations);
end;
 
function fertilizerFiller:load(xmlFile)
  
	--Filling
	assert(self.setIsSprayerFilling == nil, "fertilizerFiller needs to be the first specialization which implements setIsSprayerFilling");
	self.setIsSprayerFilling = Sprayer.setIsSprayerFilling;
	self.addSprayerFillTrigger = Sprayer.addSprayerFillTrigger;
	self.removeSprayerFillTrigger = Sprayer.removeSprayerFillTrigger;
  
	self.fillLitersPerSecond = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fillLitersPerSecond"), 500);
	self.isSprayerFilling = false;
  
	self.sprayerFillTriggers = {};
	self.sprayerFillActivatable = SprayerFillActivatable:new(self);
 
	self.fillTypes[Fillable.FILLTYPE_FERTILIZER] = true;
	
	self.emptyBag = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.unloadBag#emptyBag"));
	self.overlay = Utils.getFilename("textures/fertilizer_hud.png", self.baseDirectory);
    self.FruitTypeOverlay = Overlay:new("hudPDAControl", self.overlay, g_currentMission.fruitSymbolX, g_currentMission.fruitSymbolY, g_currentMission.fruitSymbolSize, g_currentMission.fruitSymbolSize * (4 / 3)); 

	--Unloading
	assert(self.setIsUnloading == nil, "fertilizerFiller needs to be the first specialization which implements setIsUnloading");
	self.setIsUnloading = fertilizerFiller.setIsUnloading;
	self.getIsUnloadingAllowed = fertilizerFiller.getIsUnloadingAllowed;
  
	self.unloadLitersPerSecond = {};
	local i=0;
	while true do
		local key = string.format("vehicle.unloadBag(%d)", i);
		if not hasXMLProperty(xmlFile, key) then
			break;
		end;
		local fillType = getXMLString(xmlFile, key.. "#unloadType");
		local litersPerSecond = getXMLFloat(xmlFile, key.. "#litersPerSecond");
		if fillType ~= nil and litersPerSecond ~= nil then
			local fillTypeInt = Fillable.fillTypeNameToInt[fillType];
			if fillTypeInt ~= nil then
				self.unloadLitersPerSecond[fillTypeInt] = litersPerSecond;
				if self.defaultUnloadLitersPerSecond == nil then
					self.defaultUnloadLitersPerSecond = litersPerSecond;
				end;
			else
				print("Warning: Invalid unload type '"..fillType.."' in '" .. self.configFileName.. "'");
			end;
		end;
		i = i+1;
	end;
	if self.defaultUnloadLitersPerSecond == nil then
		print("Warning: No unload type specified for '" .. self.configFileName.. "'. This bag will not use any unload type.");
		self.defaultUnloadLitersPerSecond = 0;
	end;
  
	self.unloadValves = {};
  
	if self.isClient then
		local psFile = getXMLString(xmlFile, "vehicle.unloadParticleSystem#file");
		if psFile ~= nil then
			local i=0;
			while true do
				local baseName = string.format("vehicle.unloadParticleSystem(%d)", i);
				local node = getXMLString(xmlFile, baseName.. "#index");
				if node == nil then
					break;
				end;
				node = Utils.indexToObject(self.components, node);
				if node ~= nil then
					local unloadValve = {};
					unloadValve.particleSystems = {};
					Utils.loadParticleSystem(xmlFile, unloadValve.particleSystems, "vehicle.unloadParticleSystem", node, false, nil, self.baseDirectory);
					table.insert(self.unloadValves, unloadValve);
				end;
				i = i+1;
			end;
		end;
		local unloadSound = getXMLString(xmlFile, "vehicle.unloadSound#file");
		if unloadSound ~= nil and unloadSound ~= "" then
			unloadSound = Utils.getFilename(unloadSound, self.baseDirectory);
			self.unloadSound = createSample("unloadSound");
			self.unloadSoundEnabled = false;
			loadSample(self.unloadSound, unloadSound, false);
			self.unloadSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.unloadSound#pitchOffset"), 1);
			self.unloadSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.unloadSound#volume"), 1);
		end;
	end;
	
	self.minThreshold = 0.05;
	self.isUnloading = false;

	--Trigger
	self.FillableTrigger = fertilizerFiller.FillableTrigger;
	self.FillableTriggers = {};
  
	local FillableTrigger = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.fillableTrigger#index"));
	if FillableTrigger ~= nil then
		self.FillableTriggers[FillableTrigger] = {node=FillableTrigger, pipeState=2};
	end;
	for _, FillableTrigger in pairs(self.FillableTriggers) do
		addTrigger(FillableTrigger.node, "FillableTrigger", self);
	end;
  
	self.isSpreaderInRange = nil;
	
	--Show fertilizer fill level
	self.hudFillLevelBasePosX = 0.01;
	self.hudFillLevelBasePosY = 0.0149;
	self.hudFillLevelBaseWidth = 0.2;
	self.hudFillLevelBaseHeight = 0.043;
	self.FillLevelPanelPath = Utils.getFilename("textures/fertilizerFillLevel_hud.png", self.baseDirectory);
	self.hudFillLevelBaseOverlay = Overlay:new("hudFillLevelBaseOverlay", self.FillLevelPanelPath, self.hudFillLevelBasePosX, self.hudFillLevelBasePosY, self.hudFillLevelBaseWidth, self.hudFillLevelBaseHeight);
end;
  
function fertilizerFiller:delete()
  
	g_currentMission:removeActivatableObject(self.sprayerFillActivatable);
  
	for k,unloadValve in pairs(self.unloadValves) do
		Utils.deleteParticleSystem(unloadValve.particleSystems);
	end;
  
	if self.unloadSound ~= nil then
		delete(self.unloadSound);
	end;
	for _, FillableTrigger in pairs(self.FillableTriggers) do
		removeTrigger(FillableTrigger.node);
	end;
end;
  
function fertilizerFiller:readStream(streamId, connection)
	local unloading = streamReadBool(streamId);
	local isSprayerFilling = streamReadBool(streamId);
	self:setIsUnloading(unloading, true);
	self:setIsSprayerFilling(isSprayerFilling, true);
end;
  
function fertilizerFiller:writeStream(streamId, connection)
	streamWriteBool(streamId, self.isUnloading);
	streamWriteBool(streamId, self.isSprayerFilling);
end;
  
function fertilizerFiller:readUpdateStream(streamId, timestamp, connection)
end;
  
function fertilizerFiller:writeUpdateStream(streamId, connection, dirtyMask)
end;
  
function fertilizerFiller:mouseEvent(posX, posY, isDown, isUp, button)
end;
  
function fertilizerFiller:keyEvent(unicode, sym, modifier, isDown)
end;
 
function fertilizerFiller:update(dt)
  
      if self.isClient then
          if self:getIsActiveForInput() then
              if InputBinding.hasEvent(InputBinding.IMPLEMENT_EXTRA) then
                  self:setIsUnloading(not self.isUnloading);
              end;
          end;
      end;
end;
  
function fertilizerFiller:updateTick(dt)

	if self.fillLevel / self.capacity <= self.minThreshold then
		setVisibility(self.emptyBag, true);
	else
		setVisibility(self.emptyBag, false);
	end;
	if self:getIsActive() then
		if self.isUnloading then
			if self.isServer then
				local litersPerSecond = self.unloadLitersPerSecond[self.currentFillType];
				if litersPerSecond == nil then
					litersPerSecond = self.defaultUnloadLitersPerSecond;
				end;
				local usage = litersPerSecond * dt*0.001;
				if self.fillLevel > 0 then
					self:setFillLevel(self.fillLevel - usage, self.currentFillType);
				end;  
			end;
			if self.isClient then
				if not self.unloadSoundEnabled and self:getIsActiveForSound() then
					playSample(self.unloadSound, 0, self.unloadSoundVolume, 0);
					setSamplePitch(self.unloadSound, self.unloadSoundPitchOffset);
					self.unloadSoundEnabled = true;
				end;
			end;
			if self.fillLevel <= 0 and self.capacity ~= 0 then
				self:setIsUnloading(false, true);
			end;
		end;
	end;

	if self.isSprayerFilling and self.isServer then
		local disableFilling = false;
		if self:allowFillType(self.sprayerFillingFillType, false) then
			local oldFillLevel = self.fillLevel;
  
			local delta = self.fillLitersPerSecond*dt*0.001;
  
			local silo = g_currentMission:getSiloAmount(self.sprayerFillingFillType);
			if self.sprayerFillingIsSiloTrigger then
				if silo <= 0 then
					disableFilling = true;
				end;
				delta = math.min(delta, silo);
			end;
  
			self:setFillLevel(self.fillLevel + delta, self.sprayerFillingFillType, true);
			local delta = self.fillLevel - oldFillLevel;
			if delta > 0 then
				if self.sprayerFillingIsSiloTrigger then
					g_currentMission:setSiloAmount(self.sprayerFillingFillType, silo - delta);
				else
					local sprayType = Sprayer.fillTypeToSprayType[self.sprayerFillingFillType];
					if sprayType ~= nil then
						local sprayTypeDesc = Sprayer.sprayTypeIndexToDesc[sprayType]
  
						local price = delta*sprayTypeDesc.pricePerLiter;
						g_currentMission.missionStats.expensesTotal = g_currentMission.missionStats.expensesTotal + price;
						g_currentMission.missionStats.expensesSession = g_currentMission.missionStats.expensesSession + price;
  
						g_currentMission:addSharedMoney(-price);
					end;
				end;
			elseif self.fillLevel == self.capacity then
				disableFilling = true;
			end;
		else
			disableFilling = true;
		end;
		if disableFilling then
			self:setIsSprayerFilling(false);
		end;
	end;

	if self.isServer and self:getIsActive() then
		if self.isUnloading and self.isSpreaderInRange ~= nil then
			local fillable = self.isSpreaderInRange;
			if fillable.setFillLevel ~= nil then
				for fillType,v in pairs(fillable.fillTypes) do
					if fillType == self.currentFillType then
						if  fillable.fillLevel ~= fillable.capacity  then
							local litersPerSecond = self.unloadLitersPerSecond[self.currentFillType];
							if litersPerSecond == nil then
								litersPerSecond = self.defaultUnloadLitersPerSecond;
							end;
							local usage = litersPerSecond * dt*0.001;
							fillable:resetFillLevelIfNeeded(Fillable.FILLTYPE_FERTILIZER);
							fillable:setFillLevel(fillable.fillLevel + usage, Fillable.FILLTYPE_FERTILIZER);
						end; 	
					end;
				end;
			end;
		end;
	end;
end;
  
function fertilizerFiller:draw()

	if self.isClient then
		if self.fillLevel <= 0 and self.capacity ~= 0 then
				g_currentMission:addExtraPrintText(g_i18n:getText("FirstFillTheTool"));
		end;
		if self.fillLevel > 0 then
			self.FruitTypeOverlay:render();
			if self.isUnloading then
				g_currentMission:addHelpButtonText(g_i18n:getText("StopFertilizer"), InputBinding.IMPLEMENT_EXTRA);
			else
				g_currentMission:addHelpButtonText(g_i18n:getText("StartFertilizer"), InputBinding.IMPLEMENT_EXTRA);
			end;
		end;
	end;
	if self:getIsActive() then
		if self.isSpreaderInRange ~= nil then
			local fillable = self.isSpreaderInRange;
			if self.isSpreaderInRange.fillLevel ~= nil then
				for fillType,v in pairs(fillable.fillTypes) do
					if fillType == self.currentFillType and fillable.rootNode ~= self.rootNode then
						local percent = (self.isSpreaderInRange.fillLevel / self.isSpreaderInRange.capacity) * 100;
						setTextBold(true);
						setTextAlignment(RenderText.ALIGN_CENTER);
						--setTextColor(0, 0, 0, 1);
						renderText(self.hudFillLevelBasePosX + self.hudFillLevelBaseWidth / 2 + 0.003, self.hudFillLevelBasePosY + 0.0115, 0.024, string.format("%d (%d%%)", self.isSpreaderInRange.fillLevel, percent));
						self.hudFillLevelBaseOverlay:render();
					end;
				end;
			end;
		end;
	end;
end;

function fertilizerFiller:onAttach(attacherVehicle)
	setCenterOfMass(self.components[1].node, 0, 2.05, 0);
end;
 
function fertilizerFiller:onDetach()
	if self.deactivateOnDetach then
		fertilizerFiller.onDeactivate(self);
	else
		fertilizerFiller.onDeactivateSounds(self);
	end;
	setCenterOfMass(self.components[1].node, 0, -0.3, 0);
end;
  
function fertilizerFiller:onLeave()
	if self.deactivateOnLeave then
		fertilizerFiller.onDeactivate(self);
	else
		fertilizerFiller.onDeactivateSounds(self);
	end;
end;
  
function fertilizerFiller:onDeactivate()
	self:setIsUnloading(false, true)
	fertilizerFiller.onDeactivateSounds(self);
end;
  
function fertilizerFiller:onDeactivateSounds()
	if self.unloadSoundEnabled then
		stopSample(self.unloadSound);
		self.unloadSoundEnabled = false;
	end;
end;
  
function fertilizerFiller:getIsUnloadingAllowed(isUnloading)
	if not isUnloading or self.fillLevel > 0 or self.capacity == 0 then
		return true;
	end;
end;
  
function fertilizerFiller:setIsUnloading(isUnloading, noEventSend)
	if isUnloading ~= self.isUnloading then
		if self:getIsUnloadingAllowed(isUnloading) then
			SetUnloadingEvent.sendEvent(self, isUnloading, noEventSend)
  
			self.isUnloading = isUnloading;
			if self.isClient then
				for k,unloadValve in pairs(self.unloadValves) do
					Utils.setEmittingState(unloadValve.particleSystems, self.isUnloading);
				end;
  
				if not self.isUnloading and self.unloadSoundEnabled then
					stopSample(self.unloadSound);
					self.unloadSoundEnabled = false;
				end;
			end;
		end;
	end;
end;

function fertilizerFiller:setIsSprayerFilling(isFilling, fillType, isSiloTrigger, noEventSend)
	FertSetIsFillingEvent.sendEvent(self, isFilling, fillType, isSiloTrigger, noEventSend)
	if self.isSprayerFilling ~= isFilling then
		self.isSprayerFilling = isFilling;
		self.sprayerFillingFillType = fillType;
		self.sprayerFillingIsSiloTrigger = isSiloTrigger;
	end;
end;
  
function fertilizerFiller:addSprayerFillTrigger(trigger)
	if table.getn(self.sprayerFillTriggers) == 0 then
		g_currentMission:addActivatableObject(self.sprayerFillActivatable);
	end;
	table.insert(self.sprayerFillTriggers, trigger);
end;
  
function fertilizerFiller:removeSprayerFillTrigger(trigger)
	for i=1, table.getn(self.sprayerFillTriggers) do
		if self.sprayerFillTriggers[i] == trigger then
			table.remove(self.sprayerFillTriggers, i);
			break;
		end;
	end;
	if table.getn(self.sprayerFillTriggers) == 0 then
		if self.isServer then
			self:setIsSprayerFilling(false);
		end;
		g_currentMission:removeActivatableObject(self.sprayerFillActivatable);
	end;
end;
 
function fertilizerFiller:FillableTrigger(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
	if onEnter or onLeave then
		local spreader = g_currentMission.nodeToVehicle[otherShapeId];
		if spreader ~= nil then
			if spreader ~= self and spreader.setFillLevel	then
				if onEnter then
					self.isSpreaderInRange = (spreader);
				else
					self.isSpreaderInRange = nil;
				end;
			end;
		end;
	end;
end;
 
 
SprayerFillActivatable = {}
local SprayerFillActivatable_mt = Class(SprayerFillActivatable);
  
function SprayerFillActivatable:new(sprayer)
	local self = {};
	setmetatable(self, SprayerFillActivatable_mt);
  
	self.sprayer = sprayer;
	self.activateText = "unknown";
  
	self.currentTrigger = nil;
  
	return self;
end;

function SprayerFillActivatable:getIsActivatable()
	self.currentTrigger = nil;
	if not self.sprayer:getIsActiveForInput() or self.sprayer.fillLevel == self.sprayer.capacity then
		return false;
	end;
	-- find the first trigger which is activable
   for i=1, table.getn(self.sprayer.sprayerFillTriggers) do
		local trigger = self.sprayer.sprayerFillTriggers[i];
		if trigger:getIsActivatable(self.sprayer) then
			self.currentTrigger = trigger;
			self:updateActivateText();
			return true;
		end;
	end;
	return false;
end;

function SprayerFillActivatable:onActivateObject()
	self.sprayer:setIsSprayerFilling(not self.sprayer.isSprayerFilling, self.currentTrigger.fillType, self.currentTrigger.isSiloTrigger);
	self:updateActivateText();
	g_currentMission:addActivatableObject(self);
end;
  
function SprayerFillActivatable:drawActivate()
	-- TODO draw icon
end;
  
function SprayerFillActivatable:updateActivateText()
	if self.sprayer.isSprayerFilling then
		self.activateText = string.format(g_i18n:getText("stop_refill_OBJECT"), self.sprayer.typeDesc);
	else
		self.activateText = string.format(g_i18n:getText("refill_OBJECT"), self.sprayer.typeDesc);
	end;
end;