-- Dada --

ImportParts = {};
ImportParts.modDirectory = g_currentModDirectory;
ImportParts.newConfgurations = {};

function ImportParts.prerequisitesPresent(specializations)
      return true;
end;
function ImportParts.initSpecialization()
	local schema = Vehicle.xmlSchema
    schema:setXMLSpecializationType("ImportParts")
	local modDesc = loadXMLFile("modDesc", ImportParts.modDirectory .. "modDesc.xml");
	local configNumber = 0
	
	while true do
		local configKey = "modDesc.newConfigurations.newConfiguration(" .. tostring(configNumber) .. ")";

		if not hasXMLProperty(modDesc, configKey) then
			break;
		end;
		
		local newConfguration = {};
				newConfguration.isColorConfig = Utils.getNoNil(getXMLBool(modDesc, configKey .. "#isColorConfig"), false);
		newConfguration.configName = Utils.getNoNil(getXMLString(modDesc, configKey .. "#configName"), "");
		
		if newConfguration.configName ~= "" then 
			table.insert(ImportParts.newConfgurations, newConfguration);
			if newConfguration.isColorConfig then
				g_configurationManager:addConfigurationType(newConfguration.configName, g_i18n:getText("configuration_" .. newConfguration.configName), nil, ConfigurationUtil.getConfigMaterialSingleItemLoad, ConfigurationUtil.getConfigColorSingleItemLoad, ConfigurationUtil.getConfigColorPostLoad, ConfigurationUtil.SELECTOR_COLOR);
			else
				g_configurationManager:addConfigurationType(newConfguration.configName, g_i18n:getText("configuration_" .. newConfguration.configName), nil, nil, nil, nil, ConfigurationUtil.SELECTOR_MULTIOPTION)
				ObjectChangeUtil.registerObjectChangeXMLPaths(schema, "vehicle." .. newConfguration.configName .. "Configurations." .. newConfguration.configName .. "Configuration(?)")
			end

		end;

		configNumber = configNumber + 1;
	end;
	delete(modDesc);
	for _, newConfguration in pairs(ImportParts.newConfgurations) do
		key = "vehicle." .. newConfguration.configName .. "Configurations." .. newConfguration.configName .. "Configuration(?)"
		schema:register(XMLValueType.STRING, key .. ".".. newConfguration.configName .."(?)#xmlFilename", "xmlFilename")
		schema:register(XMLValueType.NODE_INDEX, key .. ".".. newConfguration.configName .."(?)#linkNode", "linkNode")
		schema:register(XMLValueType.STRING, key .. ".".. newConfguration.configName .."(?)#filename", "filename")
		schema:register(XMLValueType.NODE_INDEX, key .. ".".. newConfguration.configName .."(?)#node", "node")		
		schema:register(XMLValueType.NODE_INDEX, key .. ".".. newConfguration.configName .."(?)#parentNode", "parentNode")
		schema:register(XMLValueType.NODE_INDEX, key .. ".".. newConfguration.configName .."(?)#childNode", "childNode")		
		schema:register(XMLValueType.NODE_INDEX, key .. ".".. newConfguration.configName .."(?)#resetPos", "resetPos")		
		schema:register(XMLValueType.NODE_INDEX, key .. ".".. newConfguration.configName .."(?)#removeCompond", "removeCompond")
		schema:register(XMLValueType.FLOAT, key .. ".".. newConfguration.configName .."(?)#trans", "trans")
		schema:register(XMLValueType.FLOAT, key .. ".".. newConfguration.configName .."(?)#rot", "rot")
		schema:register(XMLValueType.FLOAT, key .. ".".. newConfguration.configName .."(?)#scale", "scale")
		schema:register(XMLValueType.INT, key .. ".".. newConfguration.configName .."(?)#axis", "axis")

		schema:register(XMLValueType.STRING, key .. ".".. newConfguration.configName .."(?)#dependant", "dependant")
		schema:register(XMLValueType.STRING, key .. ".".. newConfguration.configName .."(?)#contrainte", "contrainte")
		schema:register(XMLValueType.STRING, key .. ".".. newConfguration.configName .."(?)#numberConfig", "numberConfig")
		schema:register(XMLValueType.STRING, key .. ".".. newConfguration.configName .."(?)#colorCanal0", "colorCanal0")


		schema:register(XMLValueType.BOOL, key .. ".WheelAdd(?)#Add", "Add")
		schema:register(XMLValueType.FLOAT, key .. ".WheelAdd(?).wheels.wheel(?)#autoRotateBackSpeed", "Auto rotate back speed", 1)
		schema:register(XMLValueType.FLOAT, key .. ".WheelAdd(?).wheels.wheel(?)#versatileFoldMinLimit", "Auto rotate back speed", 1)
		schema:register(XMLValueType.FLOAT, key .. ".WheelAdd(?).wheels.wheel(?)#versatileFoldMaxLimit", "Auto rotate back speed", 1)
	    Wheels.registerWheelXMLPaths(schema, key .. ".WheelAdd(?).wheels.wheel(?)")
		
		schema:register(XMLValueType.STRING, "vehicle.colorConfigurations.colorConfiguration(?)#canal", "canal")
		schema:register(XMLValueType.STRING, "vehicle.colorConfigurations.colorConfiguration(?)#name", "name")
		schema:register(XMLValueType.STRING, "vehicle.colorConfigurations.colorConfiguration(?)#filename", "filename")
		schema:register(XMLValueType.BOOL, "vehicle.colorConfigurations.colorConfiguration(?)#useShader", "useShader")
		schema:register(XMLValueType.BOOL, "vehicle.colorConfigurations.colorConfiguration(?)#useFilename", "useFilename")
		
		schema:register(XMLValueType.NODE_INDEX, "vehicle.colorConfigurations.colorConfiguration(?)#node", "node")
		local i = 0
		while i < 10 do
			schema:register(XMLValueType.INT, key .. ".".. newConfguration.configName .."(?)#contrainteIndex"..i, "contrainteIndex")
			
			schema:register(XMLValueType.NODE_INDEX, key .. ".".. newConfguration.configName .."(?)#linkNode"..i, "linkNode")
			--local canalColor = string.format("(?)#colorCanal%d", i)
			schema:register(XMLValueType.STRING, key .. ".".. newConfguration.configName .."(?)#colorCanal"..i, "colorCanal")
			
			schema:register(XMLValueType.STRING, key .. ".".. newConfguration.configName .."(?)#shaderParameter"..i, "shaderParameter")
			i = i + 1
		end

	end
