-- @Author: DangYu 
-- @Date: 2020-07-05 17:37:31

local Config = Config or class("MakeFaceConfig");

local Lib = ImportScript("ugc_common/script/base/lib.lua")

local FACE_BONE_RANGE_DIR = "ugc_common\\settings\\character\\schem\\face\\bone\\Bone_"
local FACE_BONE_RANGE_SUFFIX = ".tab"
local FACE_BONE_PATH = "ugc_common\\settings\\character\\schem\\face\\FaceBones.tab"
local FACE_DECAL_PATH = "ugc_common\\settings\\character\\schem\\face\\FaceDecals.tab"
local FACE_DECAL_LIST = "ugc_common\\settings\\character\\schem\\face\\Decal.tab"
local FACE_DEFAULT_PATH = "ugc_common\\settings\\character\\schem\\face\\FaceDefault.tab"

local FACE_LIFT_DECAL_TYPE = Lib.CreateEnumTable({
    "BASE",
    "IRIS_LEFT",
    "IRIS_RIGHT",
    "EYE_SHADOW",
    "EYE_LINE",
    "BROW",
    "BLUSHER_MOUSTACHE",
    "LIP_GLOSS",
    "EYE_LIGHT",
    "DECAL",
    "TOTAL",
})

local FACE_LIFT_CUSTOM_DECAL_TYPE = Lib.CreateEnumTable(
{
	"SKINCOLOR",		--肤色
	"SKINGLOSS",		--光泽度
	"SKINGRAININESS",	--颗粒度
	"TOTAL",
})

local FACE_DECAL_NAME =
{
    [FACE_LIFT_DECAL_TYPE.BASE]              = "面部皮肤",
    [FACE_LIFT_DECAL_TYPE.IRIS_LEFT]         = "眼瞳",
    [FACE_LIFT_DECAL_TYPE.IRIS_RIGHT]        = "右瞳",
    [FACE_LIFT_DECAL_TYPE.EYE_SHADOW]        = "眼影",
    [FACE_LIFT_DECAL_TYPE.EYE_LINE]          = "眼线",
    [FACE_LIFT_DECAL_TYPE.BROW]              = "眉毛",
    [FACE_LIFT_DECAL_TYPE.BLUSHER_MOUSTACHE] = "腮红和胡须",
    [FACE_LIFT_DECAL_TYPE.LIP_GLOSS]         = "唇形",
    [FACE_LIFT_DECAL_TYPE.EYE_LIGHT]         = "眼神光",
    [FACE_LIFT_DECAL_TYPE.DECAL]             = "贴花",
}

local FACE_BONE_NAME_INI = {
    "cheekY",		--颧骨位置
	"cheekZ",		--颧骨凹凸
	"faceY",		--脸蛋上下
	"faceZ",		--脸蛋前后
	"upFace",		--上脸宽窄
	"lowFace",		--下脸宽窄
	"faceScale",	--脸蛋丰满
	"jawWidth",		--下巴宽窄
	"jawPos",		--下巴位置
	"jawLength",	--下巴长短
	"jawEnd",		--下巴尖宽
	"jawRot",		--下巴翘起
	"noseSize",		--鼻子大小
	"noseHeight",	--鼻子高度
	"nosetopPosZ",	--鼻头位置1
	"nosetopPosY",	--鼻头位置2
	"nosetopWidth",	--鼻头宽度
	"nosetopUp",	--鼻头俯仰
	"nosebowWidth",	--鼻梁宽度
	"nosebowBend",	--鼻梁弯度
	"mouthPos",		--嘴巴位置
	"mouthSize",	--嘴巴大小
	"mouthRot",		--嘴巴倾斜
	"mouthOpen",	--嘴巴开合
	"mouthOut",		--嘴巴凹凸
	"mouthEnd",		--嘴角上下
	"upLip",		--上唇厚度
	"lowLip",		--下唇厚度
	"upLipOut",		--上唇突出
	"lowLipOut",	--下唇突出
	"upLipPos",		--上唇位置
	"lowLipPos",	--下唇位置
	"mouthEndL",	--嘴角前后1
	"mouthEndR",	--嘴角前后2
	"out",			--眼睛外突
	"eyePos",		--眼睛位置
	"eyeSize",		--眼睛大小
	"eyeDirc",		--眼睛斜度
	"eyeDist",		--眼睛间距
	"eyeOpen",		--眼睛开合
	"eyebowOut",	--眉骨凹凸
	"eyebowDirc",	--眉毛斜度
	"eyebowPos",	--眉毛高度
	"pupilSize",	--瞳孔大小
	"pupilDirc",	--瞳孔朝向
	"upLidPos",		--眼皮高度
	"lowLidPos",	--眼睑高度
	"eyecrowY",		--眼角高度
	"ridgeY",		--泪腺高度
	"eyeSideL",		--左眼斜视
	"eyeSideR",		--右眼斜视
}

