--
-- urfSeeder 2.0
-- Class for sowing machines with under-root fertilization
--
-- @author  Stefan Geiger
-- @date  25/02/08
--
-- @author  webalizer
-- @date  v 2.0 11/08/13
--
-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.

source("dataS/scripts/vehicles/specializations/SprayerAreaEvent.lua");
source("dataS/scripts/vehicles/specializations/SprayerSetIsFillingEvent.lua");

UrfSeeder = {};
UrfSeeder.DIR =  g_currentModDirectory;

function UrfSeeder.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(SowingMachine, specializations);
end;

function UrfSeeder:load(xmlFile)
	self.setIsFertilizing = SpecializationUtil.callSpecializationsFunction("setIsFertilizing");
	self.addSprayerFillTrigger = SpecializationUtil.callSpecializationsFunction("addSprayerFillTrigger");
	self.removeSprayerFillTrigger = SpecializationUtil.callSpecializationsFunction("removeSprayerFillTrigger");
	self.drawFillLevels = SpecializationUtil.callSpecializationsFunction("drawFillLevels");

	self.setSprayFillLevel = UrfSeeder.setSprayFillLevel;
  	assert(self.setIsSprayerFilling == nil, "UrfSeeder needs to be the first specialization which implements setIsSprayerFilling");
    self.setIsSprayerFilling = UrfSeeder.setIsSprayerFilling;
    self.addSprayerFillTrigger = UrfSeeder.addSprayerFillTrigger;
    self.removeSprayerFillTrigger = UrfSeeder.removeSprayerFillTrigger;
	self.fillUpSprayer = UrfSeeder.fillUpSprayer;

	self.allowFullFertilization = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.allowFullFertilization"), false);
	self.sprayFillLitersPerSecond = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.sprayFillLitersPerSecond"), 50);
	self.sprayCapacity = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.sprayCapacity"), 0.0);
	self.sprayLitersPerSecond = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.sprayLitersPerSecond"), 7.2);

	local numSprayingAreas = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.urfSeeder_Areas#count"), 0);
      self.sprayingAreas = {}
      for i=1, numSprayingAreas do
          local sareanamei = string.format("vehicle.urfSeeder_Areas.sprayingArea%d", i);
          local sprayingArea = {};
          if self:loadAreaFromXML(sprayingArea, xmlFile, sareanamei) then
              table.insert(self.sprayingAreas, sprayingArea);
          end;
      end;

	self.sprayFillType = "fertilizer";
	self.currentSprayFillType = Fillable.fillTypeNameToInt[self.sprayFillType]
	self.sprayFillLevel = 0;
  	self.isSprayerFilling = false;
	self.isFertilizing = 2;

   	self.sprayerFillTriggers = {};
    self.sprayerFillActivatable = SprayerFillActivatable:new(self);
		
	self.fullFertilizationText = string.format(g_i18n:getText("URF_FULL_FERTILIZER"), self.typeDesc);
	self.partialFertilizationText = string.format(g_i18n:getText("URF_PARTIAL_FERTILIZER"), self.typeDesc);
	self.noFertilizationText = string.format(g_i18n:getText("URF_NO_FERTILIZER"), self.typeDesc);
	self.fertilizationText = string.format(g_i18n:getText("URF_FERTILIZATION"), self.typeDesc);
	
 	self.xPos = Utils.getNoNil(getXMLFloat(xmlFile,  "vehicle.hudPos#posX"), 0.853);
	self.yPos = Utils.getNoNil(getXMLFloat(xmlFile,  "vehicle.hudPos#posY"), 0.245);
	self.hudBarWidth = 0.104;
	
	self.hudFullOverlay = Overlay:new("hudFullOverlay", Utils.getFilename("textures/full_fertilizer_hud.dds", UrfSeeder.DIR), self.xPos, self.yPos, 0.235, 0.039525);
	self.hudHalfOverlay = Overlay:new("hudHalfOverlay", Utils.getFilename("textures/half_fertilizer_hud.dds", UrfSeeder.DIR), self.xPos, self.yPos, 0.235, 0.039525);
	self.hudNoneOverlay = Overlay:new("hudNoneOverlay", Utils.getFilename("textures/none_fertilizer_hud.dds", UrfSeeder.DIR), self.xPos, self.yPos, 0.235, 0.039525);
	self.hudBgOverlay = Overlay:new("hudBgOverlay", Utils.getFilename("textures/fertilizer_bg.dds", UrfSeeder.DIR), self.xPos, self.yPos, 0.235, 0.039525);	
	self.hudBarLimeOverlay = Overlay:new("hudBarLimeOverlay", Utils.getFilename("textures/lime_fertilizer_bar.dds", UrfSeeder.DIR), self.xPos + 0.028, self.yPos + 0.01, 0.21, 0.02190);
	self.hudBarRedOverlay = Overlay:new("hudBarRedOverlay", Utils.getFilename("textures/red_fertilizer_bar.dds", UrfSeeder.DIR), self.xPos + 0.028, self.yPos + 0.01, 0.21, 0.02190);