end
function ImportParts.registerOverwrittenFunctions(vehicleType)
end
function ImportParts.registerFunctions(vehicleType)	
end
function ImportParts.registerEvents(vehicleType)
end
function ImportParts:registerActionEventsPlayer()
end
function ImportParts:registerActionEventsMenu()
end

function ImportParts.registerEventListeners(vehicleType)
	SpecializationUtil.registerEventListener(vehicleType, "onLoad", ImportParts)	
	SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", ImportParts)
	SpecializationUtil.registerEventListener(vehicleType, "onDelete", ImportParts)
    SpecializationUtil.registerEventListener(vehicleType, "onReadStream", ImportParts)
    SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", ImportParts)
	SpecializationUtil.registerEventListener(vehicleType, "onUpdate", ImportParts)
	SpecializationUtil.registerEventListener(vehicleType, "onDraw", ImportParts)

end

function ImportParts:onLoad(vehicle, savegame)	

	for _, newConfguration in pairs(ImportParts.newConfgurations) do
        ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle." .. newConfguration.configName .. "Configurations." .. newConfguration.configName .. "Configuration", self.configurations[newConfguration.configName], self.components, self)
	end
	self.colorParts = {}
	local modDesc = loadXMLFile("modDesc", ImportParts.modDirectory .. "modDesc.xml");
	local j = 0
	while true do
		local baseNameConfig = string.format("modDesc.newConfigurations.newConfiguration(%d)", j)
		local configName = getXMLString(modDesc, baseNameConfig .. "#configName")
		if configName == nil then
			break
		end
			if getXMLBool(modDesc, baseNameConfig .. "#xmlFile") then
				local i = 0
				while true do
					nameBase = "vehicle." .. configName .. "Configurations." .. configName .. "Configuration(%d)"
					local baseName = string.format(nameBase, i)
					self.index = nil
					m = 0
					if not self.xmlFile:hasProperty(baseName) then
						break
					end
					while true do
						self.index = self.xmlFile:getValue(baseName .. "." .. configName .. "(" .. m .. ")" .. "#xmlFilename")


						local index = self.index
						if index == nil then
							break
						end
						if self.configurations[configName] ~= nil and i == self.configurations[configName]-1 then

							baseIndexName = baseName .. "." .. configName .. "(" .. m .. ")"

							if ImportParts:getContrainte(self, baseIndexName) then
								xmlFilename = Utils.getFilename(index, self.baseDirectory)
								prefix = getXMLString(modDesc, baseNameConfig .. "#xmlPrefix")
								if prefix == nil then
									prefix = configName
								end
								local cabineXmlFile = loadXMLFile(prefix, xmlFilename)
								local filename = getXMLString(cabineXmlFile, prefix .. "#filename")
								--self.xmlFile:iterate(baseName .. "." .. configName, function(index, key)
								--	self.linkNode = self.xmlFile:getValue(key .. "#linkNode", nil, self.components, self.i3dMappings)
								--end)
								
										if getXMLString(modDesc, baseNameConfig .. "#dependant") ~= nil then
											self.linkNode = self.xmlFile:getValue(baseName .. "." .. configName .. "(" .. m .. ")#linkNode"..self.configurations[getXMLString(modDesc, baseNameConfig .. "#dependant")]-1, nil, self.components, self.i3dMappings)
										else
											self.linkNode = self.xmlFile:getValue(baseName .. "." .. configName .. "(" .. m .. ")#linkNode", nil, self.components, self.i3dMappings)
										end
								filename = Utils.getFilename(filename, self.baseDirectory)
								local i3dNode = g_i3DManager:loadSharedI3DFile(filename, false, false)
								local node = I3DUtil.indexToObject(i3dNode, Utils.getNoNil(getXMLString(cabineXmlFile, prefix .. ".cab#node"), "0"))
								
								local nodePath = getXMLString(cabineXmlFile, prefix .. "#nodePath")
								
								ImportParts:getColorPart(self, prefix, i3dNode, cabineXmlFile, nodePath)
								
								local xmlFile = XMLFile.load(prefix, xmlFilename, self.xmlSchema)
								link(self.linkNode, node)
																
								local k = 0
								while true do
									local baseName = string.format(prefix .. ".Parts.Part(%d)", k)
									local index = getXMLString(cabineXmlFile, baseName .. "#filename")
									if index == nil then
										break
									end
									--self.linkNode = I3DUtil.indexToObject(self.components, getXMLString(cabineXmlFile, baseName .. "#linkNode"));
									if getXMLString(modDesc, baseNameConfig .. "#dependant") ~= nil then
											self.linkNode = I3DUtil.indexToObject(self.components, getXMLString(cabineXmlFile, baseName .. "#linkNode"..self.configurations[getXMLString(modDesc, baseNameConfig .. "#dependant")]-1));
										else
											self.linkNode = I3DUtil.indexToObject(self.components, getXMLString(cabineXmlFile, baseName .. "#linkNode"));
										end
									index = Utils.getFilename(index, self.baseDirectory)
									local i3dNodeParts = g_i3DManager:loadSharedI3DFile(index, false, false)
									local node = I3DUtil.indexToObject(i3dNodeParts, "0")
									ImportParts:getColorPart(self, baseName, i3dNodeParts, cabineXmlFile)
									link(self.linkNode, node)
									k = k + 1  
								end  
								ImportParts:loadMove(self, baseName .. "." .. configName .. "(" .. m)
								ImportParts:importLight(self, xmlFile)
								ImportParts:addWheel(self, baseName, m)
								ImportParts:importFillUnit(self, xmlFile)
								ImportParts:importFillVolume(self, xmlFile)
								ImportParts:importAnim(self, prefix, xmlFile, i3dNode)
								ImportParts:importTrailer(self, xmlFile)
								ImportParts:importDischargeable(self, xmlFile)
								ImportParts:importFoldable(self, xmlFile)
								
								ImportParts:importMoovingTool(self, prefix, xmlFile)
								ImportParts:importAttacherJoint(self, xmlFile)
								ImportParts:addColorPartsByNode(self, cabineXmlFile, prefix, i3dNode)
								
								delete(cabineXmlFile)
								
							end
						end
						m = m + 1
					end
					i = i + 1 
					
				end  
			else
				local dependantToBaseConfig = getXMLString(modDesc, baseNameConfig .. "#dependantToBaseConfig")
				if dependantToBaseConfig ~= nil then 
					local i = 0
					while true do
						nameBase = "vehicle." .. configName .. "Configurations." .. configName .. "Configuration(%d)"
						local baseName = string.format(nameBase, i)
						
						if not self.xmlFile:hasProperty(baseName) then
							break
						end
						local m = 0
						while true do
							self.Filename = nil
							
							self.Filename = self.xmlFile:getValue(baseName .. "." .. configName .. "(" .. m .. ")#filename")
							if self.Filename == nil or m > 100 then
								break
							end
							if self.configurations[configName] ~= nil and i == self.configurations[configName]-1 then	
									Filename = Utils.getFilename(self.Filename .. self.configurations[dependantToBaseConfig] .. ".i3d", self.baseDirectory)
									local i3dNode = g_i3DManager:loadSharedI3DFile(Filename, false, false)
									if getXMLString(modDesc, baseNameConfig .. "#dependant") ~= nil then
										self.linkNode = self.xmlFile:getValue(baseName .. "." .. configName .. "(" .. m .. ")#linkNode"..self.configurations[getXMLString(modDesc, baseNameConfig .. "#dependant")]-1, nil, self.components, self.i3dMappings)
									else
										self.linkNode = self.xmlFile:getValue(baseName .. "." .. configName .. "(" .. m .. ")#linkNode", nil, self.components, self.i3dMappings)
									end
									local node = I3DUtil.indexToObject(i3dNode, "0")
									link(self.linkNode, node)	
									ImportParts:loadMove(self, baseName .. "." .. configName .. "(" .. m)
									ImportParts:addWheel(self, baseName, m)
							end
							m = m + 1
						end
						i = i + 1
					end
				else
					local i = 0
					while true do
						nameBase = "vehicle." .. configName .. "Configurations." .. configName .. "Configuration(%d)"
						local baseName = string.format(nameBase, i)
						
						if not self.xmlFile:hasProperty(baseName) then
							break
						end
						local m = 0
						while true do
							self.Filename = nil

							self.Filename = self.xmlFile:getValue(baseName .. "." .. configName .. "(" .. m .. ")#filename")
							if self.Filename == nil or m > 100 then
								break
							end
							
								if self.configurations[configName] ~= nil and i == self.configurations[configName]-1 then
									baseIndexName = baseName .. "." .. configName .. "(" .. m .. ")"
									if ImportParts:getContrainte(self, baseIndexName) then
										if getXMLString(modDesc, baseNameConfig .. "#dependant") ~= nil then
											self.linkNode = self.xmlFile:getValue(baseName .. "." .. configName .. "(" .. m .. ")#linkNode"..self.configurations[getXMLString(modDesc, baseNameConfig .. "#dependant")]-1, nil, self.components, self.i3dMappings)
										else
											self.linkNode = self.xmlFile:getValue(baseName .. "." .. configName .. "(" .. m .. ")#linkNode", nil, self.components, self.i3dMappings)
										end
										
										if getXMLString(modDesc, baseNameConfig .. "#lockConfig") then
											self.xmlFile:getValue(baseName .. "." .. configName .. "(" .. m .. ")#numberConfig", nil)
										end
										
										Filename = Utils.getFilename(self.Filename, self.baseDirectory)
										local i3dNode = g_i3DManager:loadSharedI3DFile(Filename, false, false)
										
										ImportParts:getColorPart(self, baseIndexName, i3dNode)

										local node = I3DUtil.indexToObject(i3dNode, "0")
										link(self.linkNode, node)	
										ImportParts:loadMove(self, baseName .. "." .. configName .. "(" .. m)
										ImportParts:addWheel(self, baseName, m)
									end	
								end
							m = m + 1
						end
						i = i + 1

					end
				end
			end
		j = j + 1
	end
		
	self.color = {}
	n = 0
	while true do
		local configName = string.format("vehicle.colorConfigurations.colorConfiguration(%d)", n)
			canal = self.xmlFile:getValue(configName .. "#canal")
			name = self.xmlFile:getValue(configName .. "#name")
			filename = self.xmlFile:getValue(configName .. "#filename")
			useShader = self.xmlFile:getValue(configName .. "#useShader")
			useFilename = self.xmlFile:getValue(configName .. "#useFilename")
			if useShader == nil then
				useShader = false
			end
			if useFilename == nil then
				useFilename = true
			end
		if canal == nil then
			break
		end
		if filename ~= nil then
			Filename = Utils.getFilename(filename, self.baseDirectory)
			 i3dNode = g_i3DManager:loadSharedI3DFile(Filename, false, false)
		else
			i3dNode = self.xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings)
		end
		local color = {canal, name, i3dNode, useShader, useFilename}
		table.insert(self.color, color)
		n = n + 1
	end
	for _, parts in pairs(self.colorParts) do
		
		local a, b, h = unpack(parts)
		for _, color in pairs(self.color) do
			local c, d, e, f, g, q = unpack(color)
			if c == b then
				if not g then
					self.colorPart = e
				else
					self.colorPart = I3DUtil.indexToObject(e, string.format("0|%d", self.configurations[d]-1))
				end
				if not f then
					setMaterial(a, getMaterial(self.colorPart, 0), 0)
					--break
				else
					local color = ConfigurationUtil.getColorByConfigId(self, d, self.configurations[d]);
					local r, g, b = unpack(color);
					if h == nil then
						h = "colorMat0"
					end
					if materialId == nil then
						_, _, _, materialId = getShaderParameter(a, h);
					end  
					materialName = q
					setShaderParameter(a, h, r, g, b, materialId, false)
				end
			end
		end
	end 
	

