-- script to add customizable license plates to vehicles

LicensePlates = {}
LicensePlates.CONFIGFILENAME = "xml/defaultVehiclesConfig.xml"
LicensePlates.DIRECTORY = g_currentModDirectory
LicensePlates.I3D = "assets/licensePlate.i3d"
LicensePlates.SYMBOL_COLORS = {
	"black",
	"green",
	"red",
	black = 1,
	green = 2,
	red = 3
}
LicensePlates.BACKGROUND_COLORS = {
	"white",
	"yellow",
	"red",
	"green",
	white = 1,
	yellow = 2,
	red = 3,
	green = 4
}
LicensePlates.BACKGROUND_SHADER_PARAMS = {
	{
		r = 0.8,	g = 0.8,	b = 0.8,	mat = 0.0
	},
	{
		r = 0.7,	g = 0.7,	b = 0.0,	mat = 0.0
	},
	{
		r = 0.7,	g = 0.0,	b = 0.0,	mat = 0.0
	},
	{
		r = 0.0,	g = 0.7,	b = 0.0,	mat = 0.0
	}
}
LicensePlates.COUNTRY_CODES = {
	"AL",	"A",	"BY",	"B",	"BIH",
	"BG",	"HR",	"CY",	"CZ",	"DK",
	"EST",	"FIN",	"F",	"D",	"GR",
	"H",	"IS",	"IRL",	"I",	"LV",
	"LT",	"L",	"M",	"MD",	"MNE",
	"NL",	"NMK",	"N",	"PL",	"P",
	"RO",	"SRB",	"SK",	"SLO",	"E",
	"S",	"CH",	"UA",	"GB",
	AL = 1,	A = 2,	BY = 3,	B = 4,	BIH = 5,
	BG = 6,	HR = 7,	CY = 8,	CZ = 9,	DK = 10,
	EST = 11,	FIN = 12,	F = 13,	D = 14,	GR = 15,
	H = 16,	IS = 17, IRL = 18,	I = 19,	LV = 20,
	LT = 21,	L = 22,	M = 23,	MD = 24,	MNE = 25,
	NL = 26,	NMK = 27,	N = 28,	PL = 29,	P = 30,
	RO = 31,	SRB = 32,	SK = 33,	SLO = 34,	E = 35,
	S = 36, CH = 37, UA = 38, GB = 39
}
LicensePlates.COUNTRY_CODE_DEFAULT = LicensePlates.COUNTRY_CODES["D"] -- germany by default

-- load events from external files
source(Utils.getFilename("src/events/LicensePlatesVisibilityEvent.lua", LicensePlates.DIRECTORY))
source(Utils.getFilename("src/events/LicensePlatesTextEvent.lua", LicensePlates.DIRECTORY))
source(Utils.getFilename("src/events/LicensePlatesSymbolColorEvent.lua", LicensePlates.DIRECTORY))
source(Utils.getFilename("src/events/LicensePlatesBackgroundColorEvent.lua", LicensePlates.DIRECTORY))
source(Utils.getFilename("src/events/LicensePlatesCountryCodeEvent.lua", LicensePlates.DIRECTORY))
source(Utils.getFilename("src/events/LicensePlatesSmallPlateFormatEvent.lua", LicensePlates.DIRECTORY))

-- load and set up gui
source(Utils.getFilename("src/gui/LicensePlatesGui.lua", LicensePlates.DIRECTORY))
g_gui:loadGui(LicensePlates.DIRECTORY.."src/gui/LicensePlatesGui.xml", "LicensePlatesGui", LicensePlatesGui:new())

-- can be added to all vehicles
function LicensePlates.prerequisitesPresent(specializations)
	return true
end

-- add necessary event listeners for loading, saving, input and multiplayer
function LicensePlates.registerEventListeners(vehicleType)
	SpecializationUtil.registerEventListener(vehicleType, "onLoad", LicensePlates)
	SpecializationUtil.registerEventListener(vehicleType, "saveToXMLFile", LicensePlates)
	SpecializationUtil.registerEventListener(vehicleType, "onReadStream", LicensePlates)
	SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", LicensePlates)
	SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", LicensePlates)
end