end;

function UrfSeeder:delete()
	if self.hudBarLimeOverlay then
        self.hudBarLimeOverlay:delete();
    end;
	if self.hudBarRedOverlay then
        self.hudBarRedOverlay:delete();
    end;
	if self.hudBgOverlay then
        self.hudBgOverlay:delete();
    end;
	if self.hudHalfOverlay then
        self.hudHalfOverlay:delete();
    end;
	if self.hudFullOverlay then
        self.hudFullOverlay:delete();
    end;
	if self.hudNoneOverlay then
        self.hudNoneOverlay:delete();
    end;
    g_currentMission:removeActivatableObject(self.sprayerFillActivatable);

end;

function UrfSeeder:readStream(streamId, connection)
  	local isSprayerFilling = streamReadBool(streamId);
	local isFertilizing = streamReadInt8(streamId);
	local sprayFillLevel = streamReadInt32(streamId);
    self:setIsSprayerFilling(isSprayerFilling, true);
	self:setIsFertilizing(isFertilizing, true);
	self:setSprayFillLevel(sprayFillLevel, true);
end;

function UrfSeeder:writeStream(streamId, connection)
    streamWriteBool(streamId, self.isSprayerFilling);
	streamWriteInt8(streamId, self.isFertilizing);
	streamWriteInt32(streamId, self.sprayFillLevel);
end;

function UrfSeeder:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	local fertilizationStatus = getXMLInt(xmlFile, key.."#fertilizationStatus");
	if fertilizationStatus ~= nil then
           self.isFertilizing = tonumber(fertilizationStatus);
    end;
	local sprayFillLevel = getXMLInt(xmlFile, key.."#sprayFillLevel");
	if sprayFillLevel ~= nil then
			self.sprayFillLevel = sprayFillLevel;
	end;
    return BaseMission.VEHICLE_LOAD_OK;
end;

function UrfSeeder:getSaveAttributesAndNodes(nodeIdent)
    local fertilizationStatus = self.isFertilizing;
	local sprayFillLevel = self.sprayFillLevel;
	local attributes = 'fertilizationStatus="'..fertilizationStatus..'" sprayFillLevel="'..sprayFillLevel..'"';
    return attributes, nil;
end;

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

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

function UrfSeeder:update(dt)
    if self:getIsActive() then
        if self:getIsActiveForInput() then
			if InputBinding.hasEvent(InputBinding.URF_FERTILIZATION) then
				if self.allowFullFertilization then
					local urfState = self.isFertilizing + 1;
					if urfState > 3 then
						urfState = 1;
					end;
					self:setIsFertilizing(urfState);
				else
					local urfState = self.isFertilizing + 1;
					if urfState > 2 then
						urfState = 1;
					end;
					self:setIsFertilizing(urfState);
				end;
			end;
        end;
	end;
end;