end;

function ImportParts:onPostLoad(savegame)
        local spec = self.spec_cylindered
        for _, part in pairs(spec.movingTools) do
				if part.xmlFile ~= nil then
					ImportParts:loadDependentWheels(part.xmlFile, part.key, part, self)
					self:loadDependentAttacherJoints(part.xmlFile, part.key, part)
				else
					self:loadDependentAttacherJoints(self.xmlFile, part.key, part)
					ImportParts:loadDependentWheels(self.xmlFile, part.key, part, self)
				end
        end
		
		if self.rampeNode ~= nil and self.rampeRef ~= nil then
			setTranslation(self.rampeNode, 0, 0, 0)
			link(self.rampeRef, self.rampeNode)
			setRotation(self.rampeNode, 0, 180*math.pi/180, 0)
		end
end


function ImportParts:loadDependentWheels(xmlFile, baseName, entry, self)
        if SpecializationUtil.hasSpecialization(Wheels, self.specializations) then
                local indices = xmlFile:getValue(baseName .. "#wheelIndices", nil, true)

                if indices ~= nil then
                        entry.wheels = {}

                        for _, wheelIndex in pairs(indices) do
                                local wheel = self:getWheelFromWheelIndex(wheelIndex)

                                if wheel ~= nil then
                                        table.insert(entry.wheels, wheel)
                                end
                        end
                end

                local wheelNodesStr = xmlFile:getValue(baseName .. "#wheelNodes")

                if wheelNodesStr ~= nil and wheelNodesStr ~= "" then
                        local wheelNodes = wheelNodesStr:split(" ")

                        for i = 1, #wheelNodes do
                                local wheel = self:getWheelByWheelNode(wheelNodes[i])

                                if wheel ~= nil then
                                        table.insert(entry.wheels, wheel)
                                else
                                        Logging.xmlWarning(xmlFile, "Invalid wheelNode '%s' for '%s'!", wheelNodes[i], baseName)
                                end
                        end
                end
        end
