--
-- RealLoading
-- Specialization for RealLoading functionality
-- Redefinition of RealLoading-Specialization
-- Modified Trailer-Specialization
--
-- Modschmiede / LS-Modsource
-- @author  Manuel Leithner
-- @date  16/08/09
--

RealLoading = {};
RealLoading = {};

RealLoading.TIPSTATE_CLOSED = 0;
RealLoading.TIPSTATE_OPENING = 1;
RealLoading.TIPSTATE_OPEN = 2;
RealLoading.TIPSTATE_CLOSING = 3;

function RealLoading.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Attachable, specializations);
end;

function RealLoading:load(xmlFile)

    self.toggleTipState = SpecializationUtil.callSpecializationsFunction("toggleTipState");
    self.onStartTip = SpecializationUtil.callSpecializationsFunction("onStartTip");
    self.onEndTip = SpecializationUtil.callSpecializationsFunction("onEndTip");
    self.allowFillType = RealLoading.allowFillType;
    self.setFillLevel = SpecializationUtil.callSpecializationsFunction("setFillLevel");


    self.lastFillDelta = 0;
    self.fillLevel = 0;
    self.capacity = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.capacity"), 0.0);
    self.minThreshold = 0.05; -- fill level percentage that still allows overriding with another fruit type

    self.fillRootNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.fillRootNode#index"));
    if self.fillRootNode == nil then
        self.fillRootNode = self.components[1].node;
    end;

    self.grainPlanes = {};
    local i = 0;
    while true do
        local key = string.format("vehicle.grainPlane.node(%d)", i);
        local t = getXMLString(xmlFile, key.."#type");
        local index = getXMLString(xmlFile, key.."#index");
        if t==nil or index==nil then
            break;
        end;

        local node = Utils.indexToObject(self.components, index);
        if node ~= nil then
            setVisibility(node, false);
            if self.defaultGrainPlane == nil then
                self.defaultGrainPlane = node;
            end;
            self.grainPlanes[t] = node;
        end;
        i = i +1;
    end;
    if self.defaultGrainPlane==nil then
        self.grainPlanes = nil;
    end;
	local maxScalePlane = 0;
    self.grainPlaneMinY, self.grainPlaneMaxY = Utils.getVectorFromString(getXMLString(xmlFile, "vehicle.grainPlane#minMaxY"));
    if self.grainPlaneMinY == nil or self.grainPlaneMaxY == nil then
        local grainAnimCurve = AnimCurve:new(linearInterpolator4);
        local keyI = 0;
        while true do
            local key = string.format("vehicle.grainPlane.key(%d)", keyI);
            local t = getXMLFloat(xmlFile, key.."#time");
            local yValue = getXMLFloat(xmlFile, key.."#y");
            local scaleX,scaleY,scaleZ = Utils.getVectorFromString(getXMLString(xmlFile, key.."#scale"));
            if y == nil or scaleX == nil or scaleY == nil or scaleZ == nil then
                break;
            end;
			if t == 1 then
				maxScalePlane = scaleZ;
			end;
            grainAnimCurve:addKeyframe({x=scaleX, y=scaleY, z=scaleZ, w=yValue, time = t});
            keyI = keyI +1;
        end;
        if keyI > 0 then
            self.grainAnimCurve = grainAnimCurve;
        end;
        self.grainPlaneMinY = 0;
        self.grainPlaneMaxY = 0;
    end;

	self.tipDischargeEndTime = nil;
	
    local tipAnimRootNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tipAnimation#rootNode"));
    self.tipAnimCharSet = 0;
    if tipAnimRootNode ~= nil and tipAnimRootNode ~= 0 then
        self.tipAnimCharSet = getAnimCharacterSet(tipAnimRootNode);
        if self.tipAnimCharSet ~= 0 then
            local clip = getAnimClipIndex(self.tipAnimCharSet, getXMLString(xmlFile, "vehicle.tipAnimation#clip"));
            assignAnimTrackClip(self.tipAnimCharSet, 0, clip);
            setAnimTrackLoopState(self.tipAnimCharSet, 0, false);
            self.tipAnimSpeedScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.tipAnimation#speedScale"), 1);
            self.tipAnimDuration = getAnimClipDuration(self.tipAnimCharSet, clip);
            if self.tipDischargeEndTime == nil then
                self.tipDischargeEndTime = self.tipAnimDuration*2.0;
            end;
        end;
    end;
    self.tipState = RealLoading.TIPSTATE_CLOSED;

    self.tipReferencePoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tipReferencePoint#index"));
    if self.tipReferencePoint == nil then
        self.tipReferencePoint = self.components[1].node;
    end;

	
	self.realLoading = {};
	self.realLoading.trailerEnd = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.realLoading#trailerEnd"));
	local x,y,z = getTranslation(self.realLoading.trailerEnd);
	self.realLoading.maxDistance = math.abs(z);
	self.realLoading.maxZ = z;
	self.realLoading.minZ = 0;
	self.realLoading.ScaleZDif = Utils.getNoNil(1-maxScalePlane,0);
	self.realLoading.unloadingTime = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.realLoading#unloadingTime"), 10)*1000;
	
	self.tipDischargeEndTime = self.realLoading.unloadingTime;
	
	
    self.dischargeParticleSystems = {};
	local i = 0;
    while true do
        local key = string.format("vehicle.dischargeParticleSystems.dischargeParticleSystem(%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/trailerDischargeParticleSystem.i3d", self.baseDirectory);
            self.dischargeParticleSystems[desc.index] = currentPS;
            if self.defaultdischargeParticleSystems == nil then
                self.defaultdischargeParticleSystems = currentPS;
            end;
        end;
        i = i + 1;
    end;
    
    self.fillTypes = {};
    self.fillTypes[FruitUtil.FRUITTYPE_UNKNOWN] = true;

    local fruitTypes = getXMLString(xmlFile, "vehicle.fillTypes#fruitTypes");
    if fruitTypes ~= nil then
        local types = Utils.splitString(" ", fruitTypes);
        for k,v in pairs(types) do
            local desc = FruitUtil.fruitTypes[v];
            if desc ~= nil then
                self.fillTypes[desc.index] = true;
            end;
        end;
    end;
    
    local hydraulicSound = getXMLString(xmlFile, "vehicle.hydraulicSound#file");
    if hydraulicSound ~= nil and hydraulicSound ~= "" then
		hydraulicSound = Utils.getFilename(hydraulicSound, self.baseDirectory);
        self.hydraulicSound = createSample("hydraulicSound");
        loadSample(self.hydraulicSound, hydraulicSound, false);
        self.hydraulicSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.hydraulicSound#pitchOffset"), 1);
        self.hydraulicSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.hydraulicSound#pitchMax"), 2.0);
        self.hydraulicSoundEnabled = false;
    end;    
    
    local fillSound = getXMLString(xmlFile, "vehicle.fillSound#file");
    if fillSound ~= nil and fillSound ~= "" then
        self.fillSound = createSample("fillSound");
        loadSample(self.fillSound, fillSound, false);
        self.fillSoundPitchOffset = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fillSound#pitchOffset"), 1);
        self.fillSoundVolume = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.fillSound#pitchMax"), 2.0);
        self.fillSoundEnabled = false;
    end;

    self.currentFillType = FruitUtil.FRUITTYPE_UNKNOWN;

    self.allowFillFromAir = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.allowFillFromAir#value"), true);
    self.allowTipDischarge = Utils.getNoNil(getXMLBool(xmlFile, "vehicle.allowTipDischarge#value"), true);

    self.massScale = 1.3*0.0001*0.7 *Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.massScale#value"), 1);

    setUserAttribute(self.fillRootNode, "vehicleType", "Integer", 2);
    self:setFillLevel(0, FruitUtil.FRUITTYPE_UNKNOWN);
	self.emptyTime = 3000;
	self.lastGrainPlane = nil;
	self.setTime = true;
	
	self.runOnce = true;

