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

threesdk = {};

function threesdk.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Trailer, specializations) and SpecializationUtil.hasSpecialization(Attachable, specializations);
end;

function threesdk:load(xmlFile)

	self.setTipSide = threesdk.setTipSide;

	self.is3SideTipperFromGeri = false;
	
	local sides = {};
	sides[1] = "left";
	sides[2] = "right";
	sides[3] = "back";
	
	self.sides = sides;
	
	self.hydraulics = {};
	self.hydraulics.nodes ={};
	self.tipAnims = {};
	self.tipReferencePoints = {};
	self.particleSystems = {};
	for k,v in pairs(sides) do
	---ANIMATIONS
		local baseString = string.format("vehicle.tipAnimation.%s",v);
		self.tipAnims[v] = {};
		local entry = {};
		
		local tipAnimRootNode = Utils.indexToObject(self.components, getXMLString(xmlFile, baseString.."#rootNode"));
		local tipAnimCharSet = 0;
		if tipAnimRootNode ~= nil and tipAnimRootNode ~= 0 then
			tipAnimCharSet = getAnimCharacterSet(tipAnimRootNode);
			
			if tipAnimCharSet ~= 0 then
				local clip = getAnimClipIndex(tipAnimCharSet, getXMLString(xmlFile, baseString.."#clip"));
				assignAnimTrackClip(tipAnimCharSet, 0, clip);
				setAnimTrackLoopState(tipAnimCharSet, 0, false);
				
				entry.tipAnimCharSet = tipAnimCharSet;
				entry.tipAnimSpeedScale = Utils.getNoNil(getXMLFloat(xmlFile, baseString.."#speedScale"), 1);
				entry.tipAnimDuration = getAnimClipDuration(tipAnimCharSet, clip);
				
				if entry.tipDischargeEndTime == nil then
					entry.tipDischargeEndTime = entry.tipAnimDuration*2.0;
				end;
				self.hydraulics.nodes[v] = Utils.indexToObject(self.components, getXMLString(xmlFile, baseString.."#DirectionNode"));
				self.tipAnims[v] = entry;
			end;
		end;
		
	---TIPREFERENCEPOINTS
		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;
	
	---PARTICLESYSTEMS
	
		self.particleSystems[v] = {};
		local entry = {};
		
		entry.dischargeParticleSystems = {};
		
		local i = 0;
		while true do
			local key = string.format("vehicle.dischargeParticleSystems%s.dischargeParticleSystem(%d)",v, i);
			local t = getXMLString(xmlFile, key .. "#type");
			if t == nil then
				break;
			end;
			local desc = FruitUtil.fruitTypes[t];
			
			if desc ~= nil 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);
				
				entry.dischargeParticleSystems[fillType] = currentPS;
				if entry.defaultdischargeParticleSystems == nil then
					entry.defaultdischargeParticleSystems = currentPS;					
				end;
				if self.dischargeParticleSystems[fillType] == nil then
					self.dischargeParticleSystems[fillType] = currentPS;
					self.defaultdischargeParticleSystems = currentPS;
				end;
			end;
			i = i + 1;
		end;
		self.particleSystems[v] = entry;
	end;

	
	self.currentSide = 1;
	self.hydraulics.cylinders = {};
	self.hydraulics.FixPoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tipAnimation#fixPoint1"));
	self.hydraulics.FixPointPunchs = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tipAnimation#fixPoint2"));
	local x,y,z = getTranslation(self.hydraulics.FixPointPunchs);
	self.hydraulics.PunchDis = z-0.1;
	local i = 0;
	while true do
		local key = string.format("vehicle.tipAnimation.cylinders(%d)", i);
		local entry = {};
		entry.node = Utils.indexToObject(self.components, getXMLString(xmlFile, key.."#node"));
		entry.minPos = {getTranslation(entry.node)};
		if entry.node == nil or entry.node == 0 then
			break;
		end;
		self.hydraulics.cylinders[i + 1]= entry;
		i = i + 1;
	end;
	self:setTipSide(1);
	self.hydraulics.count= i+1;
	
end;

function threesdk:delete()
	for k,v in pairs(self.particleSystems) do
		if k ~= self.sides[self.currentSide] then
			Utils.deleteParticleSystem(v.dischargeParticleSystems);	
		end;	
	end; 	
end;

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

function threesdk:keyEvent(unicode, sym, modifier, isDown)
end;
function threesdk:readStream(streamId, connection)
	local currentSide = streamReadInt8(streamId);
	self:setTipSide(currentSide,true);