end

function ImportParts:getContrainte(self, baseIndexName)
	self.contrainteValide = true
	l = 0
	while true do
		if not self.xmlFile:hasProperty(baseIndexName .. "#contrainteIndex" .. l) or l > 9 then
			break
		end
		self.contrainteIndex = self.xmlFile:getValue(baseIndexName .. "#contrainteIndex" .. l)
		self.contrainte = self.xmlFile:getValue(baseIndexName .. "#contrainte")
								
		if self.contrainteIndex ~= "nil" then
			if self.contrainteIndex == self.configurations[self.contrainte] then
				self.contrainteValide = true
				break
			else
				self.contrainteValide = false
			end
		end
		l = l + 1
	end
	return self.contrainteValide
end

function ImportParts:getColorPart(self, baseIndexName, i3dNode, xmlFile, nodePath, node)
	local o = 0
	while true do								

		colorName = nil
		if xmlFile == nil then
			if not self.xmlFile:hasProperty(baseIndexName .. "#colorCanal" .. o) then
				break
			end
			colorName = self.xmlFile:getValue(baseIndexName .. string.format("#colorCanal%d", o))
			shaderParameter = self.xmlFile:getValue(baseIndexName .. string.format("#shaderParameter%d", o))
		else
			colorName = getXMLString(xmlFile, baseIndexName .. string.format("#colorCanal%d", o))
			shaderParameter = getXMLString(xmlFile, baseIndexName .. string.format("#shaderParameter%d", o))
		end
		if colorName == nil then
			break
		end
		if nodePath == nil then
			if node == nil then
				nodei3d = I3DUtil.indexToObject(i3dNode, "0|".. o)
			else	
				nodei3d = node
			end
		else	
			 nodei3d = I3DUtil.indexToObject(i3dNode, nodePath .. o)
		end
		local part = {nodei3d, colorName, shaderParameter}
		table.insert(self.colorParts, part)
		o = o + 1
	end
end

function ImportParts:loadMove(self, key)
	local node = self.xmlFile:getValue(key .. ")#node", nil, self.components, self.i3dMappings)
	local trans = self.xmlFile:getValue(key .. ")#trans")
	local rot = self.xmlFile:getValue(key .. ")#rot")
	local scale = self.xmlFile:getValue(key .. ")#scale")
	local axis = self.xmlFile:getValue(key .. ")#axis")
	
	

	local parentNode = self.xmlFile:getValue(key .. ")#parentNode", nil, self.components, self.i3dMappings)
	local childNode = self.xmlFile:getValue(key .. ")#childNode", nil, self.components, self.i3dMappings)
	local resetPos = self.xmlFile:getValue(key .. ")#resetPos", nil, self.components, self.i3dMappings)
	--local ReplaceRamp = self.xmlFile:getValue(key .. ")#replaceElementCompond", nil, self.components, self.i3dMappings)

	if parentNode ~= nil and childNode ~= nil then
		setTranslation(childNode, 0, 0, 0)
		link(parentNode, childNode)
	end
	if resetPos ~= nil then
		
		setTranslation(resetPos, 0, 0, 0)
		setTranslation(self.components[2].node, 0, 0, 0)
		local x, y, z = getWorldTranslation(parentNode)
        setWorldTranslation(self.components[2].node, x, y, z)
        self.components[2].originalTranslation = {
                                                x,
                                                y,
                                                z
                                        }
        self.components[2].sentTranslation = {
                                                x,
                                                y,
                                                z
                                        }
	end
	
	if parentNode ~= nil and childNode ~= nil then
		self.rampeRef = self.components[2].node
		self.rampeNode = getChildAt(parentNode, 0)
	end
	if axis == 1 then
		if trans ~= nil then
			x, y, z = getTranslation(node) 
			setTranslation(node, trans, y, z)
		end
		if rot ~= nil then
			x, y, z = getRotation(node) 
			setRotation(node, rot, y, z)
		end	
		if scale ~= nil then
			x, y, z = getScale(node) 
			setScale(node, scale, y, z)
		end
	end	
	if axis == 2 then
		if trans ~= nil then
			x, y, z = getTranslation(node) 
			setTranslation(node, x, trans, z)
		end
		if rot ~= nil then
			x, y, z = getRotation(node) 
			setRotation(node, x, rot, z)
		end	
		if scale ~= nil then
			x, y, z = getScale(node) 
			setScale(node, x, scale, z)
		end
	end	
	if axis == 3 then
		if trans ~= nil then
			x, y, z = getTranslation(node) 
			setTranslation(node, x, y, z+trans)
		end
		if rot ~= nil then
			x, y, z = getRotation(node) 
			setRotation(node, x, y, rot)
		end	
		if scale ~= nil then
			x, y, z = getScale(node) 
			setScale(node, x, y, scale)
		end
	end
	
end