end;

function RealLoading:delete()
    Utils.deleteParticleSystem(self.dischargeParticleSystems);
    
    if self.hydraulicSound ~= nil then
        delete(self.hydraulicSound);
    end;    
    if self.fillSound ~= nil then
        delete(self.fillSound);
    end;
    
end;

function RealLoading:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
    local fillLevel = getXMLFloat(xmlFile, key.."#fillLevel");
    local fillType = getXMLString(xmlFile, key.."#fillType");
    if fillLevel ~= nil and fillType ~= nil then
        local fillTypeDesc = FruitUtil.fruitTypes[fillType];
        if fillTypeDesc ~= nil then
            self:setFillLevel(fillLevel, fillTypeDesc.index);
        end;
    end;
    return BaseMission.VEHICLE_LOAD_OK;
end;

function RealLoading:getSaveAttributesAndNodes(nodeIdent)
    local fillType = "unknown";
    if self.currentFillType ~= FruitUtil.FRUITTYPE_UNKNOWN then
        fillType = FruitUtil.fruitIndexToDesc[self.currentFillType].name;
    end;
    local attributes = 'fillLevel="'..self.fillLevel..'" fillType="'..fillType..'"';
    return attributes, nil;
end;

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

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

function RealLoading:update(dt)
	if self:getIsActive() then
		self.lastFillDelta = 0;
		
		if self.tipState == RealLoading.TIPSTATE_OPENING or self.tipState == RealLoading.TIPSTATE_OPEN then      
			self.isHayBaseActive = true;
			self.hayBase.speed = self.hayBase.unloadingSpeed;
			
			local isReadyForUnloading = false;
			local isEmpty = false;
			
			if self.fillLevel > 0 then
				local grainPlane;
				if self.currentFillType ~= FruitUtil.FRUITTYPE_UNKNOWN then
					local fillTypeName = FruitUtil.fruitIndexToDesc[self.currentFillType].name;
					grainPlane = self.grainPlanes[fillTypeName];
				end;
				if grainPlane == nil then
					grainPlane = self.defaultGrainPlane;
				end;
				local x,y,z = getTranslation(grainPlane);
				local currentPosition = (self.realLoading.maxDistance - math.abs(z)) / self.realLoading.maxDistance;
				local xScale,yScale,zScale = getScale(grainPlane);
				if currentPosition <= zScale+self.realLoading.ScaleZDif then
					isReadyForUnloading = true;
				end;	
				
				local curX,curY,curZ = getTranslation(grainPlane);	
				local newZ = Utils.getMovedLimitedValues({curZ}, {self.realLoading.maxZ}, {self.realLoading.minZ}, 1, self.realLoading.unloadingTime, dt, false);
				setTranslation(grainPlane, curX,curY, newZ[1]);	
			else
				isReadyForUnloading = true;
				isEmpty = true;
			end;
			
			if isReadyForUnloading then		
				local m = self.capacity/(self.tipDischargeEndTime/self.tipAnimSpeedScale);
				local curFill = self.fillLevel;
				self:setFillLevel(self.fillLevel - (m* dt), self.currentFillType);
				self.lastFillDelta = self.fillLevel - curFill;

				g_currentMission.trailerIsTipping = true;

				if self.currentFillType ~= FruitUtil.FRUITTYPE_UNKNOWN and self.currentTipTrigger ~= nil then

					if self.currentTipTrigger.isFarmTrigger then
						-- put load into storage
						g_currentMission.missionStats.farmSiloFruitAmount[self.currentFillType] = g_currentMission.missionStats.farmSiloFruitAmount[self.currentFillType] - self.lastFillDelta;

					else
						-- increase money according to price of current fill type
						local priceMultiplier = self.currentTipTrigger.priceMultipliers[self.currentFillType];  
						local difficultyMultiplier = math.max(3 * (3 - g_currentMission.missionStats.difficulty), 1); -- 1  3  6
						local money = FruitUtil.fruitIndexToDesc[self.currentFillType].pricePerLiter * priceMultiplier * difficultyMultiplier * self.lastFillDelta;
						g_currentMission.missionStats.money = g_currentMission.missionStats.money - money;
					end;

					if self.lastFillDelta < 0 then
						self.currentTipTrigger:updateMoving(-self.lastFillDelta);
					end;

				end;
				
				if not self.hydraulicSoundEnabled and self.hydraulicSound ~= nil and self:getIsActiveForSound() then
					playSample(self.hydraulicSound, 0, self.hydraulicSoundVolume, 0);
					setSamplePitch(self.hydraulicSound, self.hydraulicSoundPitchOffset-0.4);
					self.hydraulicSoundEnabled = true;  
				end;            
				
				if not self.fillSoundEnabled and self.fillLevel > 0 and self.fillSound ~= nil and self:getIsActiveForSound() then
					playSample(self.fillSound, 0, self.fillSoundVolume, 0);
					self.fillSoundEnabled = true;   
				end;
				
				if self.fillSoundEnabled and self.fillLevel == 0 then
					stopSample(self.fillSound);
					self.fillSoundEnabled = false;   
				end;

				if self.tipState == RealLoading.TIPSTATE_OPENING then
					if getAnimTrackTime(self.tipAnimCharSet, 0) > self.tipAnimDuration then
						self.tipState = RealLoading.TIPSTATE_OPEN;
					end;
				else
					if isEmpty then
						self.emptyTime = self.emptyTime - dt;
					end;	
					if self.emptyTime <= 0 then
						self.setTime = true;
						self:onEndTip();
					end;
				end;
				
				if self.tipState == RealLoading.TIPSTATE_OPEN then
					if self.hydraulicSoundEnabled then
						stopSample(self.hydraulicSound);
						self.hydraulicSoundEnabled = false;   
					end;
				end;
			end;
			
		elseif self.tipState == RealLoading.TIPSTATE_CLOSING then
		
			if not self.hydraulicSoundEnabled and self.hydraulicSound ~= nil and self:getIsActiveForSound() then
				playSample(self.hydraulicSound, 0, self.hydraulicSoundVolume, 0);
				setSamplePitch(self.hydraulicSound, self.hydraulicSoundPitchOffset);
				self.hydraulicSoundEnabled = true;   
			end;

			g_currentMission.trailerIsTipping = false;

			if getAnimTrackTime(self.tipAnimCharSet, 0) < 0.0 then
				g_currentMission.allowSteerableMoving = true;
				g_currentMission.fixedCamera = false;
				self.tipState = RealLoading.TIPSTATE_CLOSED;
			end;
		elseif self.tipState == RealLoading.TIPSTATE_CLOSED then
			if self.hydraulicSoundEnabled then
				stopSample(self.hydraulicSound);
				self.hydraulicSoundEnabled = false;   
			end;
		end;
		
		Utils.setEmittingState(self.dischargeParticleSystems[self.currentFillType], self.lastFillDelta < 0);

		if self.firstTimeRun then
			if self.emptyMass == nil then
				self.emptyMass = getMass(self.fillRootNode);
				self.currentMass = self.emptyMass;
			end;
			local newMass = self.emptyMass + self.fillLevel*self.massScale;
			if newMass ~= self.currentMass then
				setMass(self.fillRootNode, newMass);
				self.currentMass = newMass;
				for k,v in pairs(self.components) do
					if v.node == self.fillRootNode then
						if v.centerOfMass ~= nil then
							setCenterOfMass(v.node, v.centerOfMass[1], v.centerOfMass[2], v.centerOfMass[3]);
						end;
						break;
					end;
				end;
			end;
		end;
	end;
