---Specialization for placing license plates to vehicles












---Checks if all prerequisite specializations are loaded
-- @param table specializations specializations
-- @return boolean hasPrerequisite true if all prerequisite specializations are loaded
function LicensePlates1.prerequisitesPresent(specializations)
    return true
end


---
function LicensePlates1.initSpecialization()
    g_storeManager:addSpecType("licensePlate", "shopListAttributeIconLicensePlate", LicensePlates1.loadSpecValuePlateText, LicensePlates1.getSpecValuePlateText, "vehicle")

    local schema = Vehicle.xmlSchema
    schema:setXMLSpecializationType("LicensePlates1")

    schema:register(XMLValueType.STRING, "vehicle.LicensePlates1#defaultPlacement", "Defines the default placement index independent of map setting (NONE|BOTH|BACK_ONLY)", false)
    schema:register(XMLValueType.NODE_INDEX, "vehicle.LicensePlates1.licensePlate(?)#node", "License plate node")
    schema:register(XMLValueType.STRING, "vehicle.LicensePlates1.licensePlate(?)#preferedType", "Prefered license plate type to be placed if available")
    schema:register(XMLValueType.VECTOR_4, "vehicle.LicensePlates1.licensePlate(?)#placementArea", "Defines the available area around the node (top, right, bottom, left) ('-' means unlimited)")
    schema:register(XMLValueType.STRING, "vehicle.LicensePlates1.licensePlate(?)#position", "Position of license plate ('FRONT' or 'BACK')", "ANY")
    schema:register(XMLValueType.BOOL, "vehicle.LicensePlates1.licensePlate(?)#frame", "License plate with frame of without frame", true)

    ObjectChangeUtil.registerObjectChangeXMLPaths(schema, "vehicle.LicensePlates1.licensePlate(?)")

    schema:setXMLSpecializationType()

    local schemaSavegame = Vehicle.xmlSchemaSavegame
    schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).LicensePlates1#variation", "License plate variation", 1)
    schemaSavegame:register(XMLValueType.STRING, "vehicles.vehicle(?).LicensePlates1#characters", "Characters string")
    schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).LicensePlates1#colorIndex", "Selected color index", 1)
    schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).LicensePlates1#placementIndex", "Selected placement index", 1)
end


---
function LicensePlates1.registerFunctions(vehicleType)
    SpecializationUtil.registerFunction(vehicleType, "setLicensePlates1Data", LicensePlates1.setLicensePlates1Data)
    SpecializationUtil.registerFunction(vehicleType, "getLicensePlates1Data", LicensePlates1.getLicensePlates1Data)
    SpecializationUtil.registerFunction(vehicleType, "getLicensePlates1DataIsEqual", LicensePlates1.getLicensePlates1DataIsEqual)
    SpecializationUtil.registerFunction(vehicleType, "getHasLicensePlates1", LicensePlates1.getHasLicensePlates1)
    SpecializationUtil.registerFunction(vehicleType, "getLicensePlateDialogSettings", LicensePlates1.getLicensePlateDialogSettings)
end


---
function LicensePlates1.registerEventListeners(vehicleType)
    SpecializationUtil.registerEventListener(vehicleType, "onLoad", LicensePlates1)
    SpecializationUtil.registerEventListener(vehicleType, "onDelete", LicensePlates1)
    SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", LicensePlates1)
    SpecializationUtil.registerEventListener(vehicleType, "onReadStream", LicensePlates1)
    SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", LicensePlates1)
end