local FACE_DECAL_NAME_INI = {
    "FaceBaseTexture",  --面部皮肤
	"IrisLeft",         --眼瞳
	"IrisRight",        --右瞳
	"EyeShadow",        --眼影
	"EyeLine",          --眼线
	"Brow",             --眉毛
	"BlusherMoustache", --腮红和胡须
	"LipGloss",         --唇形
	"EyeLight",         --眼神光
	"Decal",            --贴花
}

local FACE_CUSTOM_DECAL_RANGE = {
    {
        RoleType=1,
        SKINCOLOR = {MAX=30,MIN=0},
        SKINGLOSS = {MAX=190,MIN=0},
        SKINGRAININESS = {MAX=200,MIN=0}
    },
    {
        RoleType=2,
        SKINCOLOR = {MAX=70,MIN=0},
        SKINGLOSS = {MAX=120,MIN=0},
        SKINGRAININESS = {MAX=200,MIN=0}
    },
    {
        RoleType=5,
        SKINCOLOR = {MAX=70,MIN=0},
        SKINGLOSS = {MAX=120,MIN=0},
        SKINGRAININESS = {MAX=200,MIN=0}
    },
    {
        RoleType=6,
        SKINCOLOR = {MAX=70,MIN=0},
        SKINGLOSS = {MAX=120,MIN=0},
        SKINGRAININESS = {MAX=200,MIN=0}
    }
}

function Config:ctor()
end

function Config:dtor()
    --
end

---@return string RoleType
---@param  nRoleTypr number 
function Config:GetStringRoleType(nRoleType)
    local szRoleType = ""
    if nRoleType == 1 then
        szRoleType = "m2"
    end
    if nRoleType == 2 then
        szRoleType = "f2"
    end
    if nRoleType == 5 then
        szRoleType = "m1"
    end
    if nRoleType == 6 then
        szRoleType = "f1"
    end
    return szRoleType
end

-- Bone
---@return number
function Config:GetFaceBoneFileRowCount()
    local tabFile = LTabFile:new(FACE_BONE_PATH);
    local nRowCount = tabFile:GetRowCount()
    return nRowCount
end

---@return table 
function Config:GetAllFaceBoneClassName()
    local tabFile = LTabFile:new(FACE_BONE_PATH);
    local nRowCount = tabFile:GetRowCount()
    local nColClassNameIndex = tabFile:GetColIdxByName("ClassName")
    local nColClassIDIndex = tabFile:GetColIdxByName("ClassID")
    local szClassName = ""
    local nCurClassID = -1
    local FaceBoneClassList = {}

    for i=1,nRowCount do
        szClassName = tabFile:GetString(i,nColClassNameIndex,"")
        nCurClassID = tabFile:GetNumber(i,nColClassIDIndex,-1)
        if szClassName ~= nil and szClassName ~= "" and nCurClassID ~= 0 then
            szClassName = util.a2u8(szClassName)
            FaceBoneClassList[nCurClassID] = szClassName
        end
    end

    return FaceBoneClassList
end

---@return --two_dimensional table
function Config:GetAllFaceBoneName()
    local tabFile = LTabFile:new(FACE_BONE_PATH);
    local nRowCount = tabFile:GetRowCount()
    local nColClassIDIndex = tabFile:GetColIdxByName("ClassID")
    local nColBoneNameIndex = tabFile:GetColIdxByName("BoneName")
    local nColBoneTypeIndex = tabFile:GetColIdxByName("BoneType")
    local nColIDIndex = tabFile:GetColIdxByName("ID")
    local nCurClassID = nil
    local tbBoneName = {}
    local szBoneName = ""
    local nCurBoneType = 0
    local nCurID = 0

    for i=1,nRowCount do
        nCurClassID = tabFile:GetNumber(i,nColClassIDIndex,-1)
        if nCurClassID ~= -1 and nCurClassID ~= 0 then
            if not tbBoneName[nCurClassID] then
                tbBoneName[nCurClassID] = {}
            end
            szBoneName = tabFile:GetString(i,nColBoneNameIndex,"")
            nCurBoneType = tabFile:GetNumber(i,nColBoneTypeIndex,0)
            nCurID = tabFile:GetNumber(i,nColIDIndex,0)
            local tbBoneDetail = {}
            tbBoneDetail.BoneName = util.a2u8(szBoneName)
            tbBoneDetail.BoneType = nCurBoneType
            tbBoneDetail.ID = nCurID
            table.insert( tbBoneName[nCurClassID], tbBoneDetail )
        end
    end

    return tbBoneName