end;

function RealLoading:draw()

    if self.currentFillType ~= FruitUtil.FRUITTYPE_UNKNOWN then
        local overlay = g_currentMission.fruitOverlays[self.currentFillType];
        if overlay ~= nil then
            g_currentMission.fruitOverlays[self.currentFillType]:render();
        end;
    end;

end;

function RealLoading:toggleTipState(currentTipTrigger)

    if self.tipState == 0 then
        self:onStartTip(currentTipTrigger);
    else
		if self.fillLevel <= 0 then
			self:onEndTip();
		end;
    end;
end;


function RealLoading:onStartTip(currentTipTrigger)

    self.currentTipTrigger = currentTipTrigger;
    if self.tipAnimCharSet ~= 0 then
        if getAnimTrackTime(self.tipAnimCharSet, 0) < 0.0 then
            setAnimTrackTime(self.tipAnimCharSet, 0, 0.0);
        end;
        setAnimTrackSpeedScale(self.tipAnimCharSet, 0, self.tipAnimSpeedScale);
        enableAnimTrack(self.tipAnimCharSet, 0);
    end;
    self.tipState = RealLoading.TIPSTATE_OPENING;
    g_currentMission.allowSteerableMoving = false;
end;

function RealLoading:onEndTip()
    self.currentTipTrigger = nil;
    if self.tipAnimCharSet ~= 0 then
        if getAnimTrackTime(self.tipAnimCharSet, 0) > self.tipAnimDuration then
            setAnimTrackTime(self.tipAnimCharSet, 0, self.tipAnimDuration);
        end;
        setAnimTrackSpeedScale(self.tipAnimCharSet, 0, -self.tipAnimSpeedScale);
        enableAnimTrack(self.tipAnimCharSet, 0);
    end;
    self.tipState = RealLoading.TIPSTATE_CLOSING;
	self.isTurnedOn = false;
	self.emptyTime = 3000;
	self.hayBase.speed = self.hayBase.loadingSpeed;
	self.isHayBaseActive = false;
	if self.lastGrainPlane ~= nil then
		setTranslation(self.lastGrainPlane, 0,0,0);
	end;