function ImportParts:importLight(self, xmlFile)
		local spec = self.spec_lights
        local registeredLightTypes = {}
        local i = 0

        while true do
                local key = string.format("vehicle.lights.states.state(%d)", i)

                if not xmlFile:hasProperty(key) then
                        break
                end

                local lightTypes = xmlFile:getValue(key .. "#lightTypes", nil, true)

                for _, lightType in pairs(lightTypes) do
                        if registeredLightTypes[lightType] == nil then
                                registeredLightTypes[lightType] = lightType
                                spec.numLightTypes = spec.numLightTypes + 1
                        end
                end

                table.insert(spec.lightStates, lightTypes)

                i = i + 1
        end

        local function loadLightsMaskFromXML(xmlFile, key, default)
                local lightTypes = xmlFile:getValue(key, default, true)
                local lightsTypesMask = 0

                for _, lightType in pairs(lightTypes) do
                        lightsTypesMask = bitOR(lightsTypesMask, 2^lightType)
                end

                return lightsTypesMask
        end

        spec.aiLightsTypesMask = loadLightsMaskFromXML(xmlFile, "vehicle.lights.states.aiState#lightTypes", "0")
        spec.aiLightsTypesMaskWork = loadLightsMaskFromXML(xmlFile, "vehicle.lights.states.aiState#lightTypesWork", "0 1 2")

        ImportParts:ImportLoadRealLightSetup(xmlFile, "vehicle.lights.realLights.low", spec.realLights.low, self)
        ImportParts:ImportLoadRealLightSetup(xmlFile, "vehicle.lights.realLights.high", spec.realLights.high, self)
		
        self:loadStaticLightNodes(xmlFile, "vehicle.lights.defaultLights.defaultLight", spec.staticLights, spec.defaultLightsStatic)
        self:loadStaticLightNodes(xmlFile, "vehicle.lights.brakeLights.brakeLight", spec.staticLights, spec.brakeLightsStatic)
        self:loadStaticLightNodes(xmlFile, "vehicle.lights.reverseLights.reverseLight", spec.staticLights, spec.reverseLightsStatic)
        self:loadStaticLightNodes(xmlFile, "vehicle.lights.turnLights.turnLightLeft", spec.staticLights, spec.turnLightsLeftStatic)
        self:loadStaticLightNodes(xmlFile, "vehicle.lights.turnLights.turnLightRight", spec.staticLights, spec.turnLightsRightStatic)

        xmlFile:iterate("vehicle.lights.sharedLight", function (_, key)
                self:loadSharedLight(xmlFile, key, spec.sharedLights)
        end)

        spec.maxLightState = Lights.LIGHT_TYPE_HIGHBEAM

        for j = 1, #spec.staticLights do
                for _, lightType in pairs(spec.staticLights[j].lightTypes) do
                        spec.maxLightState = math.max(spec.maxLightState, lightType)
                end
        end

        for j = 1, #spec.realLights.low.realLights do
                for _, lightType in pairs(spec.realLights.low.realLights[j].lightTypes) do
                        spec.maxLightState = math.max(spec.maxLightState, lightType)
                end
        end

        for j = 1, #spec.realLights.high.realLights do
                for _, lightType in pairs(spec.realLights.high.realLights[j].lightTypes) do
                        spec.maxLightState = math.max(spec.maxLightState, lightType)
                end
        end

        spec.maxLightStateMask = 2^(spec.maxLightState + 1) - 1
        spec.additionalLightTypes = {
                brakeLight = spec.maxLightState + 1,
                turnLightLeft = spec.maxLightState + 2,
                turnLightRight = spec.maxLightState + 3,
                turnLightAny = spec.maxLightState + 4,
                reverseLight = spec.maxLightState + 5,
                interiorLight = spec.maxLightState + 6
        }
        spec.totalNumLightTypes = spec.additionalLightTypes.interiorLight

        if spec.totalNumLightTypes > 31 then
                Logging.xmlError(xmlFile, "Max. number of light types reached (31). Please reduce them.")

                spec.totalNumLightTypes = 31
        end

        spec.hasTurnLights = #spec.turnLightsLeft > 0 or #spec.turnLightsRight > 0

        xmlFile:iterate("vehicle.lights.beaconLights.beaconLight", function (_, key)
                self:loadBeaconLightFromXML(xmlFile, key)
        end)

        if self.isClient ~= nil then
                spec.samples = {
                        toggleLights = g_soundManager:loadSampleFromXML(xmlFile, "vehicle.lights.sounds", "toggleLights", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self),
                        turnLight = g_soundManager:loadSampleFromXML(xmlFile, "vehicle.lights.sounds", "turnLight", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
                }
        end

        if self.loadDashboardsFromXML ~= nil then
                self:loadDashboardsFromXML(xmlFile, "vehicle.lights.dashboards", {
                        valueFunc = "lightsTypesMask",
                        valueTypeToLoad = "lightState",
                        valueObject = spec,
                        additionalAttributesFunc = Lights.dashboardLightAttributes,
                        stateFunc = Lights.dashboardLightState
                })
                self:loadDashboardsFromXML(xmlFile, "vehicle.lights.dashboards", {
                        valueFunc = "turnLightState",
                        valueTypeToLoad = "turnLightLeft",
                        valueObject = spec,
                        valueCompare = {
                                Lights.TURNLIGHT_LEFT,
                                Lights.TURNLIGHT_HAZARD
                        }
                })
                self:loadDashboardsFromXML(xmlFile, "vehicle.lights.dashboards", {
                        valueFunc = "turnLightState",
                        valueTypeToLoad = "turnLightRight",
                        valueObject = spec,
                        valueCompare = {
                                Lights.TURNLIGHT_RIGHT,
                                Lights.TURNLIGHT_HAZARD
                        }
                })
                self:loadDashboardsFromXML(xmlFile, "vehicle.lights.dashboards", {
                        valueFunc = "turnLightTriState",
                        idleValue = 0.5,
                        valueTypeToLoad = "turnLight",
                        valueObject = spec
                })
                self:loadDashboardsFromXML(xmlFile, "vehicle.lights.dashboards", {
                        valueFunc = "turnLightState",
                        valueTypeToLoad = "turnLightHazard",
                        valueObject = spec,
                        valueCompare = {
                                Lights.TURNLIGHT_HAZARD
                        }
                })
                self:loadDashboardsFromXML(xmlFile, "vehicle.lights.dashboards", {
                        valueFunc = "turnLightState",
                        valueTypeToLoad = "turnLightAny",
                        valueObject = spec,
                        valueCompare = {
                                Lights.TURNLIGHT_LEFT,
                                Lights.TURNLIGHT_RIGHT,
                                Lights.TURNLIGHT_HAZARD
                        }
                })
                self:loadDashboardsFromXML(xmlFile, "vehicle.lights.dashboards", {
                        valueTypeToLoad = "beaconLight",
                        valueObject = spec,
                        valueFunc = function (_spec)
                                return _spec.beaconLightsActive and 1 or 0
                        end
                })
        end
end

function ImportParts:ImportLoadRealLightSetup(xmlFile, key, lightTable, self)
		if lightTable.realLights == nil then 
			lightTable.realLights = {}
		end
		if lightTable.defaultLights == nil then
			lightTable.defaultLights = {}
		end
		if lightTable.turnLightsLeft == nil then
			lightTable.turnLightsLeft = {}
		end
		if lightTable.turnLightsRight == nil then
			lightTable.turnLightsRight = {}
		end
		if lightTable.brakeLights == nil then
			lightTable.brakeLights = {}
		end
		if lightTable.reverseLights == nil then
			lightTable.reverseLights = {}
		end
		if  lightTable.interiorLights == nil then
			lightTable.interiorLights = {}
		end

        self:loadRealLights(xmlFile, key .. ".light", lightTable.realLights, lightTable.defaultLights)
        self:loadRealLights(xmlFile, key .. ".brakeLight", lightTable.realLights, lightTable.brakeLights)
        self:loadRealLights(xmlFile, key .. ".reverseLight", lightTable.realLights, lightTable.reverseLights)
        self:loadRealLights(xmlFile, key .. ".turnLightLeft", lightTable.realLights, lightTable.turnLightsLeft)
        self:loadRealLights(xmlFile, key .. ".turnLightRight", lightTable.realLights, lightTable.turnLightsRight)
        self:loadRealLights(xmlFile, key .. ".interiorLight", lightTable.realLights, lightTable.interiorLights)

        for i = 1, #lightTable.interiorLights do
                local interiorLight = lightTable.interiorLights[i]
                interiorLight.customChargeFunction = self.getInteriorLightBrightness
                self.spec_lights.interiorLightsAvailable = true
        end
end

function ImportParts:importAnim(self, configName, xmlFile, i3dNode)
		local spec = self.spec_animatedVehicle
        local i = 0
        while true do
                local key = string.format("vehicle.animations.animation(%d)", i)
                if not xmlFile:hasProperty(key) then
                        break
                end

                local animation = {}
				
                if self:loadAnimation(xmlFile, key, animation) then
                        spec.animations[animation.name] = animation
                end

                i = i + 1
        end

end

function ImportParts:importMoovingTool(self, configName, xmlFile)
	local spec = self.spec_cylindered
	       i = 0
		local referenceNodes = {}
		local i = 0

        while true do
                local partKey = string.format("vehicle.cylindered.movingParts.movingPart(%d)", i)

                if not xmlFile:hasProperty(partKey) then
                        break
                end

                local entry = {}

                if self:loadMovingPartFromXML(xmlFile, partKey, entry) then
                        if referenceNodes[entry.node] == nil then
                                referenceNodes[entry.node] = {}
                        end

                        if spec.nodesToMovingParts[entry.node] == nil then
                                table.insert(referenceNodes[entry.node], entry)
                                self:loadDependentParts(xmlFile, partKey, entry)
                                self:loadDependentComponentJoints(xmlFile, partKey, entry)
                                self:loadCopyLocalDirectionParts(xmlFile, partKey, entry)
                                self:loadExtraDependentParts(xmlFile, partKey, entry)
                                self:loadDependentAnimations(xmlFile, partKey, entry)

                                entry.key = partKey
								entry.xmlFile = xmlFile
                                table.insert(spec.movingParts, entry)

                                if entry.isActiveDirty then
                                        table.insert(spec.activeDirtyMovingParts, entry)
                                end

                                spec.nodesToMovingParts[entry.node] = entry
                        else
                                Logging.xmlWarning(xmlFile, "Moving part with node '%s' already exists!", getName(entry.node))
                        end
                end

                i = i + 1
        end
		local i = 0
        while true do
                local toolKey = string.format("vehicle.cylindered.movingTools.movingTool(%d)", i)

                if not xmlFile:hasProperty(toolKey) then
                        break
                end

                local entry = {}

                if self:loadMovingToolFromXML(xmlFile, toolKey, entry) then
                        if referenceNodes[entry.node] == nil then
                                referenceNodes[entry.node] = {}
                        end

                        if spec.nodesToMovingTools[entry.node] == nil then
                                table.insert(referenceNodes[entry.node], entry)
                                self:loadDependentMovingTools(xmlFile, toolKey, entry)
                                self:loadDependentParts(xmlFile, toolKey, entry)
                                self:loadDependentComponentJoints(xmlFile, toolKey, entry)
                                self:loadExtraDependentParts(xmlFile, toolKey, entry)
                                self:loadDependentAnimations(xmlFile, toolKey, entry)

                                entry.isActive = true
                                entry.key = toolKey
								entry.xmlFile = xmlFile
                                table.insert(spec.movingTools, entry)

                                spec.nodesToMovingTools[entry.node] = entry
                        else
                                Logging.xmlWarning(xmlFile, "Moving tool with node '%s' already exists!", getName(entry.node))
                        end
                end

                i = i + 1
        end
		
		
        for _, part in pairs(spec.movingTools) do
                self:resolveDependentPartData(part.dependentPartData, referenceNodes)

                for j = #part.dependentMovingTools, 1, -1 do
                        local dependentTool = part.dependentMovingTools[j]
                        local tool = spec.nodesToMovingTools[dependentTool.node]

                        if tool ~= nil then
                                dependentTool.movingTool = tool
                        else
                                Logging.xmlWarning(self.xmlFile, "Dependent moving tool '%s' not defined. Ignoring it!", getName(dependentTool.node))
                                table.remove(part.dependentMovingTools, j)
                        end
                end
        end
end

function ImportParts:importTrailer(self, xmlFile)
		local spec = self.spec_trailer
		local configKey = string.format("vehicle.trailer.trailerConfigurations.trailerConfiguration(%d).trailer", 0)
        local i = 0

        while true do
                local key = string.format("%s.tipSide(%d)", configKey, i)

                if not xmlFile:hasProperty(key) then
                        break
                end

                local entry = {}

                if self:loadTipSide(xmlFile, key, entry) then
                        table.insert(spec.tipSides, entry)

                        entry.index = #spec.tipSides
                        spec.dischargeNodeIndexToTipSide[entry.dischargeNodeIndex] = entry
                end

                i = i + 1
        end
		
		 spec.infoText = xmlFile:getValue(configKey .. "#infoText", "action_toggleTipSide", self.customEnvironment, false)
        spec.tipSideCount = #spec.tipSides
        spec.preferedTipSideIndex = 1
        spec.currentTipSideIndex = nil
        spec.tipState = Trailer.TIPSTATE_CLOSED
        spec.remainingFillDelta = 0
        spec.dirtyFlag = self:getNextDirtyFlag()
end

function ImportParts:importAttacherJoint(self, xmlFile)
		local spec = self.spec_attacherJoints
        local i = 0
		attacherConfigs = string.format("vehicle.attacherJoints.attacherJointConfigurations.attacherJointConfiguration(%d)", 0)
        while true do
				local baseName = string.format(attacherConfigs .. ".attacherJoint(%d)", i)
                if not xmlFile:hasProperty(baseName) then
                        break
                end

                local attacherJoint = {}

                if self:loadAttacherJointFromXML(attacherJoint, xmlFile, baseName, i) then
                        table.insert(spec.attacherJoints, attacherJoint)

                        attacherJoint.index = #spec.attacherJoints
                end

                i = i + 1
        end

        spec.dirtyFlag = self:getNextDirtyFlag()
end

function ImportParts:importFillUnit(self, xmlFile)
		local spec = self.spec_fillUnit
        local i = 0

        while true do
                local key = string.format("vehicle.fillUnit.fillUnitConfigurations.fillUnitConfiguration(0).fillUnits.fillUnit(%d)", i)

                if not xmlFile:hasProperty(key) then
                        break
                end

                local entry = {}

                if self:loadFillUnitFromXML(xmlFile, key, entry, i + 1) then
                        table.insert(spec.fillUnits, entry)
                else
                        Logging.xmlWarning(xmlFile, "Could not load fillUnit for '%s'", key)
                        self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_ERROR)

                        break
                end

                i = i + 1
        end