end

---@param _ClassID number
---@return table
function Config:GetFaceBoneClassNameFromClassID(_ClassID)
    local tabFile = LTabFile:new(FACE_BONE_PATH)
    local nRowCount = tabFile:GetRowCount()
    local nColClassNameIndex = tabFile:GetColIdxByName("ClassName")
    local nColClassIDIndex = tabFile:GetColIdxByName("ClassID")
    local nCurClassName = ""
    local nCurClassID = -1

    for i=1,nRowCount do
        nCurClassName = tabFile:GetString(i,nColClassNameIndex,"")
        if nCurClassName~="" then
            nCurClassID = tabFile:GetNumber(i,nColClassIDIndex,-1)
            if nCurClassID == _ClassID then
                return nCurClassName
            end
        end
    end
    return -1
end

---@param _ID number
--- return string (single BoneName)
function Config:GetFaceBoneNameFromID(_ID)
    local tabFile = LTabFile:new(FACE_BONE_PATH)
    local nRowCount = tabFile:GetRowCount()
    local nColIDIndex = tabFile:GetColIdxByName("ID")
    local nColBoneNameIndex = tabFile:GetColIdxByName("BoneName")
    local nCurID = -1
    local nCurBoneName = ""

    for  i=1,nRowCount do
        nCurID = tabFile:GetNumber(i,nColIDIndex,-1)
        if nCurID == _ID then
            nCurBoneName = tabFile:GetString(i,nColBoneNameIndex,"")
            if nCurBoneName ~= "" then
                return nCurBoneName
            end
        end
    end

    return ""
end

---@param _ClassID number
---@return table
function Config:GetFaceBoneTypeFromClassID(_ClassID)
    local tabFile = LTabFile:new(FACE_BONE_PATH)
    local nRowCount = tabFile:GetRowCount()
    local nColClassIDIndex = tabFile:GetColIdxByName("ClassID")
    local nColBoneTypeIndex = tabFile:GetColIdxByName("BoneType")
    local nCurClassID = -1
    local nCurBoneType = -1
    local tbBoneType = {}

    for i=1,nRowCount do
        nCurClassID = tabFile:GetNumber(i,nColClassIDIndex,-1)
        if nCurClassID == _ClassID then
            nCurBoneType = tabFile:GetNumber(i,nColBoneTypeIndex,-1)
            table.insert( tbBoneType, nCurBoneType)
        end
    end

    return tbBoneType
end

function Config:GetEyeBoneType()
    return self:GetFaceBoneTypeFromClassID(4)
end

function Config:GetMouthBoneType()
    return self:GetFaceBoneTypeFromClassID(3)
end

function Config:GetNoseBoneType()
    return self:GetFaceBoneTypeFromClassID(2)
end

function Config:GetFaceBoneType()
    return self:GetFaceBoneTypeFromClassID(1)
end

---@param _ClassID number
--- return table (BoneName of the same class)
function Config:GetFaceBoneNameFromClassID(_ClassID)
    local tabFile = LTabFile:new(FACE_BONE_PATH)
    local nRowCount = tabFile:GetRowCount()
    local nColClassIDIndex = tabFile:GetColIdxByName("ClassID")
    local nColBoneNameIndex = tabFile:GetColIdxByName("BoneName")
    local nCurClassID = -1
    local nCurBoneName = ""
    local tbBoneName = {}

    for i=1,nRowCount do
        nCurClassID = tabFile:GetNumber(i,nColClassIDIndex,-1)
        if nCurClassID == _ClassID then
            nCurBoneName = tabFile:GetString(i,nColBoneNameIndex,"")
            table.insert( tbBoneName,nCurBoneName)
        end
    end

    return tbBoneName
end

function Config:GetEyeBoneName()
    return self:GetFaceBoneNameFromClassID(4)
end

function Config:GetMouthBoneName()
    return self:GetFaceBoneNameFromClassID(3)
end