function UrfSeeder:updateTick(dt)
    if self:getIsActive() then
		self.lastSprayingArea = 0;
        local doGroundManipulation = (self.movingDirection > 0 and self.sowingMachineHasGroundContact and (not self.needsActivation or self.isTurnedOn));

		if doGroundManipulation then
            if self.isServer then
				if self.isFertilizing > 1 then -- 1 -> no fertilization
				  	local litersPerSecond = self.sprayLitersPerSecond;
                     
					if self.isFertilizing == 2 then -- if partial fertilization use half consumption
						litersPerSecond = litersPerSecond / 2;
					end;					
					local usage = litersPerSecond * dt*0.001;
                    local hasSpray = false;

                    if self:getIsHired() then
                       	hasSpray = true;
                        local sprayFillType = self.currentSprayFillType;
                        local sprayFillTypeDesc = Fillable.fillTypeIndexToDesc[sprayFillType];
                        if sprayFillTypeDesc ~= nil then
                            local delta = usage*sprayFillTypeDesc.pricePerLiter;
                            g_currentMission.missionStats.expensesTotal = g_currentMission.missionStats.expensesTotal + delta;
                            g_currentMission.missionStats.expensesSession = g_currentMission.missionStats.expensesSession + delta;

                            g_currentMission:addSharedMoney(-delta, "other");

                        end;
                    else
                        if self.sprayFillLevel > 0 and self.fillLevel > 0 then
                            hasSpray = true;
                            self:setSprayFillLevel(self.sprayFillLevel - usage);
                        end;
                    end;
                    if hasSpray then
						if self.isFertilizing == 3 then --full fertilization -> use cuttingAreas
							self.sprayAmount = self.cuttingAreas;
						elseif self.isFertilizing == 2 then --partial fertilization -> use sprayingAreas
							self.sprayAmount = self.sprayingAreas;
						end;

                        local sprayingAreasSend = {};
                        for _,sprayingArea in pairs(self.sprayAmount) do
                            if self:getIsAreaActive(sprayingArea) then
                                local sx,s_,sz = getWorldTranslation(sprayingArea.start);
                                local sx1,s_1,sz1 = getWorldTranslation(sprayingArea.width);
                                local sx2,s_2,sz2 = getWorldTranslation(sprayingArea.height);
                                local sqm = math.abs((sz1-sz)*(sx2-sx) - (sx1-sx)*(sz2-sz)); -- this is the cross product with y=0
                                --Utils.updateSprayArea(x, z, x1, z1, x2, z2);
                                self.lastSprayingArea = self.lastSprayingArea + sqm;
                                table.insert(sprayingAreasSend, {sx,sz,sx1,sz1,sx2,sz2});
                            end;
                        end;
                        if (table.getn(sprayingAreasSend) > 0) then
                            SprayerAreaEvent.runLocally(sprayingAreasSend);
                            g_server:broadcastEvent(SprayerAreaEvent:new(sprayingAreasSend));
                        end;
                    end;
				end;
            end;
        end
	end;

if self.isServer and self.isSprayerFilling then

        local delta = 0;
        if self.sprayerFillTrigger ~= nil then
            delta = self.sprayFillLitersPerSecond*dt*0.001;
            delta = self:fillUpSprayer(delta);
        end;
        if delta <= 0 then
            self:setIsSprayerFilling(false);
        end;
    end;
end;

function UrfSeeder:drawFillLevels()

	local percent = 0;
	local level = self.sprayFillLevel;
	local capacity = self.sprayCapacity;
	percent = level / capacity * 100;

	-- render the hud overlays
	self.hudBgOverlay:render();
	
	if percent > 10 then
		self.hudBarOverlay = self.hudBarLimeOverlay;
	else
		self.hudBarOverlay = self.hudBarRedOverlay;
	end;
	
	self.hudBarOverlay.width = self.hudBarWidth * (self.sprayFillLevel / self.sprayCapacity);
	setOverlayUVs(self.hudBarOverlay.overlayId, 0, 0.05, 0, 1, self.sprayFillLevel / self.sprayCapacity, 0.05, self.sprayFillLevel / self.sprayCapacity, 1);
	self.hudBarOverlay:render();
	
	local urfState = self.isFertilizing;
	if urfState == 1 then
		self.hudOverlay = self.hudNoneOverlay;
	elseif urfState == 2 then
		self.hudOverlay = self.hudHalfOverlay;
	else
		self.hudOverlay = self.hudFullOverlay;
	end;
	self.hudOverlay:render();

	-- write fertilizer level
	setTextBold(true);
	setTextAlignment(RenderText.ALIGN_CENTER);

	setTextColor(0, 0, 0, 1);
	renderText(self.xPos + 0.075, self.yPos + 0.011, 0.017, string.format("%d (%d%%)", level, percent));
	if percent > 10 then
		setTextColor(1, 1, 1, 1);
	else
		setTextColor(1, 0, 0, 1);
	end;	
	renderText(self.xPos + 0.075, self.yPos + 0.013, 0.017, string.format("%d (%d%%)", level, percent));

	setTextColor(1, 1, 1, 1);
	setTextAlignment(RenderText.ALIGN_LEFT);
	setTextBold(false);
end;

function UrfSeeder:draw()
    if self.isClient then
        if self:getIsActiveForInput(true) then
			if (self.isFertilizing == 3) then
                    g_currentMission:addHelpButtonText(self.fertilizationText .. " " .. self.fullFertilizationText, InputBinding.URF_FERTILIZATION);
			elseif (self.isFertilizing == 2) then
                    g_currentMission:addHelpButtonText(self.fertilizationText .. " " .. self.partialFertilizationText, InputBinding.URF_FERTILIZATION);
			elseif (self.isFertilizing == 1) then
                    g_currentMission:addHelpButtonText(self.fertilizationText .. " " .. self.noFertilizationText, InputBinding.URF_FERTILIZATION);
			end;
        end;
		self:drawFillLevels();
    end;