end;
function threesdk:writeStream(streamId, connection)
	streamWriteInt8(streamId, self.currentSide);
end;
function threesdk:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)
	if not resetVehicles then
		self.currentSide = Utils.getNoNil(getXMLInt(xmlFile,key.."#side"),1);
		self:setTipSide(self.currentSide);
	end;
    return BaseMission.VEHICLE_LOAD_OK;
end;

function threesdk:getSaveAttributesAndNodes(nodeIdent)
    local attributes = ' side="'..tostring(self.currentSide)..'"';
    local node = nil;
    return attributes, node;
end;
function threesdk:update(dt)
	--if self:getIsActive() then
	if self.tipState ~= Trailer.TIPSTATE_CLOSED then
		g_currentMission.fixedCamera = false;
		local v = self.sides[self.currentSide];
		
		local ax, ay, az = getWorldTranslation(self.hydraulics.nodes[v]);
		local bx, by, bz = getWorldTranslation(self.hydraulics.FixPoint);
		local x, y, z = worldDirectionToLocal(getParent(self.hydraulics.nodes[v]), bx-ax, by-ay, bz-az);
		if v == "back" then
			setDirection(self.hydraulics.nodes[v], x, y, z, 1, 1, 0);
		else
			setDirection(self.hydraulics.nodes[v], x, y, z, 1, 1, 0);
		end;
		
		local distance = Utils.vector3Length(ax-bx, ay-by, az-bz);
		local new = (distance-self.hydraulics.PunchDis)/(self.hydraulics.count-1);

		for k,v in pairs(self.hydraulics.cylinders) do			
			if new >= v.minPos[3] then
				setTranslation(v.node, 0, 0, new);
			end;
		end;
	end;
	if self:getIsActiveForInput() then
		if not self.is3SideTipperFromGeri then
			if InputBinding.hasEvent(InputBinding.changeTipperMode1) and self.tipState == Trailer.TIPSTATE_CLOSED then
					local side = self.currentSide;
					if not self.is3SideTipperFromGeri then
						side = side+1;
						if side > table.getn(self.sides) then
							side = 1;
						end;						
					end;
					self:setTipSide(side);
			end;
		end;
	end;

end;
function threesdk:updateTick(dt)

end;
function threesdk:setTipSide(sideIndex,noEventSend)
	SetTipSideEvent.sendEvent(self, sideIndex, noEventSend)	
	self.currentSide = sideIndex;
	local side = self.sides[sideIndex];

	self.tipReferencePoint = self.tipReferencePoints[side].tipReferencePoint;
	
	for k,v in pairs(self.particleSystems) do
		for i,j in pairs(v.dischargeParticleSystems) do
			Utils.setEmittingState(v,false);
		end;
	end;
	self.dischargeParticleSystems = self.particleSystems[side].dischargeParticleSystems;
	
	local TipTable = self.tipAnims[side];	
	if TipTable.tipAnimCharSet ~= 0 and TipTable.tipAnimCharSet ~= nil then
		self.tipAnimCharSet = TipTable.tipAnimCharSet;
		self.tipAnimSpeedScale = TipTable.tipAnimSpeedScale;
		self.tipAnimDuration = TipTable.tipAnimDuration;
		self.tipDischargeEndTime = TipTable.tipDischargeEndTime;
	end;

	return self.sides[4];
end;
function threesdk:draw()
	if self:getIsActive() and self.tipState == Trailer.TIPSTATE_CLOSED then--and not self.is3SideTipperFromGeri then
		if not self.is3SideTipperFromGeri then
			if not self.objectInRange then
				g_currentMission:addHelpButtonText(string.format(g_i18n:getText("changeTipMode"),g_i18n:getText(self.sides[self.currentSide])), InputBinding.changeTipperMode1);
			end;
		end;
	end;
end;

function threesdk:attachImplement(implement)
	self:setTipSide(self.currentSide,true);
end;
function threesdk:detachImplement(implementIndex)
	self:setTipSide(self.currentSide,true);
end;
SetTipSideEvent = {};
SetTipSideEvent_mt = Class(SetTipSideEvent, Event);

InitEventClass(SetTipSideEvent, "SetTipSideEvent");

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

function SetTipSideEvent:new(object, currentTipSide)
    local self = SetTipSideEvent:emptyNew()
    self.object = object;
	self.currentTipSide = currentTipSide;
    return self;
end;

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

function SetTipSideEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.object));
	streamWriteInt8(streamId, self.currentTipSide);
	if self.currentTipSide == nil then
		--print("self.currentTipSide nil 2");
	end;
end;

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

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