-- override vehicle selection and dirt functions
function LicensePlates.registerOverwrittenFunctions(vehicleType)
	SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeSelected", LicensePlates.getCanBeSelected)
	SpecializationUtil.registerOverwrittenFunction(vehicleType, "validateWashableNode", LicensePlates.validateWashableNode)
	SpecializationUtil.registerOverwrittenFunction(vehicleType, "setNodeDirtAmount", LicensePlates.setNodeDirtAmount)
end

-- allow vehicles with license plates to be selected
function LicensePlates:getCanBeSelected(superFunc)
	return superFunc(self) or LicensePlates.hasLicensePlates(self)
end

-- add only the plate and not the symbols
function LicensePlates:validateWashableNode(superFunc, node)
	if not LicensePlates.hasLicensePlates(self) then
		return superFunc(self, node)
	end

	local spec = self.spec_licensePlates

	for _, wrapper in ipairs(spec.licensePlates) do
		if node == wrapper.i3d then
			return superFunc(self, node) -- wrapper is globally shared
		end

		local nodes = {}

		I3DUtil.getNodesByShaderParam(wrapper.i3d, "RDT", nodes)

		if nodes[node] then
			return false, nil -- do not save symbol nodes
		end
	end

	return superFunc(self, node)
end

-- update dirt for children of plate too
function LicensePlates:setNodeDirtAmount(superFunc, nodeData, dirtAmount, force)
	if not LicensePlates.hasLicensePlates(self) then
		return superFunc(self, nodeData, dirtAmount, force)
	end

	local spec = self.spec_licensePlates

	for _, wrapper in ipairs(spec.licensePlates) do
		for _, nodeDataNode in pairs(nodeData.nodes) do
			if nodeDataNode == wrapper.i3d then
				local clampedDirtAmount = MathUtil.clamp(dirtAmount, 0, 1)
				local nodes = {}

				I3DUtil.getNodesByShaderParam(wrapper.i3d, "RDT", nodes)

				for _, node in pairs(nodes) do
					local x, _, z, w = getShaderParameter(node, "RDT")

					setShaderParameter(node, "RDT", x, clampedDirtAmount, z, w, false)
				end
			end
		end
	end

	return superFunc(self, nodeData, dirtAmount, force)
end


-- add the input action to the menu
function LicensePlates:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
	if not g_client or not LicensePlates.hasLicensePlates(self) then
		return
	end

	local spec = self.spec_licensePlates

	self:clearActionEventsTable(spec.actionEvents)
	if isActiveForInput then
		local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.LICENSE_PLATE_CHANGE, self, LicensePlates.changeActionCallback, false, true, false, true, nil)
		g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_LOW)
	end
end

