--[[
AddConfig

Specialization for extended configurations and register new configurations.

Author:		Ifko[nator]
Datum:		04.07.2018

Version:	v3.4

History:	v1.0 @ 28.02.2017 - initial implementation - added possibility to change capacity via configuration
			-------------------------------------------------------------------------------------------------------------------------------------------------------------
			v2.0 @ 25.03.2017 - added possibility to change rim and axis color via configuration
			-------------------------------------------------------------------------------------------------------------------------------------------------------------
			v3.0 @ 21.07.2017 - added possibility to change fillable fill types and cutable fruit types via configuration
			-------------------------------------------------------------------------------------------------------------------------------------------------------------
			v3.1 @ 13.12.2017 - a little bit code optimation
			-------------------------------------------------------------------------------------------------------------------------------------------------------------
			v3.2 @ 31.12.2017 - increased the limit from 64 to 134.217.728 configurations, i hope thats enough now!
			-------------------------------------------------------------------------------------------------------------------------------------------------------------
			v3.3 @ 04.03.2018 - the capacity value from the fillUnit in the xml file will now set to the new capacity to avoid fill the fill volume too fast or too slow
			-------------------------------------------------------------------------------------------------------------------------------------------------------------
			V3.4 @ 04.07.2018 - added possibility to change the mass and possiblity to deactivate the fillable Spezi of an vehicle via configuration
]]

AddConfig = {};

AddConfig.currentModDirectory = g_currentModDirectory;
AddConfig.debugPriority = 0;

local function printError(errorMessage, isWarning, isInfo)
	local prefix = "::ERROR:: ";
	
	if isWarning then
		prefix = "::WARNING:: ";
	elseif isInfo then
		prefix = "::INFO:: ";
	end;
	
	print(prefix .. "from the AddConfig.lua: " .. tostring(errorMessage));
end;

local function printDebug(debugMessage, priority, addString)
	if AddConfig.debugPriority >= priority then
		local prefix = "";
		
		if addString then
			prefix = "::DEBUG:: from the AddConfig.lua: ";
		end;
		
		print(prefix .. tostring(debugMessage));
	end;
end;

if ConfigurationUtil.sendNumBits < 27 then	
	ConfigurationUtil.sendNumBits = 27; --## = 134.217.728 possible configurations! I think, thats enough (2^27 = 134.217.728)!
	
	printError("Set max number of configurations to ".. g_i18n:formatNumber(2^ConfigurationUtil.sendNumBits), false, true);
end;

function AddConfig.prerequisitesPresent(specializations)
    return true;
end

function AddConfig:load(savegame)
	self.applyCustomDesing = Utils.overwrittenFunction(self.applyDesign, AddConfig.applyCustomDesing);
	
	local modDesc = loadXMLFile("modDesc", AddConfig.currentModDirectory .. "modDesc.xml");
	
	AddConfig.debugPriority = Utils.getNoNil(getXMLFloat(modDesc, "vehicle.newConfigurations#debugPriority"), AddConfig.debugPriority);
	
	local configNumber = 0;
	
	while true do
		local configKey = "modDesc.newConfigurations.newConfiguration(" .. tostring(configNumber) .. ")";
		
		if not hasXMLProperty(modDesc, configKey) then
			break;
		end;
		
		local isColorConfig = Utils.getNoNil(getXMLBool(modDesc, configKey .. "#isColorConfig"), false);
		local configName = Utils.getNoNil(getXMLString(modDesc, configKey .. "#configName"), "");
		
		if configName ~= "" then
			if self.configurations[configName] ~= nil then	
				printDebug("Found configuration '" .. configName .. "' in vehicle '" .. self.configFileName .. "'.", 1, true);
				
				if isColorConfig then
					self:setColor(self.xmlFile, configName, self.configurations[configName]); --## config to change color on vehicle
					
					printDebug("Set color on vehichle '" .. self.configFileName .. "'.", 1, true);
				else
					self:applyCustomDesing(self.xmlFile, self.configurations[configName], configName); --## config to change texture on vehicle
					
					printDebug("Apply custom desing on vehichle '" .. self.configFileName .. "'.", 1, true);
				end;
			end;
		else
			printError("Missing the name for the new configuration in '" .. configKey .. "'! Stopping adding this config now!", false, false);
		end;
	
		configNumber = configNumber + 1;
	end;
	
	delete(modDesc);
