--
-- GreenTrailerAddon
-- Specialization for GreenTrailerAddon
--
-- @author  	(Flagsystems) Manuel Leithner
-- @version 	v1.0
-- @date  		13/05/11
-- @history:	v1.0 - Initial version
--

GreenTrailerAddon = {};
GreenTrailerAddon.BACK = 0;
GreenTrailerAddon.LEFT = 1;
GreenTrailerAddon.RIGHT = 2;

function GreenTrailerAddon.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Trailer, specializations);
end;

function GreenTrailerAddon:load(xmlFile)

	self.setTippingDirection = SpecializationUtil.callSpecializationsFunction("setTippingDirection");
	self.setFillLevel = Utils.prependedFunction(self.setFillLevel, GreenTrailerAddon.setFillLevel);
	
	
	self.wheelChocks = {};
	self.wheelChocks.attached = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.wheelChocks#attached"));
	self.wheelChocks.detached = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.wheelChocks#detached"));
	setVisibility(self.wheelChocks.attached, false);
	setVisibility(self.wheelChocks.detached, true);
	
	local punchCount = Utils.getNoNil(getXMLInt(xmlFile, "vehicle.punches#count"), 0);		
	self.punches = {};
	self.punches.fixpoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.punches#fixpoint"));
	self.punches.nodes = {};
	for i=1, punchCount do
		local punchName = string.format("vehicle.punches.punch%d", i);		
		local punch = {};		
		punch.node = Utils.indexToObject(self.components, getXMLString(xmlFile, punchName .. "#node"));
		punch.fixpoint = Utils.indexToObject(self.components, getXMLString(xmlFile, punchName .. "#fixpoint"));	
		local ax, ay, az = getWorldTranslation(punch.node);		
		local bx, by, bz = getWorldTranslation(punch.fixpoint);		
		punch.distance = Utils.vector3Length(ax-bx, ay-by, az-bz);		
		table.insert(self.punches.nodes, punch);
	end;
	
	self.tippingDirection = GreenTrailerAddon.BACK;
	

    local tipAnimRootNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.leftTipAnimation#rootNode"));
    self.leftTipAnimCharSet = 0;
    if tipAnimRootNode ~= nil and tipAnimRootNode ~= 0 then
        self.leftTipAnimCharSet = getAnimCharacterSet(tipAnimRootNode);
        if self.leftTipAnimCharSet ~= 0 then
            local clip = getAnimClipIndex(self.leftTipAnimCharSet, getXMLString(xmlFile, "vehicle.leftTipAnimation#clip"));
            assignAnimTrackClip(self.leftTipAnimCharSet, 0, clip);
            setAnimTrackLoopState(self.leftTipAnimCharSet, 0, false);
            self.leftTipAnimSpeedScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.leftTipAnimation#speedScale"), 1);
            self.leftTipAnimDuration = getAnimClipDuration(self.leftTipAnimCharSet, clip);
            if self.leftTipDischargeEndTime == nil then
                self.leftTipDischargeEndTime = self.leftTipAnimDuration*2.0;
            end;
        end;
    end;
	self.leftTipMovingPart = nil;
	local movingPart = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.leftTipAnimation#movingPart"));
	for _, part in pairs(self.movingParts) do
		if part.node == movingPart then
			self.leftTipMovingPart = part;
			break;
		end;
	end;	
	
	tipAnimRootNode = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.rightTipAnimation#rootNode"));
    self.rightTipAnimCharSet = 0;
    if tipAnimRootNode ~= nil and tipAnimRootNode ~= 0 then
        self.rightTipAnimCharSet = getAnimCharacterSet(tipAnimRootNode);
        if self.rightTipAnimCharSet ~= 0 then
            local clip = getAnimClipIndex(self.rightTipAnimCharSet, getXMLString(xmlFile, "vehicle.rightTipAnimation#clip"));
            assignAnimTrackClip(self.rightTipAnimCharSet, 0, clip);
            setAnimTrackLoopState(self.rightTipAnimCharSet, 0, false);
            self.rightTipAnimSpeedScale = Utils.getNoNil(getXMLFloat(xmlFile, "vehicle.rightTipAnimation#speedScale"), 1);
            self.rightTipAnimDuration = getAnimClipDuration(self.rightTipAnimCharSet, clip);
            if self.rightTipDischargeEndTime == nil then
                self.rightTipDischargeEndTime = self.rightTipAnimDuration*2.0;
            end;
        end;
    end;
	
	self.rightTipMovingPart = nil;
	movingPart = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.rightTipAnimation#movingPart"));
	for _, part in pairs(self.movingParts) do
		if part.node == movingPart then
			self.rightTipMovingPart = part;
			break;
		end;
	end;
	
	self.backTipMovingPart = nil;
	movingPart = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tipAnimation#movingPart"));
	for _, part in pairs(self.movingParts) do
		if part.node == movingPart then
			self.backTipMovingPart = part;
			break;
		end;
	end;

    self.leftTipReferencePoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tipReferencePoint#left"));
    if self.leftTipReferencePoint == nil then
        self.leftTipReferencePoint = self.components[1].node;
    end;
	self.rightTipReferencePoint = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tipReferencePoint#right"));
    if self.rightTipReferencePoint == nil then
        self.rightTipReferencePoint = self.components[1].node;
    end;
	
	self.backTipReferencePoint = self.tipReferencePoint;
	self.backTipAnimCharSet = self.tipAnimCharSet;
	self.backTipAnimSpeedScale = self.tipAnimSpeedScale;
	self.backTipAnimDuration = self.tipAnimDuration;
	self.backTipDischargeEndTime = self.tipDischargeEndTime;
	self.leftTipBolds = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.leftTipAnimation#bolts"));
	self.rightTipBolds = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.rightTipAnimation#bolts"));
	self.backTipBolds = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.tipAnimation#bolts"));
	setVisibility(self.leftTipBolds, false);
	setVisibility(self.rightTipBolds, false);
	setVisibility(self.backTipBolds, true);
	
	self.springs = {};
	local part1 = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.springs#movingPart1"));
	for _, part in pairs(self.movingParts) do
		if part.node == part1 then
			self.springs.part1 = part;
			break;
		end;
	end;
	local part2 = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.springs#movingPart2"));
	for _, part in pairs(self.movingParts) do
		if part.node == part2 then
			self.springs.part2 = part;
			break;
		end;
	end;	
	self.updateSprings = 200;
	
	
	self.backParticleSystem = self.dischargeParticleSystems;
	self.leftParticleSystem = {};
	self.addLeftParticleSystem = {};
	self.rightParticleSystem = {};
	self.addRightParticleSystem = {};
	
	if self.isClient then
		local i = 0;
        while true do
            local key = string.format("vehicle.leftDischargeParticleSystems.fruit(%d)", i);
            local t = getXMLString(xmlFile, key .. "#type");
            if t == nil then
                break;
            end;
			local desc = FruitUtil.fruitTypes[t];
			local fillType = FruitUtil.fruitTypeToFillType[desc.index];
			self.addLeftParticleSystem[fillType] = {};
			local j=0;
			while true do 				
				local pskey = string.format(key .. ".dischargeParticleSystem(%d)", j);
				local node = getXMLString(xmlFile, pskey .. "#node");
				if node == nil then
					break;
				end;
				local currentPS = {};
				
                local particleNode = Utils.loadParticleSystem(xmlFile, currentPS, pskey, self.components, false, "$data/vehicles/particleSystems/trailerDischargeParticleSystem.i3d", self.baseDirectory);
                
				if j == 0 then
					self.leftParticleSystem[fillType] = currentPS;
				else
					table.insert(self.addLeftParticleSystem[fillType], currentPS);
				end;			
				
				j = j + 1;
			end;
			
            i = i + 1;
        end;
		
		local i = 0;
        while true do
            local key = string.format("vehicle.rightDischargeParticleSystems.fruit(%d)", i);
            local t = getXMLString(xmlFile, key .. "#type");
            if t == nil then
                break;
            end;
			local desc = FruitUtil.fruitTypes[t];
			local fillType = FruitUtil.fruitTypeToFillType[desc.index];
			self.addRightParticleSystem[fillType] = {};
			local j=0;
			while true do 				
				local pskey = string.format(key .. ".dischargeParticleSystem(%d)", j);
				local node = getXMLString(xmlFile, pskey .. "#node");
				if node == nil then
					break;
				end;
				local currentPS = {};
				
                local particleNode = Utils.loadParticleSystem(xmlFile, currentPS, pskey, self.components, false, "$data/vehicles/particleSystems/trailerDischargeParticleSystem.i3d", self.baseDirectory);
                
				if j == 0 then
					self.rightParticleSystem[fillType] = currentPS;
				else
					table.insert(self.addRightParticleSystem[fillType], currentPS);
				end;			
				
				j = j + 1;
			end;
			
            i = i + 1;
        end;
	end;
	
	if self.isServer then
		self.drawbarJoint = self.componentJoints[2].jointIndex;
	end;