-- load each vehicle and initializes the spec
function LicensePlates:onLoad(savegame)
	local spec = self.spec_licensePlates

	if not spec then
		return
	end

	local filename = LicensePlates.getFilename(self)
	local config = LicensePlates.CONFIG[filename]

	-- mod support
	local key = "vehicle.licensePlates"
	if hasXMLProperty(self.xmlFile, key) then
		config = LicensePlates.parseVehicle(self.xmlFile, key)
	end

	if not config then
		return -- vehicle has no license plates defined
	end

	if #config.licensePlates == 0 and not config.parentFilename then
		g_logManager:error("Vehicle has no own license plates and no parent!")
		g_logManager:error("Vehicle filename: "..filename)
		return
	end

	local allLicensePlates = {}
	local currentConfig = config

	-- iterative lookup for parent(s)
	while currentConfig do
		for _, licensePlate in ipairs(currentConfig.licensePlates) do
			table.insert(allLicensePlates, licensePlate)
		end

		-- a misconfiguration can cause an endless loop
		currentConfig = LicensePlates.CONFIG[currentConfig.parentFilename]
	end

	if #allLicensePlates == 0 then
		g_logManager:error("Parent vehicle not found or parent vehicle has no license plates!")
		g_logManager:error("Vehicle filename: "..filename)
		return
	end

	-- now vehicle has at least one license plate
	spec.licensePlates = {}

	-- set up information for all plates and verify
	for _, wrapper in ipairs(allLicensePlates) do
		-- ensure correct link node
		local linkNode = I3DUtil.indexToObject(self.components, wrapper.linkNode, self.i3dMappings)
		if wrapper.linkNode and not linkNode then
			g_logManager:error("Could not find link node: "..wrapper.linkNode)
			g_logManager:error("Vehicle filename: "..filename)
			spec.licensePlates = nil -- disable mod for this vehicle
			return
		end

		-- ensure correct hidden node if present
		local hiddenNode = I3DUtil.indexToObject(self.components, wrapper.hiddenNode, self.i3dMappings)
		if wrapper.hiddenNode and not hiddenNode then
			g_logManager:error("Could not find node to hide: "..wrapper.hiddenNode)
			g_logManager:error("Vehicle filename: "..filename)
			spec.licensePlates = nil -- disable mod for this vehicle
			return
		end

		-- store information about size and hidden node
		table.insert(spec.licensePlates, {
			translation = wrapper.translation,
			rotation = wrapper.rotation,
			isSmall = wrapper.isSmall,
			linkNode = linkNode or self.rootNode,
			hiddenNode = hiddenNode -- can be nil
		})
	end

	LicensePlates.linkPlates(self)

	if savegame then
		-- load savegame specific information like visibility and text
		local isVisible = getXMLBool(savegame.xmlFile, savegame.key..".licensePlates#isVisible")
		local text = getXMLString(savegame.xmlFile, savegame.key..".licensePlates#text")
		local symbolColor = LicensePlates.SYMBOL_COLORS[getXMLString(savegame.xmlFile, savegame.key..".licensePlates#symbolColor")]
		local backgroundColor = LicensePlates.BACKGROUND_COLORS[getXMLString(savegame.xmlFile, savegame.key..".licensePlates#backgroundColor")]
		local countryCode = LicensePlates.COUNTRY_CODES[getXMLString(savegame.xmlFile, savegame.key..".licensePlates#countryCode")]
		local useFormat46 = getXMLBool(savegame.xmlFile, savegame.key..".licensePlates#useFormat46")

		LicensePlates.setData(self, isVisible, text, symbolColor, backgroundColor, countryCode, useFormat46, true)
	else
		-- set default values if not a savegame, nil is handled by subfunctions
		LicensePlates.setData(self,
			false,
			config.defaultText,
			LicensePlates.SYMBOL_COLORS[config.defaultSymbolColor],
			LicensePlates.BACKGROUND_COLORS[config.defaultBackgroundColor],
			LicensePlates.COUNTRY_CODES[config.defaultCountryCode],
			false, -- format 5-5
			true -- noEventSend
		)
	end
end

-- save each vehicle
function LicensePlates:saveToXMLFile(xmlFile, key)
	if not LicensePlates.hasLicensePlates(self) then
		return
	end

	local spec = self.spec_licensePlates

	-- only save attribute if different from default value

	if spec.isVisible then
		setXMLBool(xmlFile, key.."#isVisible", true)
	end

	if spec.text ~= "" then
		setXMLString(xmlFile, key.."#text", spec.text)
	end

	if spec.symbolColor ~= 1 then
		setXMLString(xmlFile, key.."#symbolColor", LicensePlates.SYMBOL_COLORS[spec.symbolColor])
	end

	if spec.backgroundColor ~= 1 then
		setXMLString(xmlFile, key.."#backgroundColor", LicensePlates.BACKGROUND_COLORS[spec.backgroundColor])
	end

	if spec.countryCode ~= LicensePlates.COUNTRY_CODE_DEFAULT then
		setXMLString(xmlFile, key.."#countryCode", LicensePlates.COUNTRY_CODES[spec.countryCode])
	end

	if spec.useFormat46 then
		setXMLBool(xmlFile, key.."#useFormat46", true)
	end
end

-- read spec attributes
function LicensePlates:onReadStream(streamId, connection)
	if not LicensePlates.hasLicensePlates(self) then
		return
	end

	local spec = self.spec_licensePlates

	LicensePlates.setData(self,
		streamReadBool(streamId),
		streamReadString(streamId),
		streamReadUInt8(streamId),
		streamReadUInt8(streamId),
		streamReadUInt8(streamId),
		streamReadBool(streamId),
		true -- noEventSend
	)
end

-- write spec attributes
function LicensePlates:onWriteStream(streamId, connection)
	if not LicensePlates.hasLicensePlates(self) then
		return
	end

	local spec = self.spec_licensePlates

	streamWriteBool(streamId, spec.isVisible)
	streamWriteString(streamId, spec.text)
	streamWriteUInt8(streamId, spec.symbolColor)
	streamWriteUInt8(streamId, spec.backgroundColor)
	streamWriteUInt8(streamId, spec.countryCode)
	streamWriteBool(streamId, spec.useFormat46)