end;

function AddConfig:preLoad(savegame)
	local modDesc = loadXMLFile("modDesc", AddConfig.currentModDirectory .. "modDesc.xml");
	local configNumber = 0;
	
	while true do
		local configKey = "modDesc.newConfigurations.newConfiguration(" .. tostring(configNumber) .. ")";
		
		if not hasXMLProperty(modDesc, configKey) then
			break;
		end;
		
		local configName = Utils.getNoNil(getXMLString(modDesc, configKey .. "#configName"), "");
		
		if configName ~= "" then
			if self.configurations[configName] ~= nil then	
				local configKey = string.format("vehicle." .. configName .. "Configurations." .. configName .. "Configuration(%d)", self.configurations[configName] - 1);
				local newCapacity = getXMLFloat(self.xmlFile, configKey .. "#capacity");
				local isFillable = Utils.getNoNil(getXMLBool(self.xmlFile, configKey .. "#isFillable"), true);
				local fillUnitIndex = getXMLString(self.xmlFile, configKey .. "#fillUnitIndex");
				local fillSoundFile = getXMLString(self.xmlFile, configKey .. "#fillSoundFile");
				
				if fillUnitIndex ~= nil then
					--## TO DO: Check if this will correctly work!
					
					local fillUnitIndexes = Utils.splitString(" ", fillUnitIndex);
					local volumeIndexes = Utils.splitString(" ", Utils.getNoNil(getXMLString(self.xmlFile, configKey .. "#volumeIndex"), "0"));
				
					if #fillUnitIndexes == #volumeIndexes then
						for _, volumeIndex in pairs(volumeIndexes) do
							for _, fillUnitIndex in pairs(fillUnitIndexes) do
								if hasXMLProperty(self.xmlFile, "vehicle.fillVolumes.volumes.volume(" .. volumeIndex .. ")") then	
									setXMLString(self.xmlFile, "vehicle.fillVolumes.volumes.volume(" .. volumeIndex .. ")#index", fillUnitIndex);
								else
									break;
								end;
							end;
						end;
					else
						printError('Found "' .. #fillUnitIndexes .. '" fillUnitIndexes and "' .. #volumeIndexes .. '" volumeIndexes! They must have the same count! The fill volume was not changed for this vehicle!', false, false);
					end;
				end;
				
				if newCapacity ~= nil then
					if newCapacity > 0 then	
						local fillUnitCount = 0;
						
						while true do
							local fillUnitKey = "vehicle.fillUnits.fillUnit(" .. tostring(fillUnitCount) .. ")";
							
							if not hasXMLProperty(self.xmlFile, fillUnitKey) then
								break;
							end;
							
							fillUnitCount = fillUnitCount + 1;
						end;
						
						for fillUnit = 1, fillUnitCount do
							setXMLFloat(self.xmlFile, "vehicle.fillUnits.fillUnit(" .. fillUnit - 1 .. ")#capacity", newCapacity/fillUnitCount);
						end;
					else
						printError('The value from capacity must be greater as 0! To deactivate the fillable for this vehicle, use isFillable="false" instead! The capacity was not changed for this vehicle!', false, false);
					end;
				end;
				
				if not isFillable then
					setXMLBool(self.xmlFile, "vehicle.allowFillFromAir#value", false);
				end;
				
				if fillSoundFile ~= nil then
					setXMLString(self.xmlFile, "vehicle.fillSound#file", fillSoundFile);
				end;
			end;
		end;
	
		configNumber = configNumber + 1;
	end;
	
	delete(modDesc);
end;

function AddConfig:applyCustomDesing(oldFunc, xmlFile, configId, configName)
    local configKey = string.format("vehicle." .. configName .. "Configurations." .. configName .. "Configuration(%d)", configId - 1);
    
    if not hasXMLProperty(xmlFile, configKey) then
        printError("Invalid '" .. configName .. "s' configuration (" .. configId .. ")", true, false);
        
	    return;
    end;
	
    --## change cutable fruit types
	
    local fruitTypes = {};
    local newFruitTypeCategories = getXMLString(self.xmlFile, configKey .. "#fruitTypeCategories");
    local newFruitTypeNames = getXMLString(self.xmlFile, configKey .. "#fruitTypes");
    local hasDeletedFruitTypes = false;
	
    if newFruitTypeCategories ~= nil and newFruitTypeNames == nil then
        fruitTypes = FruitUtil.getFruitTypeByCategoryName(newFruitTypeCategories);
    elseif newFruitTypeCategories == nil and newFruitTypeNames ~= nil then
        fruitTypes = FruitUtil.getFruitTypesByNames(newFruitTypeNames);
    end;

    if fruitTypes ~= nil then
	    for _, fruitType in pairs(fruitTypes) do
		    if not hasDeletedFruitTypes then
			    --## delete current cutable fruit types
				
				self.fruitTypes = {};
				
			    hasDeletedFruitTypes = true;
			end;

			local fruitTypeCheck = FillUtil.fillTypeIntToName[fruitType];

			if fruitTypeCheck ~= nil then	
				--## insert new cutable fruit types
				
				self.fruitTypes[fruitType] = true;
				
				printDebug("Insert fruit type '" .. fruitTypeCheck .. "' successfully to '" .. self.configFileName .. "'.", 1, true);
			end;
        end;
    end;
	
	--## change fillable fill types
	
	local fillTypes = {};
	local newFillTypeCategories = getXMLString(xmlFile, configKey .. "#fillTypeCategories");
	local newFillTypeNames = getXMLString(xmlFile, configKey .. "#fillTypes");
	local hasDeletedFillTypes = false;
	
	if newFillTypeCategories ~= nil and newFillTypeNames == nil then
		fillTypes = FillUtil.getFillTypeByCategoryName(newFillTypeCategories);
	elseif newFillTypeCategories == nil and newFillTypeNames ~= nil then
		fillTypes = FillUtil.getFillTypesByNames(newFillTypeNames);
	end;
	
	if fillTypes ~= nil then
		for _, fillType in pairs(fillTypes) do
			for _, fillUnit in pairs(self.fillUnits) do
				if not hasDeletedFillTypes then
					--## delete current fillable fill types
					
					fillUnit.fillTypes = {};
					
					hasDeletedFillTypes = true;
				end;
				
				local fillTypeCheck = FillUtil.fillTypeIntToName[fillType];
				
				if fillTypeCheck ~= nil then
					--## insert new fillable fill types
					
					fillUnit.fillTypes[fillType] = true;
					
					printDebug("Insert fill type '" .. fillTypeCheck .. "' successfully to '" .. self.configFileName .. "'.", 1, true);
				end;
			end;
		end;
	end;
	
	--## disable fill level hud if vehicle is not fillable
	
	local isFillable = Utils.getNoNil(getXMLBool(xmlFile, configKey .. "#isFillable"), true);
	
	if not isFillable then
		for _, fillUnit in pairs(self.fillUnits) do
			fillUnit.showOnHud = showFillLevelOnHud;
			fillUnit.fillTypes = {};
			
			printDebug("Decativated fillable successfully in '" .. self.configFileName .. "'.", 1, true);
		end;
	end;
	
	--## change mass
    
	local newMass = getXMLFloat(xmlFile, configKey .. "#mass");
	
	if newMass ~= nil then
		setMass(self.rootNode, getMass(self.rootNode) + newMass);

		printDebug("Change mass to: " .. getMass(self.rootNode) .. "' (old mass " .. getMass(self.rootNode) - newMass  .. ") successfully in '" .. self.configFileName .. "'.", 1, true);
	end;
	
	--## change rim and axis color
	
	local axisColor = getXMLString(xmlFile, configKey .. "#axisColor");
	local rimColor = getXMLString(xmlFile, configKey .. "#rimColor");
    
	for _, wheel in pairs(self.wheels) do
		if axisColor ~= nil then
			self.axisColor = Vehicle.getColorFromString(axisColor);
			
			if wheel.wheelHub ~= nil then
				local r, g, b, a = unpack(self.axisColor);
            
				setShaderParameter(wheel.wheelHub, "colorScale", r, g, b, a, false);
			
				printDebug("Change axis color to: " .. axisColor .. "' successfully in '" .. self.configFileName .. "'.", 1, true);
			end;
		end;
		
		if rimColor ~= nil then
			self.rimColor = Vehicle.getColorFromString(rimColor);
			
			local r, g, b, a = unpack(self.rimColor);
        
			if wheel.wheelOuterRim ~= nil then
				setShaderParameter(wheel.wheelOuterRim, "colorScale", r, g, b, a, false);
			
				printDebug("Change outer rim color to: " .. rimColor .. "' successfully in '" .. self.configFileName .. "'.", 1, true);
			end;
			
			if wheel.wheelInnerRim ~= nil then
				setShaderParameter(wheel.wheelInnerRim, "colorScale", r, g, b, a, false);
			
				printDebug("Change inner rim color to: " .. rimColor .. "' successfully in '" .. self.configFileName .. "'.", 1, true);
			end;
		end;
	end;
	
	--## change material
    
	local i = 0;
    
	while true do
        local materialKey = string.format(configKey .. ".material(%d)", i);
        
		if not hasXMLProperty(xmlFile, materialKey) then
            break;
        end;
        
		local baseMaterialNode = Utils.indexToObject(self.components, getXMLString(xmlFile, materialKey.."#node"));
        local refMaterialNode = Utils.indexToObject(self.components, getXMLString(xmlFile, materialKey.."#refNode"));
        
		if baseMaterialNode ~= nil and refMaterialNode ~= nil then
            local oldMaterial = getMaterial(baseMaterialNode, 0);
            local newMaterial = getMaterial(refMaterialNode, 0);
            
			for _, component in pairs(self.components) do
                self:replaceMaterialRec(component.node, oldMaterial, newMaterial);
				
				printDebug("Change material successfully in '" .. self.configFileName .. "'.", 1, true);
            end;
        end;
        
		i = i + 1;
    end;
    
	ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle." .. configName .. "Configurations." .. configName .. "Configuration", configId, self.components, self);
end;

function AddConfig:delete()end;
function AddConfig:mouseEvent(posX, posY, isDown, isUp, button)end;
function AddConfig:keyEvent(unicode, sym, modifier, isDown)end;
function AddConfig:update(dt)end;
function AddConfig:draw()end;

local modDesc = loadXMLFile("modDesc", AddConfig.currentModDirectory .. "modDesc.xml");
local configNumber = 0;
	
while true do
	local configKey = "modDesc.newConfigurations.newConfiguration(" .. tostring(configNumber) .. ")";
	
	if not hasXMLProperty(modDesc, configKey) then
		break;
	end;
	
	local isColorConfig = Utils.getNoNil(getXMLBool(modDesc, configKey .. "#isColorConfig"), false);
	local configName = Utils.getNoNil(getXMLString(modDesc, configKey .. "#configName"), "");
	
	if configName ~= "" then
		if ConfigurationUtil.configurations[configName] == nil then
			if isColorConfig then
				ConfigurationUtil.registerConfigurationType(configName, g_i18n:getText("configuration_" .. configName), nil, Vehicle.getConfigColorSingleItemLoad, Vehicle.getConfigColorPostLoad, ConfigurationUtil.SELECTOR_COLOR); --## config to change color on vehicle
				
				printDebug("Register color configuration '" .. configName .."' successfully.", 1, true);
			else
				ConfigurationUtil.registerConfigurationType(configName, g_i18n:getText("configuration_" .. configName), nil, nil, nil, ConfigurationUtil.SELECTOR_MULTIOPTION); --## config to change parts on vehicle
				
				printDebug("Register desing configuration '" .. configName .."' successfully.", 1, true);
			end;
		end;
	else
		printError("Missing the name for the new Config in '" .. configKey .. "'! Stopping register this config now!", false, false);
	end;

	configNumber = configNumber + 1;
end;