end;

function GreenTrailerAddon:delete()
	if self.tippingDirection ~= GreenTrailerAddon.BACK then
		for _, particleSystem in pairs(self.backParticleSystem) do
			Utils.deleteParticleSystem(particleSystem);
		end;
	end;
	if self.tippingDirection ~= GreenTrailerAddon.LEFT then
		for _, particleSystem in pairs(self.leftParticleSystem) do
			Utils.deleteParticleSystem(particleSystem);
		end;
	end;
	if self.tippingDirection ~= GreenTrailerAddon.RIGHT then
		for _, particleSystem in pairs(self.rightParticleSystem) do
			Utils.deleteParticleSystem(particleSystem);
		end;	
	end;
	for _, fruiTypes in pairs(self.addLeftParticleSystem) do
		for _, particleSystem in pairs(fruiTypes) do
			Utils.deleteParticleSystem(particleSystem);
		end;
    end;
	for _, fruiTypes in pairs(self.addRightParticleSystem) do
		for _, particleSystem in pairs(fruiTypes) do
			Utils.deleteParticleSystem(particleSystem);
		end;
    end;
end;

function GreenTrailerAddon:readStream(streamId, connection)
	local dir = streamReadUIntN(streamId, 2);
	self:setTippingDirection(dir, true);
end;

