--
-- GrainTankAnimation
-- Specialization for GrainTankAnimation
--
-- @author  	Manuel Leithner
-- @version 	v1.0
-- @date  		14/11/12
-- @history:	v1.0 - Initial version
--

GrainTankAnimation = {};

function GrainTankAnimation.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Combine, specializations);
end;

function GrainTankAnimation:load(xmlFile)
	
	self.setGraintankActive = SpecializationUtil.callSpecializationsFunction("setGraintankActive");		
	self.isGraintankExpanded = false;
	self.graintankWarning = 0;
	self.isThreshingGraintankWarning = 0;
	self.lastThreshingState = false;
	self.doFastMovement = false;
	
	self.graintankParticleSystems = {};
	local i = 0;
	while true do
		local key = string.format("vehicle.graintankParticleSystems.graintankParticleSystem(%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);
			self.graintankParticleSystems[desc.index] = currentPS;
			if self.defaultGraintankParticleSystem == nil then
				self.defaultGraintankParticleSystem = currentPS;
			end;
		end;
		i = i + 1;
	end;
	
	self.graintankPositions = {};
	local i = 0;
	while true do
		local key = string.format("vehicle.graintankPositions.position(%d)", i);
		if not hasXMLProperty(xmlFile, key) then
			break;
		end;
		local vertex = {};
		vertex.node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#index"));
		if vertex.node ~= nil then
			local defaultX, defaultY, defaultZ = getTranslation(vertex.node);
			local animCurve = AnimCurve:new(linearInterpolator3);
			local keyI = 0;
			while true do
				local animKey = key..string.format(".key(%d)", keyI);
				local keyTime = getXMLFloat(xmlFile, animKey.."#time");
				if keyTime == nil then
					break;
				end;
				local x,y,z = Utils.getVectorFromString(getXMLString(xmlFile, animKey.."#translation"));
				animCurve:addKeyframe({x=x, y=y, z=z, time = keyTime});
				keyI = keyI +1;
			end;
			vertex.positions = animCurve;
		end;
		table.insert(self.graintankPositions, vertex);
		i = i +1;
	end;
	
	self.currentGraintankParticleSystem = nil;	
end;

function GrainTankAnimation:delete()
	for k,v in pairs(self.graintankParticleSystems) do
        Utils.deleteParticleSystem(v);
    end;
end;

function GrainTankAnimation:readStream(streamId, connection)
	self.doFastMovement = true;
	self:setGraintankActive(streamReadBool(streamId), true);
end;

function GrainTankAnimation:writeStream(streamId, connection)
	streamWriteBool(streamId, self.isGraintankExpanded);
end;

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

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

function GrainTankAnimation:update(dt)
	if self:getIsActiveForInput() then
		if InputBinding.hasEvent(InputBinding.SWITCH_GRAINTANK_STATE) then
			if not self.isThreshing or not self.isGraintankExpanded then
				if self.grainTankFillLevel < 2500 or not self.isGraintankExpanded then
					self:setGraintankActive(not self.isGraintankExpanded);	
				else
					self.graintankWarning = self.time + 1800;
				end;
			else
				if self.isThreshing then
					self.isThreshingGraintankWarning = self.time + 1800;
				end;
			end;
		end;
	end;
end;

function GrainTankAnimation:updateTick(dt)
	if self:getIsActive() then
		if self.grainTankFillLevel > 3500 and not self.isGraintankExpanded then
			self:setGraintankActive(true, true);
		end;
	end;
end;

function GrainTankAnimation:draw()	
	if self.isGraintankExpanded then
		g_currentMission:addHelpButtonText(g_i18n:getText("CLOSE_GRAINTANK"), InputBinding.SWITCH_GRAINTANK_STATE);
	else
		g_currentMission:addHelpButtonText(g_i18n:getText("OPEN_GRAINTANK"), InputBinding.SWITCH_GRAINTANK_STATE);
	end;
	
	if self.isThreshingGraintankWarning > self.time then
		g_currentMission:addWarning(g_i18n:getText("PLEASE_TURNOFF_CHOPPER_FIRST"), 0.018, 0.033);
	end;
	
	if self.graintankWarning > self.time then
		g_currentMission:addWarning(g_i18n:getText("COULD_NOT_UNFOLD_GRAINTANK"), 0.018, 0.033);
	end;
end;

function GrainTankAnimation:onEnter()
	if not self.isGraintankExpanded then
		local animTimeLadder = nil;
		if self:getIsAnimationPlaying("openLadder") then			
			animTimeLadder = self:getAnimationTime("openLadder");
		end;
		self:playAnimation("openLadder", 1, animTimeLadder, true);	
	end;	
end;

function GrainTankAnimation:onLeave()
	if not self:getIsHired() then
		local animTimeLadder = nil;
		if self:getIsAnimationPlaying("openLadder") then			
			animTimeLadder = self:getAnimationTime("openLadder");
		end;
		self:playAnimation("openLadder", -1, animTimeLadder, true);	
	end;	
end;

function GrainTankAnimation:onDeactivate()
    for k,v in pairs(self.graintankParticleSystems) do
        Utils.setEmittingState(v, false);
    end;
end;

function GrainTankAnimation:setIsThreshing(isThreshing, noEventSend)
	if isThreshing and not self.isGraintankExpanded then
		self:setGraintankActive(true, true);
	end;
end;

function GrainTankAnimation:attachImplement(implement)
    local object = implement.object;
    if object.attacherJoint.jointType == Vehicle.JOINTTYPE_CUTTER then
		if object.foldCameras ~= nil then
			object:foldCameras(self.isGraintankExpanded);
		end;
    end;
end;


function GrainTankAnimation:setGrainTankFillLevel(fillLevel, fruitType)
    if self.isClient then
		if self.currentGrainTankPlane ~= nil then		
			local t = self.grainTankFillLevel/self.grainTankCapacity;
			local shaderParam = 1;
			local grainplane = self.currentGrainTankPlane.nodes[1].node;
			local refFrame = getParent(grainplane);
			for k, vertex in pairs(self.graintankPositions) do					
				local x,y,z = vertex.positions:get(t);
				setTranslation(vertex.node, x,y, z);				
				x,y,z = getWorldTranslation(vertex.node);
				x,y,z = worldToLocal(refFrame, x,y,z);				
				setShaderParameter(grainplane, "c"..shaderParam, x,y,z,0, false);
				shaderParam = shaderParam + 1;				
			end;
		end;
    end;
end;

function GrainTankAnimation:setGraintankActive(isExpanded, noEventSend)	
	SetGraintankEvent.sendEvent(self, isExpanded, noEventSend);
	
	local animTimeTank = nil;
	local animTimeLadder = nil;
	
	local animTime = nil;
	if self:getIsAnimationPlaying("openGraintank") then			
		animTimeTank = self:getAnimationTime("openGraintank");
	end;
	if self:getIsAnimationPlaying("openLadder") then			
		animTimeLadder = self:getAnimationTime("openLadder");
	end;
	
	local multiplier = 1;
	if self.doFastMovement then
		multiplier = 100;
		self.doFastMovement = false;
	end;
	
	if isExpanded then
		self:playAnimation("openGraintank", 1*multiplier, animTimeTank, true);	
		self:playAnimation("openLadder", -1*multiplier, animTimeLadder, true);
	else
		self:playAnimation("openGraintank", -1*multiplier, animTimeTank, true);
		self:playAnimation("openLadder", 1*multiplier, animTimeLadder, true);
	end;
	
	if self.setTransportState ~= nil then
		self:setTransportState(not isExpanded);
	end;
	
	for cutter, _ in pairs(self.attachedCutters) do
		if cutter.foldCameras ~= nil then
			cutter:foldCameras(isExpanded, multiplier);
		end;
	end;
	self.isGraintankExpanded = isExpanded;
end;

function GrainTankAnimation:getSaveAttributesAndNodes(nodeIdent)
	local attributes = 'isGraintankExpanded="' .. tostring(self.isGraintankExpanded) ..'"';
	return attributes, nil;
end;

function GrainTankAnimation:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	if not resetVehicles then
		local isGraintankExpanded = Utils.getNoNil(getXMLBool(xmlFile, key .. "#isGraintankExpanded"), false);
		self.doFastMovement = true;
		self:setGraintankActive(isGraintankExpanded or self.grainTankFillLevel > 3500, true)
	end; 
    return BaseMission.VEHICLE_LOAD_OK;
end;


local oldCombineSetStrawEnableEvent = CombineSetStrawEnableEvent.execute;
CombineSetStrawEnableEvent.execute = function(object, enabled, fruitType)

	oldCombineSetStrawEnableEvent(object, enabled, fruitType);
	if object.graintankParticleSystems ~= nil then
		if object.currentGraintankParticleSystem ~= nil then
			Utils.setEmittingState(object.currentGraintankParticleSystem, false);
		end;
		object.currentGraintankParticleSystem = object.graintankParticleSystems[fruitType];
		if object.currentGraintankParticleSystem == nil then
			object.currentGraintankParticleSystem = object.defaultGraintankParticleSystem;
		end;
		local visible = Utils.getNoNil(object.particleSystemsVisible, true);
		Utils.setEmittingState(object.currentGraintankParticleSystem, enabled and visible);	
	end;
end;

local oldCombineSetChopperEnableEvent = CombineSetChopperEnableEvent.execute;
CombineSetChopperEnableEvent.execute = function(object, enabled, fruitType)
	oldCombineSetChopperEnableEvent(object, enabled, fruitType);
	if object.graintankParticleSystems ~= nil then
		if object.currentGraintankParticleSystem ~= nil then
			Utils.setEmittingState(object.currentGraintankParticleSystem, false);
		end;
		object.currentGraintankParticleSystem = object.graintankParticleSystems[fruitType];
		if object.currentGraintankParticleSystem == nil then
			object.currentGraintankParticleSystem = object.defaultGraintankParticleSystem;
		end;
		local visible = Utils.getNoNil(object.particleSystemsVisible, true);
		Utils.setEmittingState(object.currentGraintankParticleSystem, enabled and visible);	
	end;
end;



--
-- SetGraintankEvent
-- NetworkEvent for GrainTankAnimation
--
-- @author  	Manuel Leithner
-- @version 	v1.0
-- @date  		14/11/12
-- @history:	v1.0 - Initial version
--
SetGraintankEvent = {};
SetGraintankEvent_mt = Class(SetGraintankEvent, Event);

InitEventClass(SetGraintankEvent, "SetGraintankEvent");

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

function SetGraintankEvent:new(object, isActive)
    local self = SetGraintankEvent:emptyNew()
    self.object = object;
	self.isActive = isActive;
    return self;
end;

function SetGraintankEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	self.isActive = streamReadBool(streamId);
    self.object = networkGetObject(id);
    self:run(connection);
end;

function SetGraintankEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.object));
	streamWriteBool(streamId, self.isActive);
end;

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

function SetGraintankEvent.sendEvent(vehicle, isActive, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(SetGraintankEvent:new(vehicle, isActive), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(SetGraintankEvent:new(vehicle, isActive));
		end;
	end;
end;