function Config:GetNoseBoneName()
    return self:GetFaceBoneNameFromClassID(2)
end

function Config:GetFaceBoneName()
    return self:GetFaceBoneNameFromClassID(1)
end

---@return two_dimensional_table (Get the range of all sliders)
function Config:GetFaceBoneDetailRanges()
    local tbFaceBoneRanges = {}
    local szRoleType = ""
    local tbFaceBoneRange = {}

    szRoleType = "m2"
    tbFaceBoneRange = self:GetFaceBoneDetailRange(szRoleType)
    tbFaceBoneRanges[1] = tbFaceBoneRange

    szRoleType = "f2"
    tbFaceBoneRange = self:GetFaceBoneDetailRange(szRoleType)
    tbFaceBoneRanges[2] = tbFaceBoneRange

    szRoleType = "m1"
    tbFaceBoneRange = self:GetFaceBoneDetailRange(szRoleType)
    tbFaceBoneRanges[5] = tbFaceBoneRange


    szRoleType = "f1"
    tbFaceBoneRange = self:GetFaceBoneDetailRange(szRoleType)
    tbFaceBoneRanges[6] = tbFaceBoneRange

    return tbFaceBoneRanges
end

function Config:GetFaceBoneDetailRange(szRoleType)
    local m_szFaceBoneRangePath = FACE_BONE_RANGE_DIR..szRoleType..FACE_BONE_RANGE_SUFFIX
    local tabFile = LTabFile:new(m_szFaceBoneRangePath)
    local nRowCount = tabFile:GetRowCount()
    local nColType = tabFile:GetColIdxByName("Type")
    local nColValueMax = tabFile:GetColIdxByName("ValueMax")
    local nColValueMin = tabFile:GetColIdxByName("ValueMin")
    local tbFaceBoneRange = {}
    local nCurType = -1
    local nCurValMax = -1
    local nCurValMin = -1

    for i=1,nRowCount do
        nCurType = tabFile:GetNumber(i,nColType,-1)
        nCurValMax = tabFile:GetNumber(i,nColValueMax,-1)
        nCurValMin = tabFile:GetNumber(i,nColValueMin,-1)
        tbFaceBoneRange[nCurType] = {}
        tbFaceBoneRange[nCurType].ValueMin = nCurValMin
        tbFaceBoneRange[nCurType].ValueMax = nCurValMax
    end
    return tbFaceBoneRange
end

-- Decal
function Config:GetAllFaceDecalClassName()
    return FACE_DECAL_NAME
end

function Config:GetDecalList()
    local tabFile = LTabFile:new(FACE_DECAL_LIST)
    local nRowCount = tabFile:GetRowCount()
    local tbDecalList = {}
    local nColRoleType = tabFile:GetColIdxByName("RoleType")
    local nColType = tabFile:GetColIdxByName("Type")
    local nColShowID = tabFile:GetColIdxByName("ShowID")
    local nColCanUse = tabFile:GetColIdxByName("CanUseInCreate")

    local nCurRoleType = -1
    local nCurType = -1
    local nCurShowID = -1
    local nCanUse = 0

    for i=1,nRowCount do
        nCurRoleType = tabFile:GetNumber(i,nColRoleType,-1)
        nCanUse = tabFile:GetNumber(i,nColCanUse,0)
        nCurType = tabFile:GetNumber(i,nColType,-1)
        nCurShowID = tabFile:GetNumber(i,nColShowID,-1)

        if not tbDecalList[nCurRoleType] then
            tbDecalList[nCurRoleType] = {}
        end
        if not tbDecalList[nCurRoleType][nCurType] then
            tbDecalList[nCurRoleType][nCurType] = {}
        end

        if nCanUse == 1 then
            tbDecalList[nCurRoleType][nCurType][nCurShowID] = nCurShowID
        end
    end

    return tbDecalList

end

