--
-- overload
-- Class 3 side Tippers
--
-- @author  Geri-G
-- @date  13/07/10
--
-- Copyright (C) Geri-G

overload = {};

function overload.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Fillable, specializations) and SpecializationUtil.hasSpecialization(Attachable, specializations) and SpecializationUtil.hasSpecialization(AnimatedVehicle, specializations);
end;

function overload:load(xmlFile)

	self.startOverLoad = overload.startOverLoad;
	self.setOverloadPipeParticle = overload.setOverloadPipeParticle;
	self.setObjectInRange = overload.setObjectInRange;
	self.onEnterULWTrigger = overload.onEnterULWTrigger;
	self.isULWFromGeri = true;
	if self.sides== nil then
		self.sides = {};
	end;
	if self.particleSystems== nil then
		self.particleSystems = {};
	end;
	self.ULW = {};
	
	if getXMLBool(xmlFile,"vehicle.ulw#hasULW") then

		self.sides[4] = "ULW";
		local v = "ULW";
		local base = "vehicle.ulw";
		
		if self.is3SideTipperFromGeri then

			self.particleSystems[v] = self.particleSystems["back"];
			self.tipAnims[v] = self.tipAnims["back"];
			self.hydraulics.nodes[v] = self.hydraulics.nodes["back"];
			self.tipReferencePoints[v] = {};
			local entry = {};
			
			entry.tipReferencePoint = Utils.indexToObject(self.components, getXMLString(xmlFile, string.format("vehicle.tipReferencePoint#%s",v)));
			if entry.tipReferencePoint == nil then
				entry.tipReferencePoint = self.components[1].node;
			end;
			self.tipReferencePoints[v] = entry;
		else
			self.particleSystems[v] = {};
		end;
		
		
		
		self.ULW.fruitTypes= {};
		self.ULW.fillTypes= {};
		self.ULW.fruitTypes[FruitUtil.FRUITTYPE_UNKNOWN] = false;
		self.ULW.fillTypes[FruitUtil.FRUITTYPE_UNKNOWN] = false;
		local fruitTypes = getXMLString(xmlFile, base .. ".discharge#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.ULW.fruitTypes[desc.index] = true;
					self.ULW.fillTypes[FruitUtil.fruitTypeToFillType[desc.index]] = true;
					self.ULW.fillTypes[Fillable.fillTypeNameToInt["seeds"]] = true;
				end;
			end;
		end;
		self.particleSystems[v].dischargeParticleSystems2 = {};
		local i = 0;
		while true do
			local key = string.format("%s.dischargeParticleSystems%s.dischargeParticleSystem(%d)",base,v,i);
			local t = getXMLString(xmlFile, key .. "#type");
			if t == nil then
				break;
			end;			
			local desc = FruitUtil.fruitTypes[t];
			if desc ~= nil then
				if self.ULW.fruitTypes[desc.index] then
				
					local fillType = FruitUtil.fruitTypeToFillType[desc.index]
					local currentPS = {};

					local particleNode = Utils.loadParticleSystem(xmlFile, currentPS, key, self.components, false, "$data/vehicles/particleSystems/trailerDischargeParticleSystem.i3d", self.baseDirectory);

					self.particleSystems[v].dischargeParticleSystems2[fillType] = currentPS;
				end;
			end;
			i = i + 1;
		end;
		
		
		if self.playAnimation~= nil and self.animations ~= nil then
			self.ULW.animation = {};
			local animationName = getXMLString(xmlFile,base..".Anim#TipanimationName");
			if animationName ~= nil then
				if self.animations[animationName]~= nil then					
					self.ULW.animation.animationName = animationName;
				end;
			end;			
			local animationName = getXMLString(xmlFile,base..".Anim#DooranimationName");
			if animationName ~= nil then
				if self.animations[animationName]~= nil then
					self.ULW.animation.animationName2 = animationName;
				end;
			end;
		end;

		
		self.ULW.triggerNode = Utils.indexToObject(self.components,getXMLString(xmlFile,base..".trigger#node"));
		self.ULW.schneckeNode = Utils.indexToObject(self.components,getXMLString(xmlFile,base..".schnecke#node"));
		self.TankUnloadingCapacity = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.TankUnloadingCapacity"), 100);
		setVisibility(self.ULW.schneckeNode,false);
		self.ULW.vehicleInRange = nil;
		local file = Utils.getFilename("textures/hudOverloadOverlay.png", self.baseDirectory);
		self.hudOverloadOverlay = Overlay:new("hudOverloadOverlay", file, 0.935, 0.18, 0.06, 0.06 * (4 / 3));
	end;
	self.DooranimIsEnabled = false;
	self.TipanimIsEnabled = false;
	self.OverLoadIsActiv = false;
	self.objectInRange = false;
	self.pipeParticleActivated = false;
	self.isAttachedVehicleULW = false;
	
	
end;

function overload:delete()
	for k,v in pairs(self.particleSystems) do
		if v.dischargeParticleSystems2 ~= nil then
			Utils.deleteParticleSystem(v.dischargeParticleSystems);
		end;
	end; 	
end;

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

function overload:keyEvent(unicode, sym, modifier, isDown)
end;
function overload:readStream(streamId, connection)
	local pipeParticleActivated = streamReadBool(streamId);
	self.OverLoadIsActiv = streamReadBool(streamId);
	self.objectInRange = networkGetObject(streamReadInt32(streamId));
	self:setOverloadPipeParticle(pipeParticleActivated,true);
end;
function overload:writeStream(streamId, connection)
	streamWriteBool(streamId, self.pipeParticleActivated);
	streamWriteBool(streamId, self.OverLoadIsActiv);
	streamWriteInt32(streamId, networkGetObject(self.objectInRange));
	--todo: particel,overloading, obejctinrange
end;
function overload:update(dt)
	--if self:getIsActive() then

	if self:getIsActiveForInput() then
		if not self.attacherVehicle.isULWFromGeri and not self.is3SideTipperFromGeri then
			if InputBinding.hasEvent(InputBinding.FLIEGLTipperGeriG_Overload) and self.tipState == Trailer.TIPSTATE_CLOSED then
				if not self.objectInRange and self:getRealAnimationTime(self.ULW.animation.animationName) <=0 then
				
				else
					----print(tostring(not self.OverLoadIsActiv));
					if self.ULW.fillTypes[self.currentFillType] then
						self:startOverLoad(not self.OverLoadIsActiv);
					end;
				end;
			end;
		end;
	end;

end;
function overload:updateTick(dt)
	if self.isServer and self:getIsActive() then
		local pipePSActiv = false;
		if self.OverLoadIsActiv and self.ULW.vehicleInRange and self.fillLevel >0 then
			local trailer = self.ULW.vehicleInRange;
			if trailer.setSeedIndex then
				if not trailer:allowFillType(Fillable.fillTypeNameToInt["seeds"], true) or not trailer.allowFillFromAir then
					pipePSActiv = false;
				else	
					pipePSActiv = true;
					
					local deltaLevel = self.TankUnloadingCapacity*dt/1000.0;

					deltaLevel = math.min(deltaLevel, trailer.capacity - trailer.fillLevel);
					local fillLevel = self.fillLevel;
					

					fillLevel = fillLevel-deltaLevel;
					if fillLevel <= 0.0 then
						deltaLevel = deltaLevel+fillLevel;
						fillLevel = 0.0;
						pipePSActiv = false;
					end;		
					if deltaLevel == 0 then
						pipePSActiv = false;
					end;
					local loaded = FruitUtil.fruitTypeToFillType[trailer.seeds[trailer.currentSeed]] == self.currentFillType or trailer.fillLevel <=0;
					if loaded then
						self:setFillLevel(fillLevel, self.currentFillType);
						trailer:setFillLevel(trailer.fillLevel+deltaLevel, Fillable.fillTypeNameToInt["seeds"]);
						trailer:setSeedFruitType(FruitUtil.fillTypeToFruitType[self.currentFillType]);
					else
						pipePSActiv = false;
						self:startOverLoad(false);
					end;
					if trailer.capacity <= trailer.fillLevel then
						self:startOverLoad(false);
					end;
					local percent = self.fillLevel/self.capacity*100;
					if not self.DooranimIsEnabled then
						self:playAnimation(self.ULW.animation.animationName2,1,nil,nil);
						self.DooranimIsEnabled = true;
					end;
					if percent <= 10 then
						if not self.TipanimIsEnabled then
							self:playAnimation(self.ULW.animation.animationName,1.5,nil,nil);
							self.TipanimIsEnabled = true;
						end;
					end;
				end;
			else
				if not trailer:allowFillType(self.currentFillType, true) or not trailer.allowFillFromAir then
					pipePSActiv = false;
				else	
					pipePSActiv = true;
					
					local deltaLevel = self.TankUnloadingCapacity*dt/1000.0;
					deltaLevel = self.TankUnloadingCapacity*dt/1000.0;
					deltaLevel = math.min(deltaLevel, trailer.capacity - trailer.fillLevel);
					local fillLevel = self.fillLevel;

					fillLevel = fillLevel-deltaLevel;
					if fillLevel <= 0.0 then
						deltaLevel = deltaLevel+fillLevel;
						fillLevel = 0.0;
						pipePSActiv = false;
					end;		
					if deltaLevel == 0 then
						pipePSActiv = false;
					end;
					self:setFillLevel(fillLevel, self.currentFillType);
					trailer:setFillLevel(trailer.fillLevel+deltaLevel, self.currentFillType);
					
					if trailer.capacity <= trailer.fillLevel then
						self:startOverLoad(false);
					end;
					local percent = self.fillLevel/self.capacity*100;
					if not self.DooranimIsEnabled then
						self:playAnimation(self.ULW.animation.animationName2,1,nil,nil);
						self.DooranimIsEnabled = true;
					end;
					if percent <= 20 then
						if not self.TipanimIsEnabled then
							self:playAnimation(self.ULW.animation.animationName,1.5,nil,nil);
							self.TipanimIsEnabled = true;
						end;
					end;
				end;
			end;
		else
			if not self.isAttachedVehicleULW then
				self:startOverLoad(false);
			end;
			if self.TipanimIsEnabled then
				self:playAnimation(self.ULW.animation.animationName,-1.5,nil,nil);
				self.TipanimIsEnabled = false;
			end;
			if self.DooranimIsEnabled then
				self:playAnimation(self.ULW.animation.animationName2,-1.5,nil,nil);
				self.DooranimIsEnabled = false;
			end;
		end;
		self:setOverloadPipeParticle(pipePSActiv);

	elseif not self:getIsActive() then
		self:setOverloadPipeParticle(false);
		self:startOverLoad(false);
		if self.DooranimIsEnabled then
			self:playAnimation(self.ULW.animation.animationName2,-1.5,nil,nil);
			self.DooranimIsEnabled = false;
		end;
	end;
end;
function overload:draw()
	if self:getIsActive() and self.tipState == Trailer.TIPSTATE_CLOSED then--and not self.attacherVehicle.is3SideTipperFromGeri then
		if not self.attacherVehicle.isULWFromGeri then
			if self.objectInRange~= false and self.objectInRange ~= nil and self.ULW.fillTypes[self.currentFillType] then
				if self.objectInRange.fillLevel ~= nil then
					local loaded = true;	
					if self.objectInRange.seeds ~= nil then
						loaded = FruitUtil.fruitTypeToFillType[self.objectInRange.seeds[self.objectInRange.currentSeed]] == self.currentFillType or self.objectInRange.fillLevel <=0;
					else
						loaded = self.objectInRange:allowFillType(self.currentFillType, true)
					end;
					if loaded then
						if not self.is3SideTipperFromGeri then
							g_currentMission:addHelpButtonText(g_i18n:getText("startOverLoad"), InputBinding.FLIEGLTipperGeriG_Overload);
						else
							g_currentMission:addHelpButtonText(g_i18n:getText("startOverLoad"), InputBinding.FLIEGLTipperGeriG_changeTipperMode);
						end;
						
						self.hudOverloadOverlay:render();
					end;
				
					local percent = self.objectInRange.fillLevel/self.objectInRange.capacity*100;
					
					local fillType = "";
					if self.objectInRange.seeds ~= nil then
						fillType = self.objectInRange.seeds[self.objectInRange.currentSeed];
					else
						fillType = FruitUtil.fillTypeToFruitType[self.objectInRange.currentFillType];
					end;
					if fillType ~= 0 and fillType~= nil then
						fillType = FruitUtil.fruitIndexToDesc[fillType].name;
						fillType = g_i18n:getText(fillType);
						g_currentMission:addExtraPrintText(string.format(g_i18n:getText("overloadedVehicleFillstate"),percent,"%",fillType));
					end;
				end;
			end;
		end;
	end;
end;
function overload:onDetach()
	self:startOverLoad(false,true);
	self:setOverloadPipeParticle(false,true);
	if self.ULW.triggerNode and not self.is3SideTipperFromGeri then
		removeTrigger(self.ULW.triggerNode);
		self.ULW.vehicleInRange = nil;
	end;
end;
function overload:onAttach(attacherVehicle)
	if self.ULW.triggerNode and not self.is3SideTipperFromGeri then
		addTrigger(self.ULW.triggerNode, "onEnterULWTrigger", self);
	end;
end;
function overload:onDeactivate()
	self:startOverLoad(false,true);
	self:setOverloadPipeParticle(false,true);
	
end;
function overload:attachImplement(implement)
	--self:setTipSide(self.currentSide,true);
	self:startOverLoad(false,true);
	self:setObjectInRange(false,true);

end;
function overload:detachImplement(implementIndex)
	self:setTipSide(self.currentSide,true);
	self:startOverLoad(false,true);
	self:setObjectInRange(false,true);
end;

function overload:startOverLoad(startOverLoad,noEventSend)
	if self.OverLoadIsActiv ~= startOverLoad then	
		local isFlieglULWAtteched = false;
		for k,v in pairs(self.attachedImplements) do
			if v.object.is3SideTipperFromGeri == true then
				isFlieglULWAtteched = v.object:startOverLoad(startOverLoad,false);				
			end;
		end;
		----print(pref.."isFlieglULWAtteched "..tostring(isFlieglULWAtteched));		
		if isFlieglULWAtteched == false then			
			startOverLoadEvent.sendEvent(self, startOverLoad, noEventSend);
		else

		end;
		self.OverLoadIsActiv = startOverLoad;
		----print(pref.."self.OverLoadIsActiv "..tostring(self.OverLoadIsActiv));
	end;
	return self.sides[4];
end;

function overload:setObjectInRange(objectInRange,noEventSend)
	setFillableInFlieglRangeEvent.sendEvent(self, objectInRange, noEventSend)
	if self.attacherVehicle then
		if self.attacherVehicle.is3SideTipperFromGeri then
			self.attacherVehicle:setObjectInRange(objectInRange,true);
		end;
	end;
	self.objectInRange = objectInRange;
end;
function overload:setOverloadPipeParticle(pipeParticleActivated,noEventSend)

	if self.pipeParticleActivated ~= pipeParticleActivated then
		setPipeParticelActivEvent.sendEvent(self, pipeParticleActivated, noEventSend)
		
		self.pipeParticleActivated = pipeParticleActivated;
		local pss = self.particleSystems[self.sides[4]].dischargeParticleSystems2;
		for k,v in pairs(pss) do

			if k == self.currentFillType then
				Utils.setEmittingState(v, pipeParticleActivated);
				
			else
				Utils.setEmittingState(v, false);
			end;
		end;
	end;
end;
function overload:onEnterULWTrigger(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
	if onEnter and self.ULW.vehicleInRange ==nil then
		local vehicle = g_currentMission.nodeToVehicle[otherShapeId];
		if vehicle ~= nil then
			if vehicle ~= self and vehicle.setFillLevel	then
				self.ULW.vehicleInRange = vehicle;
				self:setObjectInRange(vehicle);
			end;
		end;
	elseif onLeave then
		local vehicle = g_currentMission.nodeToVehicle[otherShapeId];
		if self.ULW.vehicleInRange == vehicle then
			self.ULW.vehicleInRange = nil;
			self:setObjectInRange(false);
		end;
	end;
end;
setPipeParticelActivEvent = {};
setPipeParticelActivEvent_mt = Class(setPipeParticelActivEvent, Event);

InitEventClass(setPipeParticelActivEvent, "setPipeParticelActivEvent");

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

function setPipeParticelActivEvent:new(object, pipeParticleActivated)
    local self = setPipeParticelActivEvent:emptyNew()
    self.object = object;
	self.pipeParticleActivated = pipeParticleActivated;
    return self;
end;

function setPipeParticelActivEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.pipeParticleActivated = streamReadBool(streamId);
	if self.pipeParticleActivated == nil then
		--print("self.pipeParticleActivated nil 1");
	end;
    self.object = networkGetObject(id);
    self:run(connection);
end;

function setPipeParticelActivEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.object));
	if self.pipeParticleActivated == nil then
		--print("self.pipeParticleActivated nil 2");
	end;
	streamWriteBool(streamId, self.pipeParticleActivated);