end

function ImportParts:importFillVolume(self, xmlFile)
	local spec = self.spec_fillVolume
	local configKey = string.format("vehicle.fillVolume.fillVolumeConfigurations.fillVolumeConfiguration(0).volumes")
        xmlFile:iterate(configKey .. ".volume", function (_, key)
                local entry = {}

                if self:loadFillVolume(xmlFile, key, entry) then
                        table.insert(spec.volumes, entry)

                        entry.index = #spec.volumes
                end
        end)


        for _, fillVolume in ipairs(spec.volumes) do
                local capacity = self:getFillUnitCapacity(fillVolume.fillUnitIndex)
                local fillVolumeCapacity = capacity * fillVolume.fillUnitFactor
                fillVolume.volume = createFillPlaneShape(fillVolume.baseNode, "fillPlane", fillVolumeCapacity, fillVolume.maxDelta, fillVolume.maxSurfaceAngle, fillVolume.maxPhysicalSurfaceAngle, fillVolume.maxSurfaceDistanceError, fillVolume.maxSubDivEdgeLength, fillVolume.syncMaxSubDivEdgeLength, fillVolume.allSidePlanes, fillVolume.retessellateTop)

                if fillVolume.volume == nil or fillVolume.volume == 0 then
                        print("Warning: fillVolume '" .. tostring(getName(fillVolume.baseNode)) .. "' could not create actual fillVolume in '" .. self.configFileName .. "'! Simplifying the mesh could help")

                        fillVolume.volume = nil
                else
                        setVisibility(fillVolume.volume, false)

                        for i = #fillVolume.deformers, 1, -1 do
                                local deformer = fillVolume.deformers[i]
                                deformer.polyline = findPolyline(fillVolume.volume, deformer.posX, deformer.posZ)

                                if deformer.polyline == nil and deformer.polyline ~= -1 then
                                        print("Warning: Could not find 'polyline' for '" .. tostring(getName(deformer.node)) .. "' in '" .. self.configFileName .. "'")
                                        table.remove(fillVolume.deformers, i)
                                end
                        end

                        link(fillVolume.baseNode, fillVolume.volume)

                        local fillVolumeMaterial = g_materialManager:getBaseMaterialByName("fillPlane")

                        if fillVolumeMaterial ~= nil then
                                setMaterial(fillVolume.volume, fillVolumeMaterial, 0)
                                g_fillTypeManager:assignFillTypeTextureArrays(fillVolume.volume, true, true, true)
                        else
                                Logging.error("Failed to assign material to fill volume. Base Material 'fillPlane' not found!")
                        end

                        fillPlaneAdd(fillVolume.volume, 1, 0, 1, 0, 11, 0, 0, 0, 0, 11)

                        fillVolume.heightOffset = getFillPlaneHeightAtLocalPos(fillVolume.volume, 0, 0)

                        fillPlaneAdd(fillVolume.volume, -1, 0, 1, 0, 11, 0, 0, 0, 0, 11)
                end
        end

        xmlFile:iterate("vehicle.fillVolume.loadInfos.loadInfo", function (_, key)
                local entry = {}

                if self:loadFillVolumeInfo(xmlFile, key, entry) then
                        table.insert(spec.loadInfos, entry)
                end
        end)


        xmlFile:iterate("vehicle.fillVolume.unloadInfos.unloadInfo", function (_, key)
                local entry = {}

                if self:loadFillVolumeInfo(xmlFile, key, entry) then
                        table.insert(spec.unloadInfos, entry)
                end
        end)

        xmlFile:iterate("vehicle.fillVolume.heightNodes.heightNode", function (_, key)
                local entry = {}

                if self:loadFillVolumeHeightNode(xmlFile, key, entry) then
                        table.insert(spec.heightNodes, entry)

                        if spec.fillVolumeIndexToHeightNode[entry.fillVolumeIndex] == nil then
                                spec.fillVolumeIndexToHeightNode[entry.fillVolumeIndex] = {}
                        end

                        table.insert(spec.fillVolumeIndexToHeightNode[entry.fillVolumeIndex], entry)
                end
        end)