---@return table
function Config:GetFaceDecalList()
    local tbDecalList = self:GetDecalList()
    local tbFaceDecalList = {}
    local tabFile = LTabFile:new(FACE_DECAL_PATH)
    local nRowCount = tabFile:GetRowCount()
    local nColRoleType = tabFile:GetColIdxByName("RoleType")
    local nColName = tabFile:GetColIdxByName("Name")
    local nColType = tabFile:GetColIdxByName("Type")
    local nColShowID = tabFile:GetColIdxByName("ShowID")
    local nColFlipID = tabFile:GetColIdxByName("FlipID")
  
    local nCurRoleType = 0
    local szCurName = ""
    local nCurType = 0
    local nCurShowID = 0
    local nCurFlipID = 0

    for i=1,nRowCount do
        nCurRoleType = tabFile:GetNumber(i,nColRoleType,0)
        if nCurRoleType == 1 or nCurRoleType == 2 or nCurRoleType == 5 or nCurRoleType == 6 then
            szCurName = tabFile:GetString(i,nColName,0)
            nCurType = tabFile:GetNumber(i,nColType,0)
            nCurShowID = tabFile:GetNumber(i,nColShowID,-1)
            nCurFlipID = tabFile:GetNumber(i,nColFlipID,0)

            if not tbFaceDecalList[nCurRoleType] then
                tbFaceDecalList[nCurRoleType] = {}
            end

            if not tbFaceDecalList[nCurRoleType][nCurType] then
                tbFaceDecalList[nCurRoleType][nCurType] = {}
            end

            for k,v in pairs(tbDecalList[nCurRoleType][nCurType]) do
                if k == nCurShowID then
                    if not tbFaceDecalList[nCurRoleType][nCurType][nCurShowID] then
                        tbFaceDecalList[nCurRoleType][nCurType][nCurShowID] = {}
                    end
                    tbFaceDecalList[nCurRoleType][nCurType][nCurShowID].Name = util.a2u8(szCurName)
                    tbFaceDecalList[nCurRoleType][nCurType][nCurShowID].ShowID = nCurShowID

                    if nCurFlipID ~= nil and type(nCurFlipID) == "number" and nCurFlipID >0 then
                        local szFlipName = szCurName.."2"
                        if not tbFaceDecalList[nCurRoleType][nCurType][nCurFlipID] then
                            tbFaceDecalList[nCurRoleType][nCurType][nCurFlipID] = {}
                        end
                        tbFaceDecalList[nCurRoleType][nCurType][nCurFlipID].Name = util.a2u8(szFlipName)
                        tbFaceDecalList[nCurRoleType][nCurType][nCurFlipID].ShowID = nCurFlipID
                    end
                end
            end
        end
    end

    return tbFaceDecalList
end

--- nColorCount == 1 mean No ColorID to choose,it only have the default ColorID
---@return table
function Config:GetFaceDecalColorID()
    local tabFile = LTabFile:new(FACE_DECAL_LIST)
    local nRowCount = tabFile:GetRowCount()
    local nColRoleType = tabFile:GetColIdxByName("RoleType")
    local nColType = tabFile:GetColIdxByName("Type")
    local nColShowID = tabFile:GetColIdxByName("ShowID")
    local tbFaceDecalColorID = {}

    local nCurRoleType = 0
    local nCurType = -1
    local nCurShowID = 0

    local nColorCount = 0

    for i=1,nRowCount do
        nCurRoleType = tabFile:GetNumber(i,nColRoleType,0)
        nCurType = tabFile:GetNumber(i,nColType,-1)
        nCurShowID = tabFile:GetNumber(i,nColShowID,0)
        if not tbFaceDecalColorID[nCurRoleType] then
            tbFaceDecalColorID[nCurRoleType] = {}
        end

        if not tbFaceDecalColorID[nCurRoleType][nCurType] then
            tbFaceDecalColorID[nCurRoleType][nCurType] = {}
        end

        if not tbFaceDecalColorID[nCurRoleType][nCurType][nCurShowID] then
            tbFaceDecalColorID[nCurRoleType][nCurType][nCurShowID] = {}
        end

        for j=0,30 do
            local szColorID = "ColorID"..j
            local nColColorID = tabFile:GetColIdxByName(szColorID)
            local nCurColorIDValue = tabFile:GetNumber(i,nColColorID,-1)
            if nCurColorIDValue and type(nCurColorIDValue) == "number" and nCurColorIDValue ~= -1 then
                tbFaceDecalColorID[nCurRoleType][nCurType][nCurShowID][szColorID] = nCurColorIDValue
                nColorCount = nColorCount + 1
            end
        end

        tbFaceDecalColorID[nCurRoleType][nCurType][nCurShowID].ColorCount = nColorCount
        nColorCount = 0
    end
    
    return tbFaceDecalColorID

end