end

-- show dialog with current data when input action is performed
function LicensePlates:changeActionCallback()
	local spec = self.spec_licensePlates

	local dialog = g_gui:showDialog("LicensePlatesGui")

	dialog.target:setCallback(LicensePlates.setData, self)
	dialog.target:setData(spec.isVisible, spec.text, spec.symbolColor, spec.backgroundColor, spec.countryCode, spec.useFormat46)
end

-- set all attributes together
function LicensePlates:setData(isVisible, text, symbolColor, backgroundColor, countryCode, useFormat46, noEventSend)
	-- set attributes with delayed text update
	LicensePlates.setSymbolColor(self, symbolColor, noEventSend, true)
	LicensePlates.setCountryCode(self, countryCode, noEventSend, true)
	LicensePlates.setSmallPlateFormat(self, useFormat46, noEventSend, true)

	-- background does not set text yet but links plates
	LicensePlates.setBackgroundColor(self, backgroundColor, noEventSend)

	-- visibility is corrected
	LicensePlates.setVisible(self, isVisible, noEventSend)

	-- and text is forced to be updated
	LicensePlates.setText(self, text, noEventSend, true)
end

-- set visibility
function LicensePlates:setVisible(isVisible, noEventSend)
	local spec = self.spec_licensePlates
	isVisible = isVisible or false -- ensures boolean and not nil

	if spec.isVisible == isVisible then
		return -- nothing to change
	end

	spec.isVisible = isVisible

	for _, wrapper in ipairs(spec.licensePlates) do
		if wrapper.i3d then
			setVisibility(wrapper.i3d, isVisible)
		end
		if wrapper.hiddenNode then
			setVisibility(wrapper.hiddenNode, not isVisible)
		end
	end

	LicensePlatesVisibilityEvent.sendEvent(self, isVisible, noEventSend)
end

-- set the text
function LicensePlates:setText(text, noEventSend, forceUpdate)
	local spec = self.spec_licensePlates
	text = text or "" -- ensures always a valid string

	-- trim if too long
	if #text > 10 then
		text = text:sub(1,10)
	end

	if spec.text == text and not forceUpdate then
		return -- nothing to change
	end

	spec.text = text

	for _, wrapper in ipairs(spec.licensePlates) do
		if wrapper.i3d then
			LicensePlates.clearVisual(self, wrapper)
			for i = 1, #text do
				LicensePlates.setVisualChar(self, wrapper, i, text:sub(i,i))
			end
		end
	end

	LicensePlatesTextEvent.sendEvent(self, text, noEventSend)
end

-- set symbol color
function LicensePlates:setSymbolColor(symbolColor, noEventSend, delayTextUpdate)
	local spec = self.spec_licensePlates
	symbolColor = symbolColor or 1 -- ensures always a valid color

	if spec.symbolColor == symbolColor then
		return -- nothing to change
	end

	spec.symbolColor = symbolColor

	-- set text again to refresh letters
	if not delayTextUpdate then
		LicensePlates.setText(self, spec.text, true, true) -- only local and force update
	end

	LicensePlatesSymbolColorEvent.sendEvent(self, symbolColor, noEventSend)
end

-- set background color
function LicensePlates:setBackgroundColor(backgroundColor, noEventSend)
	local spec = self.spec_licensePlates
	backgroundColor = backgroundColor or 1 -- ensures always a valid color

	if spec.backgroundColor == backgroundColor then
		return -- nothing to change
	end

	spec.backgroundColor = backgroundColor

	-- change shader parameters
	for _, wrapper in ipairs(spec.licensePlates) do
		local params = LicensePlates.BACKGROUND_SHADER_PARAMS[backgroundColor]

		setShaderParameter(wrapper.i3d, "colorMat0", params.r, params.g, params.b, params.mat, false)
	end

	LicensePlatesBackgroundColorEvent.sendEvent(self, backgroundColor, noEventSend)
end