function GreenTrailerAddon:writeStream(streamId, connection)
	streamWriteUIntN(streamId, self.tippingDirection, 2);
end;

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

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

function GreenTrailerAddon:update(dt)

	if self:getIsActive() then
		self.updateSprings = 200;
	
		if self:getIsActiveForInput() then
			if self.tipState == Trailer.TIPSTATE_CLOSED and InputBinding.hasEvent(InputBinding.CHANGE_TIPPING_DIRECTION) then
				local newDir = (self.tippingDirection+1) % 3;
				self:setTippingDirection(newDir);
			end;
		end;
	end;

	if self.tipState == Trailer.TIPSTATE_OPENING or self.tipState == Trailer.TIPSTATE_CLOSING then
	
		if self.tippingDirection == GreenTrailerAddon.BACK then
			Cylindered.updateMovingPart(self, self.backTipMovingPart);	
		elseif self.tippingDirection == GreenTrailerAddon.LEFT then
			Cylindered.updateMovingPart(self, self.leftTipMovingPart);
		else
			Cylindered.updateMovingPart(self, self.rightTipMovingPart);
		end;
	
		local bx, by, bz = getWorldTranslation(self.punches.fixpoint);
		for _,punch in pairs(self.punches.nodes) do
			local ax, ay, az = getWorldTranslation(getParent(punch.node));			
			local distance = Utils.vector3Length(ax-bx, ay-by, az-bz);
			trans = math.min(distance-punch.distance, punch.distance);
			setTranslation(punch.node, 0, 0, trans);				
		end;
	end;
	
	if self.updateSprings > 0 then
		Cylindered.updateMovingPart(self, self.springs.part1);	
		Cylindered.updateMovingPart(self, self.springs.part2);		
		self.updateSprings = self.updateSprings - 1;
	end;
end;

function GreenTrailerAddon:updateTick(dt)
	if self.isClient then
		if self.tippingDirection == GreenTrailerAddon.LEFT or self.tippingDirection == GreenTrailerAddon.RIGHT then
			local additionalPS = self.addLeftParticleSystem[self.currentFillType];
			if self.tippingDirection == GreenTrailerAddon.RIGHT then
				additionalPS = self.addRightParticleSystem[self.currentFillType];
			end;
		
			if additionalPS ~= nil then
				if (self.tipState == Trailer.TIPSTATE_OPENING or self.tipState == Trailer.TIPSTATE_OPEN) and self.fillLevel > 0 then
					for _, ps in pairs(additionalPS) do
						Utils.setEmittingState(ps, true);
					end;
				else
					for _, ps in pairs(additionalPS) do
						Utils.setEmittingState(ps, false);
					end;
				end;
			end;
		end;
    end;