end;

function setPipeParticelActivEvent:run(connection)
	self.object:setOverloadPipeParticle(self.pipeParticleActivated, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(setPipeParticelActivEvent:new(self.object, self.pipeParticleActivated), nil, connection, self.object);
    end;	
end;

function setPipeParticelActivEvent.sendEvent(vehicle, pipeParticleActivated, noEventSend)
	if pipeParticleActivated ~= vehicle.pipeParticleActivated then
		if noEventSend == nil or noEventSend == false then
			if g_server ~= nil then
				g_server:broadcastEvent(setPipeParticelActivEvent:new(vehicle, pipeParticleActivated), nil, nil, vehicle);
			else
				g_client:getServerConnection():sendEvent(setPipeParticelActivEvent:new(vehicle, pipeParticleActivated));
			end;
		end;
	end;
end;
setFillableInFlieglRangeEvent = {};
setFillableInFlieglRangeEvent_mt = Class(setFillableInFlieglRangeEvent, Event);

InitEventClass(setFillableInFlieglRangeEvent, "setFillableInFlieglRangeEvent");

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

function setFillableInFlieglRangeEvent:new(object, ObjectInRange)
    local self = setFillableInFlieglRangeEvent:emptyNew()
    self.object = object;
	self.ObjectInRange = ObjectInRange;
    return self;
end;

function setFillableInFlieglRangeEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	local ObjectInRange = streamReadInt32(streamId);
    self.object = networkGetObject(id);
    self.ObjectInRange = networkGetObject(ObjectInRange);
    self:run(connection);
end;

function setFillableInFlieglRangeEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.object));
	streamWriteInt32(streamId, networkGetObjectId(self.ObjectInRange));