---Called on loading
-- @param table savegame savegame
function LicensePlates1:onLoad(savegame)
    local spec = self.spec_LicensePlates1

    spec.LicensePlates1 = {}
    local defaultPlacementName = self.xmlFile:getValue("vehicle.LicensePlates1#defaultPlacement")
    if defaultPlacementName ~= nil then
        spec.defaultPlacementIndex = LicensePlateManager.PLACEMENT_OPTION[defaultPlacementName:upper()]
    end

    if g_licensePlateManager:getAreLicensePlates1Available() then
        local i = 0
        while true do
            local plateKey = string.format("vehicle.LicensePlates1.licensePlate(%d)", i)
            if not self.xmlFile:hasProperty(plateKey) then
                break
            end

            local licensePlate = {}

            licensePlate.node = self.xmlFile:getValue(plateKey .. "#node", nil, self.components, self.i3dMappings)
            if licensePlate.node ~= nil then
                local preferedTypeStr = self.xmlFile:getValue(plateKey .. "#preferedType", "ELONGATED")
                licensePlate.preferedType = LicensePlateManager.PLATE_TYPE[preferedTypeStr]
                if licensePlate.preferedType ~= nil then
                    licensePlate.placementArea = {1, 1, 1, 1}
                    local placementAreaString = self.xmlFile:getString(plateKey .. "#placementArea")
                    if placementAreaString ~= nil then
                        local placementArea = string.split(placementAreaString, " ")
                        if #placementArea == 4 then
                            for j=1, 4 do
                                if placementArea[j] ~= "-" then
                                    local numberValue = tonumber(placementArea[j])
                                    if numberValue == nil then
                                        Logging.xmlWarning(self.xmlFile, "Invalid 4-vector '%s' for '%s'. '%s' is not a number!", placementAreaString, plateKey .. "#placementArea", placementArea[j])
                                    else
                                        licensePlate.placementArea[j] = numberValue
                                    end
                                end
                            end
                        else
                            Logging.xmlWarning(self.xmlFile, "Invalid 4-vector '%s' for '%s' ", placementAreaString, plateKey .. "#placementArea")
                        end
                    end

                    local positionStr = self.xmlFile:getValue(plateKey .. "#position", "ANY")
                    licensePlate.position = LicensePlateManager.PLATE_POSITION[positionStr] or LicensePlateManager.PLATE_POSITION.ANY

                    local includeFrame = self.xmlFile:getValue(plateKey .. "#frame", true)

                    licensePlate.data = g_licensePlateManager:getLicensePlate(licensePlate.preferedType, includeFrame)
                    if licensePlate.data ~= nil then
                        link(licensePlate.node, licensePlate.data.node)
                        setTranslation(licensePlate.data.node, 0, 0, 0)
                        setRotation(licensePlate.data.node, 0, 0, 0)
                        setVisibility(licensePlate.data.node, false)

                        local widthPos = licensePlate.data.rawWidth * 0.5 + licensePlate.data.widthOffsetLeft
                        local widthNeg = licensePlate.data.rawWidth * 0.5 + licensePlate.data.widthOffsetRight
                        local heightPos = licensePlate.data.rawHeight * 0.5 + licensePlate.data.heightOffsetTop
                        local heightNeg = licensePlate.data.rawHeight * 0.5 + licensePlate.data.heightOffsetBot

                        local scaleFactorWidth = (licensePlate.placementArea[2] + licensePlate.placementArea[4]) / (widthPos + widthNeg)
                        local scaleFactorHeight = (licensePlate.placementArea[1] + licensePlate.placementArea[3]) / (heightPos + heightNeg)
                        local minFactor = MathUtil.clamp(math.min(scaleFactorWidth, scaleFactorHeight), 0, 1)
                        if minFactor < 1 then
                            setScale(licensePlate.data.node, minFactor, minFactor, minFactor)

                            widthPos = widthPos * minFactor
                            widthNeg = widthNeg * minFactor
                            heightPos = heightPos * minFactor
                            heightNeg = heightNeg * minFactor
                        end

                        local moveX, moveY = 0, 0
                        moveX = moveX - math.max(widthPos - licensePlate.placementArea[2], 0)
                        moveX = moveX + math.max(widthNeg - licensePlate.placementArea[4], 0)
                        moveY = moveY - math.max(heightPos - licensePlate.placementArea[1], 0)
                        moveY = moveY + math.max(heightNeg - licensePlate.placementArea[3], 0)
                        setTranslation(licensePlate.data.node, moveX, moveY, 0)

                        licensePlate.changeObjects = {}
                        ObjectChangeUtil.loadObjectChangeFromXML(self.xmlFile, plateKey, licensePlate.changeObjects, self.components, self)

                        table.insert(spec.LicensePlates1, licensePlate)
                    end
                else
                    Logging.xmlError(self.xmlFile, "Unknown preferedType '%s' for license plate '%s'", preferedTypeStr, plateKey)
                end
            end

            i = i + 1
        end

        if self:getHasLicensePlates1() then
            spec.licensePlateData = {variation=1, characters=nil, colorIndex=nil}
        end
    end
end


---
function LicensePlates1:onPostLoad(savegame)
    local spec = self.spec_LicensePlates1
    if savegame ~= nil and not savegame.resetVehicles and self:getHasLicensePlates1() then
        local variation = savegame.xmlFile:getValue(savegame.key .. ".LicensePlates1#variation", 1)
        local characters = savegame.xmlFile:getValue(savegame.key .. ".LicensePlates1#characters")
        local colorIndex = savegame.xmlFile:getValue(savegame.key .. ".LicensePlates1#colorIndex", 1)
        local placementIndex = savegame.xmlFile:getValue(savegame.key .. ".LicensePlates1#placementIndex", 1)

        if variation ~= nil and characters ~= nil and colorIndex ~= nil and placementIndex ~= nil then
            local characterTbl = {}
            local characterLength = characters:len()
            for i=1, characterLength do
                table.insert(characterTbl, characters:sub(i, i))
            end

            spec.licensePlateData = {variation=variation, characters=characterTbl, colorIndex=colorIndex, placementIndex=placementIndex}
            self:setLicensePlates1Data(spec.licensePlateData)
        end
    end
end


---
function LicensePlates1:onDelete(savegame)
    local spec = self.spec_LicensePlates1

    spec.LicensePlates1 = {}
end