---@return table
function Config:GetDefaultRGBA()
    local tabFile = LTabFile:new(FACE_DECAL_PATH)
    local nRowCount = tabFile:GetRowCount()
    local nColRoleType = tabFile:GetColIdxByName("RoleType")
    local nColType = tabFile:GetColIdxByName("Type")
    local nColShowID = tabFile:GetColIdxByName("ShowID")
    local nColDefaultRGBA = tabFile:GetColIdxByName("DefaultRGBA")
    local nColFlipID = tabFile:GetColIdxByName("FlipID")

    local nCurRoleType = 0
    local nCurType = -1
    local nCurShowID = -1
    local nCurFlipID = -1
    local szCurRGBA = ""
    local tbDefaultRGBA = {}
    for i=1,nRowCount do
        nCurRoleType = tabFile:GetNumber(i,nColRoleType,-1)
        if nCurRoleType == 1 or nCurRoleType == 2 or nCurRoleType == 5 or nCurRoleType == 6 then
            nCurType = tabFile:GetNumber(i,nColType,-1)
            nCurShowID = tabFile:GetNumber(i,nColShowID,-1)
            szCurRGBA = tabFile:GetString(i,nColDefaultRGBA,"")
            if not tbDefaultRGBA[nCurRoleType] then
                tbDefaultRGBA[nCurRoleType] = {}
            end

            if not tbDefaultRGBA[nCurRoleType][nCurType] then
                tbDefaultRGBA[nCurRoleType][nCurType] = {}
            end

            if not tbDefaultRGBA[nCurRoleType][nCurType][nCurShowID] then
                tbDefaultRGBA[nCurRoleType][nCurType][nCurShowID] = {}
            end

            tbDefaultRGBA[nCurRoleType][nCurType][nCurShowID].DefaultRGBA = szCurRGBA

            nCurFlipID = tabFile:GetNumber(i,nColFlipID,-1)
            if nCurFlipID ~= nil and type(nCurFlipID) == "number" and nCurFlipID >0 then
                if not tbDefaultRGBA[nCurRoleType][nCurType][nCurFlipID] then
                    tbDefaultRGBA[nCurRoleType][nCurType][nCurFlipID] = {}
                end
                tbDefaultRGBA[nCurRoleType][nCurType][nCurFlipID].DefaultRGBA = szCurRGBA
            end
        end
    end
    return tbDefaultRGBA
end

function Config:GetCustomFaceDecal()
    local total = FACE_LIFT_DECAL_TYPE.TOTAL
    local tbCustomFaceDecal = {}
    for i=0,total-1 do
        tbCustomFaceDecal[i] = {}
		tbCustomFaceDecal[i].SKINCOLOR = 0
		tbCustomFaceDecal[i].SKINGLOSS = 1
        tbCustomFaceDecal[i].SKINGRAININESS = 1
        tbCustomFaceDecal[i].bUSE = 0
    end
    return tbCustomFaceDecal
end

function Config:GetFaceCustomDecalNames()
    local tbFaceCustomDecalRange = {}
    for i=1,#FACE_CUSTOM_DECAL_RANGE do
        if not tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType] then
            tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType] = {}
        end
        if not tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType][0] then
            tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType][0] = {}
        end
        if not tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType][1] then
            tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType][1] = {}
        end
        if not tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType][2] then
            tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType][2] = {}
        end
        
        tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType][0].MAX = FACE_CUSTOM_DECAL_RANGE[i].SKINCOLOR.MAX
        tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType][0].MIN = FACE_CUSTOM_DECAL_RANGE[i].SKINCOLOR.MIN
        tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType][1].MAX = FACE_CUSTOM_DECAL_RANGE[i].SKINGLOSS.MAX
        tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType][1].MIN = FACE_CUSTOM_DECAL_RANGE[i].SKINGLOSS.MIN
        tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType][2].MAX = FACE_CUSTOM_DECAL_RANGE[i].SKINGRAININESS.MAX
        tbFaceCustomDecalRange[FACE_CUSTOM_DECAL_RANGE[i].RoleType][2].MIN = FACE_CUSTOM_DECAL_RANGE[i].SKINGRAININESS.MIN
    end
    return tbFaceCustomDecalRange
end