end

function ImportParts:importDischargeable(self, xmlFile)
	local spec = self.spec_dischargeable
	configKey = "vehicle.dischargeable"
	xmlFile:iterate(configKey .. ".dischargeNode", function (i, key)
                local entry = {}

                if self:loadDischargeNode(xmlFile, key, entry) then
                        local canBeAdded = true

                        if spec.dischargNodeMapping[entry.node] ~= nil then
                                Logging.xmlWarning(xmlFile, "DischargeNode '%s' already defined. Discharge nodes need to be unique. Ignoring it!", getName(entry.node))

                                canBeAdded = false
                        end

                        if entry.trigger.node ~= nil and spec.triggerToDischargeNode[entry.trigger.node] ~= nil then
                                Logging.xmlWarning(xmlFile, "DischargeNode trigger '%s' already defined. DischargeNode triggers need to be unique. Ignoring it!", getName(entry.trigger.node))

                                canBeAdded = false
                        end

                        if entry.activationTrigger.node ~= nil and spec.activationTriggerToDischargeNode[entry.activationTrigger.node] ~= nil then
                                Logging.xmlWarning(xmlFile, "DischargeNode activationTrigger '%s' already defined. DischargeNode activationTriggers need to be unique. Ignoring it!", getName(entry.activationTrigger.node))

                                canBeAdded = false
                        end

                        if self.getFillUnitExists ~= nil and not self:getFillUnitExists(entry.fillUnitIndex) then
                                Logging.xmlWarning(xmlFile, "FillUnit with index '%d' does not exist for discharge node '%s'. Ignoring discharge node!", entry.fillUnitIndex, key)

                                canBeAdded = false
                        end

                        if canBeAdded then
                                table.insert(spec.dischargeNodes, entry)
                                entry.index = #spec.dischargeNodes
                                spec.fillUnitDischargeNodeMapping[entry.fillUnitIndex] = entry
                                spec.dischargNodeMapping[entry.node] = entry

                                if entry.trigger.node ~= nil then
                                        spec.triggerToDischargeNode[entry.trigger.node] = entry
                                end

                                if entry.activationTrigger.node ~= nil then
                                        spec.activationTriggerToDischargeNode[entry.activationTrigger.node] = entry
                                end
                        end
                end
        end)
		spec.requiresTipOcclusionArea = spec.requiresTipOcclusionArea and #spec.dischargeNodes > 0
        spec.currentDischargeState = Dischargeable.DISCHARGE_STATE_OFF
        spec.currentRaycast = nil
        spec.forcedFillTypeIndex = nil
        spec.isAsyncRaycastActive = false

        self:setCurrentDischargeNodeIndex(1)

        spec.dirtyFlag = self:getNextDirtyFlag()
		if #spec.dischargeNodes ~= 0 then
                SpecializationUtil.registerEventListener(self, "onReadStream", Dischargeable)
                SpecializationUtil.registerEventListener(self, "onWriteStream", Dischargeable)
                SpecializationUtil.registerEventListener(self, "onReadUpdateStream", Dischargeable)
                SpecializationUtil.registerEventListener(self, "onWriteUpdateStream", Dischargeable)
                SpecializationUtil.registerEventListener(self, "onUpdate", Dischargeable)
                SpecializationUtil.registerEventListener(self, "onUpdateTick", Dischargeable)
                SpecializationUtil.registerEventListener(self, "onRegisterActionEvents", Dischargeable)
                SpecializationUtil.registerEventListener(self, "onFillUnitFillLevelChanged", Dischargeable)
                SpecializationUtil.registerEventListener(self, "onDeactivate", Dischargeable)
        end

