------------------------------------------------------------------
-- 角色相关排行榜

-- 排序规则
-- 征战：征战进度
-- 通天塔：层数 通关时间
-- 战力：战力
-- 等级：等级
------------------------------------------------------------------

local LuaMongo = _G.lua_mongo
local DB = require("common.DB")
local BillboardDefine = require("billboard.BillboardDefine")
local BillboardDB = require("billboard.BillboardDB")
local BillboardAim = require("billboard.BillboardAim")
local GlobalWorld = require("core.GlobalWorld")
local CombatPosLogic = require("combat.CombatPosLogic")
local CombatDefine = require("combat.CombatDefine")
local Util = require("common.Util")
local AbsActLogic = require("absAct.AbsActLogic")

-- 加载角色排行
function loadBoard()
    -- 角色
    local cnt = 0
    LuaMongo.find(DB.db_char, nil, BillboardDB.newFiles)
    while true do
        local data = {}
        if not LuaMongo.next(data) then
            break
        end

        cnt = cnt + 1
        if cnt % 1000 == 0 then
            _G.collectgarbage("step", 100000)
        end

        -- 征战
        updateData(BillboardDefine.TYPE_BATTLE, data, true)
        -- 通天塔
        updateData(BillboardDefine.TYPE_TOWER, data, true)
        -- 战力
        updateData(BillboardDefine.TYPE_ZHANDOULI, data, true)
        -- 等级
        updateData(BillboardDefine.TYPE_LV, data, true)
        -- 无尽之路
        updateData(BillboardDefine.TYPE_LIANYU, data, true)    
        -- 冰龙巢穴
        updateData(BillboardDefine.TYPE_DRAGON, data, true)     
        
        -- ABS活动
        AbsActLogic.updateBillBoard(data)  
    end

    AbsActLogic.updateBillBoardRank()
	
	--计算世界等级
	GlobalWorld.doCalcWorldLv()
end

-- 排名值
function getValues(boardType, db)
    if boardType == BillboardDefine.TYPE_BATTLE then
        local fininID = db.guajiID
        local passTimes = db.maxBattleTime or 0
        return (fininID > 0) and fininID, passTimes
    elseif boardType == BillboardDefine.TYPE_TOWER then
        if db.tower and (db.tower.lv or 0) > 0 then
            return db.tower.lv, db.tower.usetime
        end
    elseif boardType == BillboardDefine.TYPE_ZHANDOULI then
        local fakeHuman = {db = db}
        return CombatPosLogic.getCombatHeroZDL(fakeHuman, CombatDefine.COMBAT_TYPE1)
    elseif boardType == BillboardDefine.TYPE_LV then
        return db.lv
    elseif boardType == BillboardDefine.TYPE_UNION then
        return db.zhandouli, db.lv
    elseif boardType == BillboardDefine.TYPE_LIANYU then
        if db.lianyu and db.lianyu.maxLv then
            return db.lianyu.maxLv
        end
    elseif boardType == BillboardDefine.TYPE_DRAGON then
        if db.dragonCopy and db.dragonCopy.time and db.dragonCopy.dayHurt then
            if Util.isSameDay(db.dragonCopy.time) and db.dragonCopy.dayHurt > 0 then                
                return db.dragonCopy.dayHurt 
            end
        end
    end
end

-- 比较
function cmpValues(boardType, data1, data2)
    if data1.value1 ~= data2.value1 then
        return data1.value1 > data2.value1
    end
    if data1.value2 ~= data2.value2 then
        if boardType == BillboardDefine.TYPE_TOWER or boardType == BillboardDefine.TYPE_BATTLE then
            return data1.value2 < data2.value2
        else
            return data1.value2 > data2.value2
        end
    end
    if (data1.time or 0) ~=(data2.time or 0) then
        return(data1.time or 0) <(data2.time or 0)
    end
    return true
end

-- 设置值
local function setValues(boardType, data, db, value1, value2)
    data.uuid = db._id
    data.value1 = value1
    data.value2 = value2 or 0
    data.time = BillboardDB.getTime(boardType, db)
end

--
local TempData = nil
function getCacheData(boardType, db, value1, value2)
    TempData = TempData or BillboardDB.initRankData()
    setValues(boardType, TempData, db, value1, value2)   
    return TempData
end

function updateData(boardType, db, isInit)
    local board = BillboardDB.getBoard(boardType, isInit)
    if not board then return end

    local value1, value2 = getValues(boardType, db)
    if not value1 then return end

    local dbrank = board.uuid2rank[db._id]
    local dbdata = dbrank and board.rank2data[dbrank]
    if dbdata then
        if dbdata.value1 == value1 and dbdata.value2 == (value2 or 0) then
            return -- 优化，原来值跟新值一样
        end
        table.remove(board.rank2data, dbrank)
    end
    if not isInit then -- 刷新上榜时间
        BillboardDB.refreshTime(boardType, db)
        BillboardAim.onCallback(boardType, db, value1)
    end

    local maxRank = #board.rank2data
    local rank = maxRank + 1
    local tempData = getCacheData(boardType, db, value1, value2)
    for i = maxRank, 1, -1 do
        local tdata = board.rank2data[i]
        if cmpValues(boardType, tdata, tempData) then
            break
        end
        board.rank2data[i + 1] = tdata
        rank = i
    end

    if rank > BillboardDefine.MAX_CNT then return end
    local data = nil
    if maxRank < BillboardDefine.MAX_CNT then
        data = BillboardDB.initRankData()
    else
        data = board.rank2data[BillboardDefine.MAX_CNT + 1]
    end
    setValues(boardType, data, db, value1, value2)
    board.rank2data[rank] = data
    board.rank2data[BillboardDefine.MAX_CNT + 1] = nil
    if rank ~= dbrank then
        board.dirty = true
    end
    return true
end