function Config:GetFaceDefault()
    local tabFile = LTabFile:new(FACE_DEFAULT_PATH)
    local nRowCount = tabFile:GetRowCount()
    local nColRoleType = tabFile:GetColIdxByName("RoleType")
    local nColFilePath = tabFile:GetColIdxByName("FilePath")
    local nColCanUseInCreate = tabFile:GetColIdxByName("CanUseInCreate")
    local tbFaceDefault = {}

    local nCurRoleType = 0
    local szCurFilePath = ""
    local nCurCanUseInCreate = 0
    for i=1,nRowCount do
        nCurRoleType = tabFile:GetNumber(i,nColRoleType,0)
        if nCurRoleType ~= 0 then
            if not tbFaceDefault[nCurRoleType] then
                tbFaceDefault[nCurRoleType] = {}
            end
            
            szCurFilePath = tabFile:GetString(i,nColFilePath,"")
            nCurCanUseInCreate = tabFile:GetNumber(i,nColCanUseInCreate,0)
            if nCurCanUseInCreate then
                table.insert(tbFaceDefault[nCurRoleType],szCurFilePath)
            end
        end
    end
    return tbFaceDefault
end

function Config:Rand(...)
    return Lib.Rand(...)
end

function Config:GetHistoryFile()
    local tbFaceFile = {}
    local tbRoleType = {}
    tbRoleType[1] = "m2"
    tbRoleType[2] = "f2"
    tbRoleType[5] = "m1"
    tbRoleType[6] = "f1"

    if PLATFORM_PC then
        local szPath = "ugc_common\\settings\\FaceHistory\\"
        szPath = FS.Path.Join(FS.GetCwd(), szPath)
        for k,v in pairs(tbRoleType) do
            local szTypeFaceFile = szPath.."\\"..v
            if not FS.Path.Exists(szTypeFaceFile) then
                FS.MakeDirs(szTypeFaceFile)
            end
            local tbFile = FS.ListDir(szTypeFaceFile)
            tbFaceFile[k] = tbFile
        end
    else
        local szPath = "Resource\\ugc_common\\settings\\FaceHistory\\"
        local szIOPath = ""
        local tbCurRoleTypeFiles = {}
        szIOPath = KLPlatformNative:KLGetPlatformIOPath()
        szIOPath = self:PathJoin_Android(szIOPath,szPath)
        for k,v in pairs(tbRoleType) do
            local szTypeFaceFile = szIOPath..v
            if not KLPlatformNative:KLExist(szTypeFaceFile) then
                KLPlatformNative:KLRecursiveCreate(szTypeFaceFile)
            end
            local nDirectorySizes = KLPlatformNative:KLGetDirectorySizes(szTypeFaceFile)
            if nDirectorySizes >0 then
                for i=1,nDirectorySizes do
                    tbCurRoleTypeFiles[i] = i..""
                end
                KLPlatformNative:KLWalkFile(szTypeFaceFile,tbCurRoleTypeFiles,#tbCurRoleTypeFiles)
            end
            tbFaceFile[k] = tbCurRoleTypeFiles
        end
    end
    return tbFaceFile
end

function Config:SaveCurFace(nRoleType,fileName,tbFaceBone,tbFaceDecals,tbCustomDecal)
    local faceFile
    local nTextureID = 0
    local savePath
    local szContent
    local nVal1,nVal2,nVal3
    if nRoleType == 1 then
        nTextureID = 3
    elseif nRoleType == 2 then
        nTextureID = 3
    elseif nRoleType == 5 then
        nTextureID = 2
    elseif nRoleType == 6 then
        nTextureID = 1
    end

    if PLATFORM_PC then
        savePath = "ugc_common\\settings\\FaceHistory\\f2\\"
        savePath = FS.Path.Join(FS.GetCwd(), savePath)
        if not FS.Path.Exists(savePath) then
            FS.MakeDirs(savePath)
        end
    else
        savePath = "Resource\\ugc_common\\settings\\FaceHistory\\f2\\"
        savePath = self:PathJoin_Android(KLPlatformNative:KLGetPlatformIOPath(),savePath)
        if not KLPlatformNative:KLExist(savePath) then
            LOG_E("Path:"..savePath .." is not exist,Create it now!")
            KLPlatformNative:KLRecursiveCreate(savePath)
        end
    end

    savePath = savePath..fileName
    if PLATFORM_PC then
        faceFile = FS.Open(savePath,"w+")
        if faceFile == nil then
            LOG_E("file:"..savePath.." open failed")
            return
        end
        faceFile.Write("[Face]\n")
        for i=1,#FACE_BONE_NAME_INI do
            szContent = FACE_BONE_NAME_INI[i].."="..tbFaceBone[i].." \n"
            faceFile.Write(szContent)
        end
        faceFile.Write("[Base]\n")
        faceFile.Write("RoleType="..nRoleType.."\n")
        faceFile.Write("TextureID="..nTextureID.."\n")
        faceFile.Write("[Decal]\n")
        for i=1, #FACE_DECAL_NAME_INI do
            faceFile.Write(FACE_DECAL_NAME_INI[i].."="..tbFaceDecals[i-1].nRealShowID.."\n")
            faceFile.Write(FACE_DECAL_NAME_INI[i].."_color".."="..tbFaceDecals[i-1].nRealColorID.."\n")
        end
        faceFile.Write("[CustomDetail]\n")
        for i=1,#FACE_DECAL_NAME_INI do
            nVal1 = self:ValueScaleConversion(tbCustomDecal[i][1],1)
            nVal2 = self:ValueScaleConversion(tbCustomDecal[i][2],2)
            nVal3 = self:ValueScaleConversion(tbCustomDecal[i][3],3)
            faceFile.Write(FACE_DECAL_NAME_INI[i].."_valueEnable="..tbCustomDecal[i][4].."\n")
            faceFile.Write(FACE_DECAL_NAME_INI[i].."_value1="..nVal1.."\n")
            faceFile.Write(FACE_DECAL_NAME_INI[i].."_value2="..nVal2.."\n")
            faceFile.Write(FACE_DECAL_NAME_INI[i].."_value3="..nVal3.."\n")
        end
        faceFile.Close()
    else
        --faceFile = KNativeInterface.KLOpen(savePath,"wa")
        --if faceFile == nil then
        --    LOG_E("file:"..savePath.." open failed")
        --    return
        --end
        szContent = "[Face]\n"
        KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
        for i=1,#FACE_BONE_NAME_INI do
            szContent = FACE_BONE_NAME_INI[i].."="..tbFaceBone[i].." \n"
            KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
        end
        szContent = "[Base]\n"
        KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
        szContent = "RoleType="..nRoleType.."\n"
        KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
        szContent = "TextureID="..nTextureID.."\n"
        KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
        szContent = "[Decal]\n"
        KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
        for i=1, #FACE_DECAL_NAME_INI do
            szContent = FACE_DECAL_NAME_INI[i].."="..tbFaceDecals[i-1].nRealShowID.."\n"
            KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
            szContent = FACE_DECAL_NAME_INI[i].."_color".."="..tbFaceDecals[i-1].nRealColorID.."\n"
            KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
        end
        szContent = "[CustomDetail]\n"
        KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
        for i=1,#FACE_DECAL_NAME_INI do
            nVal1 = self:ValueScaleConversion(tbCustomDecal[i][1],1)
            nVal2 = self:ValueScaleConversion(tbCustomDecal[i][2],2)
            nVal3 = self:ValueScaleConversion(tbCustomDecal[i][3],3)
            szContent = FACE_DECAL_NAME_INI[i].."_valueEnable="..tbCustomDecal[i][4].."\n"
            KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
            szContent = FACE_DECAL_NAME_INI[i].."_value1="..nVal1.."\n"
            KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
            szContent = FACE_DECAL_NAME_INI[i].."_value2="..nVal2.."\n"
            KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
            szContent = FACE_DECAL_NAME_INI[i].."_value3="..nVal3.."\n"
            KLPlatformNative:KLWriteFile(savePath,szContent,"a+")
        end
    end
end

function Config:ValueScaleConversion(num,nType)
    if nType == 1 then
        if self.m_nCurRoleType == 1 then
            num = num / 30
        else
            num = num /70
        end
    elseif nType == 2 then
        if self.m_nCurRoleType == 1 then
            num = num *2 / 190
        else
            num = num *2 / 120
        end
    elseif nType == 3 then
        num = num*2 / 200
    end
    return num
end

function Config:PathJoin_Android(szIOPath,...)
    local tabPath = {...}
    szIOPath = string.replace(szIOPath,"\\","/")
    szIOPath = string.replace(szIOPath,"//","/")
    if string.sub(szIOPath,string.len(szIOPath),string.len(szIOPath)) ~= "/" then
        szIOPath = szIOPath.."/"
    end
    while true do
        local path = table.remove( tabPath, 1)
        if path ~= nil then
            path = string.gsub(path, "//","/");
            path = string.gsub(path, "\\","/");
            if string.sub(path,1,1) == "/" then
                path = string.sub(path,2,string.len(path))
            end
            if string.sub(path,string.len(path),string.len(path)) ~= "/" then
                path = path.."/"
            end
            szIOPath = szIOPath .. path
        else break end
    end
    return szIOPath
end

MakeFaceCfg = Config:new();