-- set the country code
function LicensePlates:setCountryCode(countryCode, noEventSend, delayTextUpdate)
	local spec = self.spec_licensePlates
	countryCode = countryCode or LicensePlates.COUNTRY_CODE_DEFAULT -- ensures always a valid country code

	if spec.countryCode == countryCode then
		return -- nothing to change
	end

	spec.countryCode = countryCode

	-- set text again to refresh country sign
	if not delayTextUpdate then
		LicensePlates.setText(self, spec.text, true, true) -- only local and force update
	end

	LicensePlatesCountryCodeEvent.sendEvent(self, countryCode, noEventSend)
end

-- set format for small plates
function LicensePlates:setSmallPlateFormat(useFormat46, noEventSend, delayTextUpdate)
	local spec = self.spec_licensePlates
	useFormat46 = useFormat46 or false -- ensures boolean and not nil

	if spec.useFormat46 == useFormat46 then
		return -- nothing to change
	end

	spec.useFormat46 = useFormat46

	-- set text again to refresh letters
	if not delayTextUpdate then
		LicensePlates.setText(self, spec.text, true, true) -- only local and force update
	end

	LicensePlatesSmallPlateFormatEvent.sendEvent(self, useFormat46, noEventSend)
end

-- link all license plates to vehicle
function LicensePlates:linkPlates()
	local spec = self.spec_licensePlates

	for _, wrapper in ipairs(spec.licensePlates) do
		local i3d = g_i3DManager:loadSharedI3DFile(LicensePlates.I3D, LicensePlates.DIRECTORY, false, false)
		local index = wrapper.isSmall and "0|0|1" or "0|0|0"

		wrapper.i3d = I3DUtil.indexToObject(i3d, index)

		-- apply position data
		setTranslation(wrapper.i3d, wrapper.translation[1], wrapper.translation[2], wrapper.translation[3])
		setRotation(wrapper.i3d, math.rad(wrapper.rotation[1]), math.rad(wrapper.rotation[2]), math.rad(wrapper.rotation[3]))
		link(wrapper.linkNode, wrapper.i3d)

		-- i3d can not be used again because index is strange
		delete(i3d)
	end
end

-- remove the text from the plates
function LicensePlates:clearVisual(wrapper)
	if wrapper.isSmall then
		LicensePlates.removeAllFirstGrandchildren(self, getChildAt(wrapper.i3d, 0))
		LicensePlates.removeAllFirstGrandchildren(self, getChildAt(wrapper.i3d, 1))
	else
		LicensePlates.removeAllFirstGrandchildren(self, wrapper.i3d)
	end
end

-- removes the symbols from the placeholder group
function LicensePlates:removeAllFirstGrandchildren(node)
	for i = 0, getNumOfChildren(node) - 1 do
		local intermediate = getChildAt(node, i)

		if getNumOfChildren(intermediate) > 0 then
			local symbol = getChildAt(intermediate, 0)
			unlink(symbol)
			delete(symbol)
		end
	end
end

-- set a character at a position from 1 to 10 for a license plate
function LicensePlates:setVisualChar(wrapper, position, character)
	local spec = self.spec_licensePlates
	local index = LicensePlates.getSymbolIndex(character, spec.symbolColor, spec.countryCode)

	if not index then
		return -- user entered unsupported character
	end

	-- load and link new symbol
	local i3d = g_i3DManager:loadSharedI3DFile(LicensePlates.I3D, LicensePlates.DIRECTORY, false, false)
	local symbol = I3DUtil.indexToObject(i3d, index)

	local placeholderGroup = wrapper.i3d

	if wrapper.isSmall then
		placeholderGroup = getChildAt(placeholderGroup, spec.useFormat46 and 1 or 0)
	end

	local placeholder = getChildAt(placeholderGroup, position - 1)

	-- symbols are translated in i3d
	setTranslation(symbol, 0, 0, 0)

	link(placeholder, symbol)

	delete(i3d)
end

-- get the index for a symbol in the asset i3d
function LicensePlates.getSymbolIndex(c, symbolColor, countryCode)
	local colorPrefix = "0|2|"..symbolColor

	if "a" <= c and c <= "z" then
		-- turns into upper case
		return colorPrefix.."|0|" ..(c:byte() - 97)
	elseif "A" <= c and c <= "Z" then
		return colorPrefix.."|0|" ..(c:byte() - 65)
	elseif "0" <= c and c <= "9" then
		-- stupid order in i3d so put 0 to the end
		return colorPrefix.."|1|" ..((c:byte() - 48 + 9) % 10)
	elseif c == "#" then
		return "0|1|0|"..countryCode
	elseif c == "*" then
		return "0|1|2"
	end

	return nil
