--
-- BuyableCareWheels
-- Specialization for Buyable Care Wheels
--
-- @author  	Manuel Leithner (SFM-Modding)
-- @version 	v1.0
-- @date  		30/10/10
-- @history:	v1.0 - Initial version
--
-- free for noncommerical-usage
--

BuyableCareWheels = {};

function BuyableCareWheels.prerequisitesPresent(specializations)
    return true;
end;

function BuyableCareWheels:load(xmlFile)

	self.careWheelTriggerCallback = BuyableCareWheels.careWheelTriggerCallback;
	self.wheelDelete = BuyableCareWheels.wheelDelete;
	self.assembleWheels = SpecializationUtil.callSpecializationsFunction("assembleWheels");
	self.disassembleWheels = SpecializationUtil.callSpecializationsFunction("disassembleWheels");

	self.checkString = Utils.getNoNil(getXMLString(xmlFile, "vehicle.careWheels#checkString"), "standart");
	self.usingTrigger = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.careWheels#activationTrigger"));
	
	addTrigger(self.usingTrigger, "careWheelTriggerCallback", self);
    self.deleteListenerId = addDeleteListener(self.usingTrigger, "wheelDelete", self);
	
	self.careBelts = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.careWheels#careBelts"));
	self.normBelts = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.careWheels#normBelts"));
	
    self.buyableWheels = {};
    local i = 0;
    while true do
        local wheelnamei = string.format("vehicle.careWheels.wheel(%d)", i);
        local wheel = {};
        local wheelIndex = getXMLInt(xmlFile, wheelnamei .. "#wheelIndex");
        if wheelIndex == nil then
            break;
        end;
		
		wheel.wheelIndex = wheelIndex;
		wheel.careWheelPos = Utils.indexToObject(self.components, getXMLString(xmlFile, wheelnamei .. "#careWheelPos"));
		wheel.careWheel = getChildAt(wheel.careWheelPos, 0);
		wheel.standardWheel = nil;
		wheel.driveNode = nil;
		wheel.standardWheelPos = Utils.indexToObject(self.components, getXMLString(xmlFile, wheelnamei .. "#standardWheelPos"));
		table.insert(self.buyableWheels, wheel);
		i = i + 1;
	end;

	self.loadedCoords = nil;
	self.careWheelUser = nil;
end;

function BuyableCareWheels:delete()
	if self.careWheelUser ~= nil then
		self.careWheelUser:onDisassembling(true);
		self:disassembleWheels();
		self.buyableWheels = {};
	end;
    removeTrigger(self.usingTrigger);
end;

function BuyableCareWheels:wheelDelete()
    removeDeleteListener(self.usingTrigger, self.deleteListenerId);
end;

function BuyableCareWheels:readStream(streamId, connection)
	local id = streamReadInt32(streamId);
	if id ~= -1 then
		local careWheelUser = networkGetObject(id);
		if careWheelUser ~= nil then
			self:assembleWheels(careWheelUser, true);
		end;
	end;
end;

function BuyableCareWheels:writeStream(streamId, connection)
	local idToWrite = -1;
	if self.careWheelUser ~= nil then
		idToWrite = networkGetObjectId(self.careWheelUser);
	end;
	streamWriteInt32(streamId, idToWrite);
end;

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

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

function BuyableCareWheels:update(dt)
end;

function BuyableCareWheels:updateTick(dt)

	-- try to load saved careWheels
	if self.loadedCoords ~= nil then
		for k,steerable in pairs(g_currentMission.steerables) do
			local a,b,c = getWorldTranslation(steerable.rootNode);
			local distance = Utils.vector3Length(self.loadedCoords.x-a, self.loadedCoords.y-b, self.loadedCoords.z-c);
			if distance < 0.15 then				
				self:assembleWheels(steerable);
				break;
			end;
		end;
		self.loadedCoords = nil;
	end;
end;

function BuyableCareWheels:draw()	
end;

function BuyableCareWheels:careWheelTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
	local vehicle = g_currentMission.controlledVehicle;
	if vehicle ~= nil then
		if onEnter then		
			if vehicle.rootNode == otherId then
				if vehicle.buyableCareWheels ~= nil then
					if vehicle.buyableCareWheels.checkString == self.checkString then
						if self.careWheelUser ~= nil then
							if self.careWheelUser == vehicle then
								vehicle.buyableCareWheels.wheelsInRange = self;
							end;
						else
							vehicle.buyableCareWheels.wheelsInRange = self;
						end;
					end;
				end;
			end;
		elseif onLeave then		
			if otherId == vehicle.rootNode then
				if vehicle.buyableCareWheels ~= nil then
					vehicle.buyableCareWheels.wheelsInRange = nil;
				end;
			end;
		end;
	end;