end;

function GreenTrailerAddon:draw()
	local label = g_i18n:getText("BACK");
	if self.tippingDirection == GreenTrailerAddon.LEFT then
		label = g_i18n:getText("LEFT");
	elseif self.tippingDirection == GreenTrailerAddon.RIGHT then
		label = g_i18n:getText("RIGHT");
	end;
	g_currentMission:addHelpButtonText(string.format(g_i18n:getText("changeTippingDirection"), label), InputBinding.CHANGE_TIPPING_DIRECTION);
end;

function GreenTrailerAddon:onAttach(attacherVehicle)
	setVisibility(self.wheelChocks.attached, true);
	setVisibility(self.wheelChocks.detached, false);
	if self.isServer then
		setJointRotationLimit(self.drawbarJoint, 0, true, -math.rad(160), math.rad(160));
	end;
end;

function GreenTrailerAddon:onDetach()
	setVisibility(self.wheelChocks.attached, false);
	setVisibility(self.wheelChocks.detached, true);
	if self.isServer then
		setJointRotationLimit(self.drawbarJoint, 0, true, -math.rad(5), math.rad(5));
	end;
end;

function GreenTrailerAddon:setFillLevel(fillLevel, fillType, force)
    if self.isClient then
		if self.tippingDirection == GreenTrailerAddon.LEFT or self.tippingDirection == GreenTrailerAddon.RIGHT then
			if self.currentFillType ~= fillType or fillLevel <= 0  then
				for _, fruiTypes in pairs(self.addLeftParticleSystem) do
					for _, particleSystem in pairs(fruiTypes) do
						Utils.setEmittingState(particleSystem, false);
					end;
				end;
				for _, fruiTypes in pairs(self.addRightParticleSystem) do
					for _, particleSystem in pairs(fruiTypes) do
						Utils.setEmittingState(particleSystem, false);
					end;
				end;
			end;
		end;
    end;
end;

function GreenTrailerAddon:setTippingDirection(tippingDirection, noEventSend)
	SetTippingDirectionEvent.sendEvent(self, tippingDirection, noEventSend);
	
	self.tippingDirection = tippingDirection;
	if self.tippingDirection == GreenTrailerAddon.BACK then
		self.tipReferencePoint = self.backTipReferencePoint;
		self.tipAnimCharSet = self.backTipAnimCharSet;
		self.tipAnimSpeedScale = self.backTipAnimSpeedScale;
		self.tipAnimDuration = self.backTipAnimDuration;
		self.tipDischargeEndTime = self.backTipDischargeEndTime;
		self.dischargeParticleSystems = self.backParticleSystem;
		
	elseif self.tippingDirection == GreenTrailerAddon.LEFT then
		self.tipReferencePoint = self.leftTipReferencePoint;
		self.tipAnimCharSet = self.leftTipAnimCharSet;
		self.tipAnimSpeedScale = self.leftTipAnimSpeedScale;
		self.tipAnimDuration = self.leftTipAnimDuration;
		self.tipDischargeEndTime = self.leftTipDischargeEndTime;
		self.dischargeParticleSystems = self.leftParticleSystem;
		
	elseif self.tippingDirection == GreenTrailerAddon.RIGHT then
		self.tipReferencePoint = self.rightTipReferencePoint;
		self.tipAnimCharSet = self.rightTipAnimCharSet;
		self.tipAnimSpeedScale = self.rightTipAnimSpeedScale;
		self.tipAnimDuration = self.rightTipAnimDuration;
		self.tipDischargeEndTime = self.rightTipDischargeEndTime;
		self.dischargeParticleSystems = self.rightParticleSystem;
	end;
	
	setVisibility(self.leftTipBolds, self.tippingDirection == GreenTrailerAddon.LEFT);
	setVisibility(self.rightTipBolds, self.tippingDirection == GreenTrailerAddon.RIGHT);
	setVisibility(self.backTipBolds, self.tippingDirection == GreenTrailerAddon.BACK);
end;


function GreenTrailerAddon:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)	
	if not resetVehicles then
		local tippingDirection = Utils.getNoNil(getXMLInt(xmlFile, key .. "#tippingDirection"), 0);
		self:setTippingDirection(tippingDirection, true);
	end; 
    return BaseMission.VEHICLE_LOAD_OK;
end;

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