end;

function RealLoading:allowFillType(fillType, allowEmptying)
    local allowed = false;

    if self.fillTypes[fillType] then
        if self.currentFillType ~= FruitUtil.FRUITTYPE_UNKNOWN then
            if self.currentFillType ~= fillType then
                if self.fillLevel / self.capacity <= self.minThreshold then
                    allowed = true; -- fill level is low enough to be overridden
                    if allowEmptying then
                        self.fillLevel = 0; -- empty the trailer
                    end;
                end;
            else
                allowed = true; -- fill type is the same as the trailer's current fill type
            end;
        else
            allowed = true; -- trailer is empty --> FruitUtil.FRUITTYPE_UNKNOWN
        end;
    end;

    return allowed;
end;

function RealLoading:setFillLevel(fillLevel, fillType)
    if not self:allowFillType(fillType, false) then
        return;
    end;
	local isUnloading = false;
	if self.fillLevel > fillLevel then
		isUnloading = true;
	end;
    self.currentFillType = fillType;
    self.fillLevel = fillLevel;
    if self.fillLevel > self.capacity then
        self.fillLevel = self.capacity;
    end;
    if self.fillLevel < 0 then
        self.fillLevel = 0;
        -- reset fill type as the trailer is empty
        Utils.setEmittingState(self.dischargeParticleSystems[self.currentFillType], false);
        self.currentFillType = FruitUtil.FRUITTYPE_UNKNOWN;
    end;
	if self.fillLevel <= 0 then
		if self.setTime then
			self.emptyTime = 3000;
			self.setTime = false;
		end;
	end;
    if self.currentGrainPlane ~= nil then
        setVisibility(self.currentGrainPlane, false);
    end;
    if self.grainPlanes ~= nil and self.defaultGrainPlane ~= nil and fillType ~= FruitUtil.FRUITTYPE_UNKNOWN then
		self.lastGrainPlane = self.grainPlanes[fillTypeName];
		local fillTypeName = FruitUtil.fruitIndexToDesc[fillType].name;
		local grainPlane = self.grainPlanes[fillTypeName];
		if grainPlane == nil then
			grainPlane = self.defaultGrainPlane;
		end;	
		self.lastGrainPlane	 = grainPlane;	
		local yTranslation;
		if self.grainAnimCurve then
			local percentage = self.fillLevel / self.capacity;		
			local scaleX, scaleY, scaleZ , yTrans = self.grainAnimCurve:get(percentage);
			if percentage > 0.3 and not self.runOnce and self.isTurnedOn then
				self.isHayBaseActive = true;
			end;
			yTranslation = yTrans;
			if not isUnloading then
				setScale(grainPlane, scaleX, scaleY, scaleZ);
			else
				local curX,curY, curZ = getScale(grainPlane);
				setScale(grainPlane, curX, curY, scaleZ);
			end;		
		else
			local m = (self.grainPlaneMaxY - self.grainPlaneMinY) / self.capacity;
			yTranslation = m*self.fillLevel + self.grainPlaneMinY;
		end;
		local xPos, yPos, zPos = getTranslation(grainPlane);
		setTranslation(grainPlane, xPos, yTranslation, zPos);
		self.currentGrainPlane = grainPlane;
		setVisibility(grainPlane, self.fillLevel > 0);
    end;
	if self.fillLevel >= self.capacity then
		self.isTurnedOn = false;
		self.isHayBaseActive = false;
		self.pickup.isDown = false;
	end;
	self.runOnce = false;
end;


function RealLoading:onDetach()
    if self.deactivateOnDetach then
        RealLoading.onDeactivate(self);
    else
        RealLoading.onDeactivateSounds(self);
    end;
end;

function RealLoading:onLeave()
    if self.deactivateOnLeave then
        RealLoading.onDeactivate(self);
    else
        RealLoading.onDeactivateSounds(self);
    end;
end;

function RealLoading:onDeactivate()
    RealLoading.onDeactivateSounds(self);
end;

function RealLoading:onDeactivateSounds()
    if self.fillSoundEnabled and self.fillLevel == 0 then
        stopSample(self.fillSound);
        self.fillSoundEnabled = false;   
    end;
    if self.hydraulicSoundEnabled then
        stopSample(self.hydraulicSound);
        self.hydraulicSoundEnabled = false;   
    end;
end;