end

-- create a unique filename for each vehicle
function LicensePlates:getFilename()
	local modName, baseDir = Utils.getModNameAndBaseDirectory(self.configFileName)

	if modName then
		return modName.."/"..string.sub(self.configFileName, string.len(baseDir)-string.len(self.configFileName))
	end

	return self.configFileName
end

-- determines whether a vehicle has license plates
function LicensePlates.hasLicensePlates(vehicle)
	return vehicle and vehicle.spec_licensePlates and vehicle.spec_licensePlates.licensePlates
end

-- read the config xml
function LicensePlates.readConfig()
	local xmlFile = loadXMLFile("ConfigXML", Utils.getFilename(LicensePlates.CONFIGFILENAME, LicensePlates.DIRECTORY))

	local vehicles = LicensePlates.parseVehicles(xmlFile, "vehicles")

	delete(xmlFile)

	return vehicles
end

-- parse all default vehicles
function LicensePlates.parseVehicles(xmlFile, superKey)
	local vehicles = {}
	local i = 0

	while true do
		local key = superKey..string.format(".vehicle(%d)", i)
		if not hasXMLProperty(xmlFile, key) then
			break
		end

		local vehicle = LicensePlates.parseVehicle(xmlFile, key)

		if not vehicle.modname or g_modIsLoaded[vehicle.modname] then
			-- faster search by using file as key
			vehicles[vehicle.filename] = vehicle
		end
		-- else mod is not active, do not waste memory and ignore vehicle

		i = i + 1
	end

	return vehicles
end

-- parse a single vehicle including the license plates
function LicensePlates.parseVehicle(xmlFile, key)
	return {
		filename = getXMLString(xmlFile, key.."#filename"),
		defaultText = getXMLString(xmlFile, key.."#defaultText"),
		defaultSymbolColor = getXMLString(xmlFile, key.."#defaultSymbolColor"),
		defaultBackgroundColor = getXMLString(xmlFile, key.."#defaultBackgroundColor"),
		defaultCountryCode = getXMLString(xmlFile, key.."#defaultCountryCode"),
		parentFilename = getXMLString(xmlFile, key..".parent#filename"),
		licensePlates = LicensePlates.parseLicensePlates(xmlFile, key)
	}
end

-- parse all license plates for a vehicle
function LicensePlates.parseLicensePlates(xmlFile, superKey)
	local licensePlates = {}
	local i = 0

	while true do
		local key = superKey..string.format(".licensePlate(%d)", i)
		if not hasXMLProperty(xmlFile, key) then
			break
		end

		table.insert(licensePlates, LicensePlates.parseLicensePlate(xmlFile, key))

		i = i + 1
	end

	return licensePlates

end

-- parse a single license plate
function LicensePlates.parseLicensePlate(xmlFile, key)
	return {
		isSmall = getXMLBool(xmlFile, key.."#isSmall"),
		linkNode = getXMLString(xmlFile, key.."#linkNode"),
		rotation = StringUtil.getVectorNFromString(getXMLString(xmlFile, key.."#rotation") or "0 0 0", 3),
		translation = StringUtil.getVectorNFromString(getXMLString(xmlFile, key.."#translation") or "0 0 0", 3),
		hiddenNode = getXMLString(xmlFile, key.."#hiddenNode"),
	}
end

-- add license plates to all vehicles
function LicensePlates.addSpec()
	local specName = "licensePlates"
	for _, typeDef in pairs(g_vehicleTypeManager.vehicleTypes) do
		typeDef.specializationsByName[specName] = LicensePlates
		table.insert(typeDef.specializationNames, specName)
		table.insert(typeDef.specializations, LicensePlates)
	end
end

-- initialize mod
if g_currentModName == "FS19_LicensePlates" or g_currentModName == "FS19_LicensePlates_update" then
	LicensePlates.CONFIG = LicensePlates.readConfig()
	VehicleTypeManager.finalizeVehicleTypes = Utils.prependedFunction(VehicleTypeManager.finalizeVehicleTypes, LicensePlates.addSpec)
else
	LicensePlates = nil
	g_logManager:error("Mod 'LicensePlates' is an invalid version and was not loaded!")
	g_logManager:error("Please download this mod only from the official modhub!")
end