end

function ImportParts:addColorPartsByNode(self, xmlFile, prefix, i3dNode)
	key = prefix
	i = 0
	while true do
		local baseName = string.format(prefix .. ".colorParts.Part(%d)", i)
		local index = getXMLString(xmlFile, baseName .. "#node")
		if index == nil then
			break
		end
		local node = I3DUtil.indexToObject(i3dNode, index)

		ImportParts:getColorPart(self, prefix, i3dNode, xmlFile, nil, node)					
		i = i + 1
	end
end

function ImportParts:addWheel(self, baseName, m)

										local configKey = baseName .. ".WheelAdd(" .. m .. ")"
										local spec = self.spec_wheels
										if self.xmlFile:getValue(baseName .. ".WheelAdd(" .. m .. ")#Add") then
											local i = 0
											while true do
												local wheelKey = string.format(".wheels.wheel(%d)", i)
												if not self.xmlFile:hasProperty(configKey .. wheelKey) then
													break
												end

												local wheel = {}
												wheel.xmlIndex = i
												wheel.updateIndex = (i % 4) + 1
												wheel.configIndex = self.configurations[configName]
												if self:loadWheelFromXML(self.xmlFile, configKey, wheelKey, wheel) then
													self:finalizeWheel(wheel)
													spec.maxUpdateIndex = math.max(spec.maxUpdateIndex, wheel.updateIndex)

													table.insert(spec.wheels, wheel)
												end

												i = i + 1
											end
										end
end

function ImportParts:importFoldable(self, xmlFile, savegame)
	local spec = self.spec_foldable
local i = 0
        local configKey = string.format("vehicle.foldable.foldingConfigurations.foldingConfiguration(0).foldingParts")

        while true do
                local baseKey = string.format(configKey .. ".foldingPart(%d)", i)

                if not xmlFile:hasProperty(baseKey) then
                        break
                end

                local foldingPart = {}

                if self:loadFoldingPartFromXML(xmlFile, baseKey, foldingPart) then
                        table.insert(spec.foldingParts, foldingPart)

                        spec.maxFoldAnimDuration = math.max(spec.maxFoldAnimDuration, foldingPart.animDuration)
                end

                i = i + 1
        end

        if #spec.foldingParts > 0 then
                self.isSelectable = true
        end

        if savegame ~= nil and not savegame.resetVehicles then
                spec.loadedFoldAnimTime = savegame.xmlFile:getValue(savegame.key .. ".foldable#foldAnimTime")
        end

        if spec.loadedFoldAnimTime == nil then
                spec.loadedFoldAnimTime = spec.startAnimTime
        end

        if self.additionalLoadParameters ~= nil then
                if self.additionalLoadParameters.foldableInvertFoldState then
                        spec.loadedFoldAnimTime = 1 - spec.loadedFoldAnimTime
                elseif self.additionalLoadParameters.foldableFoldingTime ~= nil then
                        spec.loadedFoldAnimTime = self.additionalLoadParameters.foldableFoldingTime
                end
        end
end
function ImportParts:onDelete() 
end;

function ImportParts:onReadStream(streamId, connection)
end;
  
function ImportParts:onWriteStream(streamId, connection)
end;

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

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

function ImportParts:onUpdate(dt, vehicle)
end;

function ImportParts:onUpdateTick() 
end;	
function ImportParts:onLeaveVehicle()
end;       
function ImportParts:onDraw()  
end;

--[[

function Wheels.loadBrandName(xmlFile, key, baseDir, customEnvironment, isMod, configItem)
        local name = xmlFile:getValue(key .. "#brand")
        configItem.wheelBrandKey = key

        if name ~= nil then
                local brandDesc = g_brandManager:getBrandByName(name)

                if brandDesc ~= nil then
                        configItem.wheelBrandName = brandDesc.title
                        configItem.wheelBrandIconFilename = brandDesc.image

                        table.insert(configItem.nameCompareParams, "wheelBrandName")
                else
                        Logging.warning("Wheel brand '%s' is not defined for '%s'!", name, key)
                end
        end
end

function Wheels.loadedBrandNames(xmlFile, baseKey, baseDir, customEnvironment, isMod, configurationItems, storeItem)
        local hasWheelBrands = false

        for _, item in ipairs(configurationItems) do
                if item.wheelBrandName ~= nil then
                        hasWheelBrands = true

                        break
                end
        end

        if hasWheelBrands then
                for _, item in ipairs(configurationItems) do
                        if item.wheelBrandName == nil then
                                Logging.xmlWarning(xmlFile, "Wheel brand missing for wheel configuration '%s'!", item.wheelBrandKey)
                        end
                end
        end
end

function Wheels.getBrands(items)
        local brands = {}
        local addedBrands = {}

        for _, item in ipairs(items) do
                if item.wheelBrandName ~= nil and addedBrands[item.wheelBrandName] == nil then
                        table.insert(brands, {
                                title = item.wheelBrandName,
                                icon = item.wheelBrandIconFilename
                        })

                        addedBrands[item.wheelBrandName] = true
                end
        end

        return brands
end

function Wheels.getWheelsByBrand(items, brand)
        local wheels = {}

        for _, item in ipairs(items) do
                if item.wheelBrandName == brand.title then
                        table.insert(wheels, item)
                end
        end

        return wheels
end

]]--