end;

function BuyableCareWheels:assembleWheels(vehicle, noEventSend)
	BuyableCareWheelsAttachEvent.sendEvent(self, vehicle, noEventSend);

	if self.careWheelUser == nil then
		if vehicle.buyableCareWheels ~= nil then
			self.careWheelUser = vehicle;	
			for k,wheel in pairs(vehicle.wheels) do
				for l,careWheel in pairs(self.buyableWheels) do 
					if k == l then	
						careWheel.standardWheel = getChildAt(wheel.driveNode, 0);	
						careWheel.driveNode = wheel.driveNode;
						link(wheel.driveNode, careWheel.careWheel);	
						link(careWheel.standardWheelPos, careWheel.standardWheel);
						break;
					end;
				end;
			end;	
			self.careWheelUser:onAssembling(self);
		end;
	end;
	
	if self.careBelts ~= nil then
		setVisibility(self.careBelts, false);
		setVisibility(self.normBelts, true);
	end;
	
end;

function BuyableCareWheels:disassembleWheels(noEventSend)
	BuyableCareWheelsDetachEvent.sendEvent(self, noEventSend);

	self.careWheelUser:onDisassembling();
	
	for _, careWheel in pairs(self.buyableWheels) do			
		link(careWheel.driveNode, careWheel.standardWheel);	
		link(careWheel.careWheelPos, careWheel.careWheel);
		careWheel.standardWheel = nil;
		careWheel.driveNode = nil;
	end;	
	self.careWheelUser = nil;	
	
	if self.careBelts ~= nil then
		setVisibility(self.careBelts, true);
		setVisibility(self.normBelts, false);
	end;
	
end;

function BuyableCareWheels:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)

	if not resetVehicles then
		local valueStr = getXMLString(xmlFile, key.."#attacherCoords");		
		if valueStr ~= nil then
			local x,y,z = Utils.getVectorFromString(valueStr);
			self.loadedCoords = {x = x,y = y,z = z};			
		end;
	end; 

    return BaseMission.VEHICLE_LOAD_OK;
end;

function BuyableCareWheels:getSaveAttributesAndNodes(nodeIdent)	
    local attributes = nil;
	
	if self.careWheelUser ~= nil then
		local x,y,z = getWorldTranslation(self.careWheelUser.rootNode);
		attributes = 'attacherCoords="'.. x .. " " .. y .. " " .. z ..'"';
	end;
	
    return attributes, nil;
end;

BuyableCareWheelsAttachEvent = {};
BuyableCareWheelsAttachEvent_mt = Class(BuyableCareWheelsAttachEvent, Event);

InitEventClass(BuyableCareWheelsAttachEvent, "BuyableCareWheelsAttachEvent");

function BuyableCareWheelsAttachEvent:emptyNew()
    local self = Event:new(BuyableCareWheelsAttachEvent_mt);
    return self;
end;

function BuyableCareWheelsAttachEvent:new(vehicle, attacherVehicle)
    local self = BuyableCareWheelsAttachEvent:emptyNew()
    self.vehicle = vehicle;
	self.attacherVehicle = attacherVehicle;
    return self;
end;

function BuyableCareWheelsAttachEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	local attacherId = streamReadInt32(streamId);
	self.attacherVehicle = networkGetObject(attacherId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function BuyableCareWheelsAttachEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteInt32(streamId, networkGetObjectId(self.attacherVehicle));
end;

function BuyableCareWheelsAttachEvent:run(connection)
	self.vehicle:assembleWheels(self.attacherVehicle, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(BuyableCareWheelsAttachEvent:new(self.vehicle, self.attacherVehicle), nil, connection, self.object);
    end;
end;


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


BuyableCareWheelsDetachEvent = {};
BuyableCareWheelsDetachEvent_mt = Class(BuyableCareWheelsDetachEvent, Event);

InitEventClass(BuyableCareWheelsDetachEvent, "BuyableCareWheelsDetachEvent");

function BuyableCareWheelsDetachEvent:emptyNew()
    local self = Event:new(BuyableCareWheelsDetachEvent_mt);
    return self;
end;

function BuyableCareWheelsDetachEvent:new(vehicle)
    local self = BuyableCareWheelsDetachEvent:emptyNew()
    self.vehicle = vehicle;
    return self;
end;

function BuyableCareWheelsDetachEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function BuyableCareWheelsDetachEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
end;

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


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