---
function LicensePlates1:saveToXMLFile(xmlFile, key, usedModNames)
    local spec = self.spec_LicensePlates1

    if self:getHasLicensePlates1() and spec.licensePlateData then
        if spec.licensePlateData.placementIndex ~= LicensePlateManager.PLACEMENT_OPTION.NONE then
            if spec.licensePlateData.variation ~= nil
            and spec.licensePlateData.characters ~= nil
            and spec.licensePlateData.colorIndex ~= nil then
                xmlFile:setValue(key .. "#variation", spec.licensePlateData.variation)
                xmlFile:setValue(key .. "#characters", table.concat(spec.licensePlateData.characters, ""))
                xmlFile:setValue(key .. "#colorIndex", spec.licensePlateData.colorIndex)
                xmlFile:setValue(key .. "#placementIndex", spec.licensePlateData.placementIndex)
            end
        end
    end
end


---Called on client side on join
-- @param integer streamId streamId
-- @param integer connection connection
function LicensePlates1:onReadStream(streamId, connection)
    local spec = self.spec_LicensePlates1
    spec.licensePlateData = LicensePlateManager.readLicensePlateData(streamId, connection)
    self:setLicensePlates1Data(spec.licensePlateData)
end


---Called on server side on join
-- @param integer streamId streamId
-- @param integer connection connection
function LicensePlates1:onWriteStream(streamId, connection)
    local spec = self.spec_LicensePlates1
    LicensePlateManager.writeLicensePlateData(streamId, connection, spec.licensePlateData)
end


---
function LicensePlates1:setLicensePlates1Data(licensePlateData)
    local spec = self.spec_LicensePlates1
    if licensePlateData ~= nil and licensePlateData.variation ~= nil and licensePlateData.characters ~= nil and licensePlateData.colorIndex ~= nil and licensePlateData.placementIndex ~= nil then
        for i=1, #spec.LicensePlates1 do
            local licensePlate = spec.LicensePlates1[i]

            local allowLicensePlate = true
            if licensePlateData.placementIndex == LicensePlateManager.PLACEMENT_OPTION.NONE then
                allowLicensePlate = false
            elseif licensePlateData.placementIndex == LicensePlateManager.PLACEMENT_OPTION.BACK_ONLY then
                if licensePlate.position == LicensePlateManager.PLATE_POSITION.FRONT then
                    allowLicensePlate = false
                end
            end

            if allowLicensePlate then
                licensePlate.data:updateData(licensePlateData.variation, licensePlate.position, table.concat(licensePlateData.characters, ""), true)
                licensePlate.data:setColorIndex(licensePlateData.colorIndex)

                setVisibility(licensePlate.data.node, true)
            else
                setVisibility(licensePlate.data.node, false)
            end

            ObjectChangeUtil.setObjectChanges(licensePlate.changeObjects, allowLicensePlate, self, self.setMovingToolDirty)
        end

        spec.licensePlateData = licensePlateData
    else
        for i=1, #spec.LicensePlates1 do
            setVisibility(spec.LicensePlates1[i].data.node, false)
        end
    end
end


---
function LicensePlates1:getLicensePlates1Data()
    return self.spec_LicensePlates1.licensePlateData
end


---
function LicensePlates1:getLicensePlates1DataIsEqual(data)
    if data == nil or self.spec_LicensePlates1.licensePlateData == nil then
        return true
    end

    local ownData = self.spec_LicensePlates1.licensePlateData

    if data.variation ~= ownData.variation or data.colorIndex ~= ownData.colorIndex or data.placementIndex ~= ownData.placementIndex then
        return false
    end

    if data.characters ~= nil and ownData.characters ~= nil then
        if #data.characters ~= #ownData.characters then
            return false
        end

        for i=1, #data.characters do
            if data.characters[i] ~= ownData.characters[i] then
                return false
            end
        end
    end

    return true
end


---Returns if vehicle has license plates
-- @return boolean hasLicensePlates1 has license plates
function LicensePlates1:getHasLicensePlates1()
    return #self.spec_LicensePlates1.LicensePlates1 > 0
end


---Returns license plate settings for dialog
-- @return string defaultPlacementIndex default placement
-- @return boolean hasFrontPlate has front license plate
function LicensePlates1:getLicensePlateDialogSettings()
    local spec = self.spec_LicensePlates1
    local hasFrontPlate = false
    for i=1, #spec.LicensePlates1 do
        local licensePlate = spec.LicensePlates1[i]
        if licensePlate.position == LicensePlateManager.PLATE_POSITION.FRONT then
            hasFrontPlate = true
            break
        end
    end

    return spec.defaultPlacementIndex, hasFrontPlate
end


---
function LicensePlates1.loadSpecValuePlateText(xmlFile, customEnvironment, baseDir)
    -- No data to load as this spec is only for existing items
    return nil
end


---
function LicensePlates1.getSpecValuePlateText(storeItem, realItem)
    if realItem == nil then
        return nil
    end

    if realItem.getHasLicensePlates1 == nil or not realItem:getHasLicensePlates1() then
        return nil
    end

    local spec = realItem.spec_LicensePlates1
    for i=1, #spec.LicensePlates1 do
        local licensePlate = spec.LicensePlates1[i]
        if licensePlate.position == LicensePlateManager.PLATE_POSITION.BACK or i == #spec.LicensePlates1 then
            return licensePlate.data:getFormattedString()
        end
    end

    return nil
end