end;

function setFillableInFlieglRangeEvent:run(connection)
	self.object:setObjectInRange(self.ObjectInRange, true);

    if not connection:getIsServer() then
        g_server:broadcastEvent(setFillableInFlieglRangeEvent:new(self.object, self.ObjectInRange), nil, connection, self.object);
    end;	
end;

function setFillableInFlieglRangeEvent.sendEvent(vehicle, ObjectInRange, noEventSend)
	
	if ObjectInRange ~= vehicle.ObjectInRange then
		if noEventSend == nil or noEventSend == false then
			if g_server ~= nil then
				g_server:broadcastEvent(setFillableInFlieglRangeEvent:new(vehicle, ObjectInRange), nil, nil, vehicle);
			else
				g_client:getServerConnection():sendEvent(setFillableInFlieglRangeEvent:new(vehicle, ObjectInRange));
			end;
		end;
	end;
end;
startOverLoadEvent = {};
startOverLoadEvent_mt = Class(startOverLoadEvent, Event);

InitEventClass(startOverLoadEvent, "startOverLoadEvent");

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

function startOverLoadEvent:new(object, startOverLoad)
    local self = startOverLoadEvent:emptyNew()
    self.object = object;
	self.startOverLoad = startOverLoad;
    return self;
end;

function startOverLoadEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.startOverLoad = streamReadBool(streamId);
		if self.startOverLoad == nil then
		--print("self.startOverLoad nil 1");
	end;
    self.object = networkGetObject(id);
    self:run(connection);
end;

function startOverLoadEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.object));
	streamWriteBool(streamId, self.startOverLoad);
	if self.startOverLoad == nil then
		--print("self.startOverLoad nil 2");
	end;
end;

function startOverLoadEvent:run(connection)
	self.object:startOverLoad(self.startOverLoad, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(startOverLoadEvent:new(self.object, self.startOverLoad), nil, connection, self.object);
    end;	
end;

function startOverLoadEvent.sendEvent(vehicle, startOverLoad, noEventSend)

	if startOverLoad ~= vehicle.OverLoadIsActiv then
		if noEventSend == nil or noEventSend == false then
			if g_server ~= nil then
				g_server:broadcastEvent(startOverLoadEvent:new(vehicle, startOverLoad), nil, nil, vehicle);
			else
				g_client:getServerConnection():sendEvent(startOverLoadEvent:new(vehicle, startOverLoad));
			end;
		end;
	end;
end;