end;

function UrfSeeder:setSprayFillLevel(sprayFillLevel, noEventSend)
    self.sprayFillLevel = sprayFillLevel;
    if self.sprayFillLevel > self.sprayCapacity then
        self.sprayFillLevel = self.sprayCapacity;
    end;
    if self.sprayFillLevel <= 0 then
        self.sprayFillLevel = 0;
    end;
	--synchronize fill level in mp
	UrfSeederFillLevelEvent.sendEvent(self, self.sprayFillLevel, noEventSend);
end;

function UrfSeeder:setIsFertilizing(urfState, noEventSend)
	--synchronize fertilization state in mp
	UrfSeederStateEvent.sendEvent(self, urfState, noEventSend);
	self.isFertilizing = urfState;
end;

function UrfSeeder:setIsSprayerFilling(isFilling, noEventSend)
    SprayerSetIsFillingEvent.sendEvent(self, isFilling, noEventSend)
    if self.isSprayerFilling ~= isFilling then
        self.isSprayerFilling = isFilling;
        if isFilling then
            -- find the first trigger which is activable
            self.sprayerFillTrigger = nil;
            for i=1, table.getn(self.sprayerFillTriggers) do
                local trigger = self.sprayerFillTriggers[i];
                if (self.currentSprayFillType == trigger.fillType) or (trigger.isSiloTrigger and g_currentMission:getSiloAmount(trigger.fillType) > 0) then
                    self.sprayerFillTrigger = trigger;
                    break;
                end;
            end;
        end
    end;
end;

function UrfSeeder:addSprayerFillTrigger(trigger)
    if table.getn(self.sprayerFillTriggers) == 0 then
        g_currentMission:addActivatableObject(self.sprayerFillActivatable);
    end;
    table.insert(self.sprayerFillTriggers, trigger);
end;

function UrfSeeder: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 or trigger == self.sprayerFillTrigger then
        if self.isServer then
            self:setIsSprayerFilling(false);
        end;
        if table.getn(self.sprayerFillTriggers) == 0 then
            g_currentMission:removeActivatableObject(self.sprayerFillActivatable);
        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";

    return self;
end;

function SprayerFillActivatable:getIsActivatable()
    if self.sprayer:getIsActiveForInput() and self.sprayer.sprayFillLevel < self.sprayer.sprayCapacity then
        -- find the first trigger which is activable
        for i=1, table.getn(self.sprayer.sprayerFillTriggers) do
            local trigger = self.sprayer.sprayerFillTriggers[i];
			if (self.sprayer.currentSprayFillType == trigger.fillType) or (trigger.isSiloTrigger and g_currentMission:getSiloAmount(trigger.fillType) > 0) then
                self:updateActivateText();
                return true;
            end;
        end;
    end
    return false;
end;

function SprayerFillActivatable:onActivateObject()
    self.sprayer:setIsSprayerFilling(not self.sprayer.isSprayerFilling);
    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("URF_STOP_REFILL"), self.sprayer.typeDesc);
    else
        self.activateText = string.format(g_i18n:getText("URF_REFILL"), self.sprayer.typeDesc);
    end;
end;

function UrfSeeder:fillUpSprayer(deltax)

	local oldFillLevel = self.sprayFillLevel;
	if self.sprayerFillTrigger.isSiloTrigger then
		local silo = g_currentMission:getSiloAmount(self.sprayerFillTrigger.fillType);
		deltax = math.min(deltax, silo);
		if deltax > 0 then
			self:setSprayFillLevel(oldFillLevel + deltax);
			deltax = self.sprayFillLevel - oldFillLevel;
			g_currentMission:setSiloAmount(self.sprayerFillTrigger.fillType, silo - deltax);
		end;
	else
		self:setSprayFillLevel(oldFillLevel + deltax);
		deltax = self.sprayFillLevel - oldFillLevel;

		local fillTypeDesc = Fillable.fillTypeIndexToDesc[self.sprayerFillTrigger.fillType];
		
		if fillTypeDesc ~= nil then	
			local price = deltax*fillTypeDesc.pricePerLiter;
			g_currentMission.missionStats.expensesTotal = g_currentMission.missionStats.expensesTotal + price;
			g_currentMission.missionStats.expensesSession = g_currentMission.missionStats.expensesSession + price;
			g_currentMission:addSharedMoney(-price, "other");
		end;
	end;
	return deltax;
end;