%% ---------------------------------------------
%% desc:跨服团战管理进程相关逻辑接口
%% moudle:camp_war_logic.erl
%% author:hh
%% time:20/07/21
%% ---------------------------------------------


-module(camp_war_logic).

-export([
    init_zone_info/1
    ,calc_act/2
    ,add_svrs_logic/2
    ,init_local_guild_info/1
    ,update_guild_info/3
    ,db_update_fact_guild_rank/3
    ,handle_merge/4
    ]).

-compile([export_all]).

-include("camp_war.hrl").
-include("def_module.hrl").
-include("common.hrl").
-include("activitycalen.hrl").
-include("guild_war.hrl").
-include("def_fun.hrl").
-include("figure.hrl").
-include("cross_guild_war.hrl").

%% 获取标准分区信息
%% 若初始化失败,则定时检测
init_zone_info(StateData) ->
    #camp_war_state{extra_map = Map, cls_type = ClsType} = StateData,
    Ref = maps:get(?ZONE_INIT_INTERVAL, Map, undefined),
    util:cancel_timer(Ref),
    if ClsType == ?NODE_CENTER ->
            case catch czone:get_faction_map(all) of
                ZoneFacMap when is_map(ZoneFacMap) ->
                    case load_fac_zone_info(ZoneFacMap) of
                        true ->
                            NewMap  = maps:put(?ZONE_INIT_INTERVAL, undefined, Map),
                            NewMap1 = maps:put(?FAC_ZONE_INIT, 1, NewMap),
                            StateData#camp_war_state{extra_map = NewMap1};
                        false -> %% 加载为空,后续继续加载
                            AfterTime = ?ZONE_INIT_INTERVAL_TIME,
                            NewRef = erlang:send_after(AfterTime, self(), {zone_calc}),
                            NewMap = maps:put(?ZONE_INIT_INTERVAL, NewRef, Map),
                            StateData#camp_war_state{extra_map = NewMap}
                    end;
                _ ->
                    AfterTime = ?ZONE_INIT_INTERVAL_TIME,
                    NewRef    = erlang:send_after(AfterTime, self(), {zone_calc}),
                    NewMap  = maps:put(?ZONE_INIT_INTERVAL, NewRef, Map),
                    StateData#camp_war_state{extra_map = NewMap}
            end;
        ClsType == ?NODE_GAME ->
            SvrId = config:get_server_id(),
            ets:insert(?ETS_FAC_SRV_ZONE, [{SvrId, {?LOC_ZONE, ?LOC_FAC}}]),
            NewMap = maps:put(?FAC_ZONE_INIT, 1, Map),
            ets:insert(?ETS_FAC_ZONE_FACS, [{?LOC_ZONE, [?LOC_FAC]}]),
            StateData#camp_war_state{extra_map = NewMap};
        true ->
            StateData
    end.

%% 加载阵营&分区信息
%% ZoneFactionSvrsMap :: #{ZoneId => FactionSvrMap}, FactionSvrMap :: #{Faction => ServerIds}
load_fac_zone_info(#{zone_faction_svrs_map := ZoneFactionSvrsMap}) ->
    % 过滤还未分区的阵营
    ZoneFactionSvrsMap1 = maps:remove(0, ZoneFactionSvrsMap),
    ZoneFactionSvrsList = maps:to_list(ZoneFactionSvrsMap1),

    {FacSrvZoneList, ZoneFacs} =
    lists:foldl(fun({ZoneId, FacSvrsMap}, {TempSrvZoneList, TempZoneFacs}) ->

        %% 服务器ID与{分区ID,阵营ID}映射
        ServZoneList =
         maps:fold(fun(FacId, SvrsL, Acc) ->
            lists:append([{ServId, {ZoneId, FacId}} || ServId <- SvrsL], Acc)
        end, [], FacSvrsMap),
        NewTempSrvZoneList = lists:append(ServZoneList, TempSrvZoneList),
         % ?ERR("~p", [ServZoneList]),

        %% 分区ID与分区内阵营列表映射
        %% {ZoneId, FacIds = [_|_]}
        ZoneFacList =
         maps:fold(fun(FacId1, _SvrsL1, Acc1) ->
            case lists:member(FacId1, Acc1) of
                true ->
                    Acc1;
                _ ->
                    [FacId1|Acc1]
            end
        end, [], FacSvrsMap),
        NewTempZoneFacs = lists:append([{ZoneId, ZoneFacList}], TempZoneFacs),
        {NewTempSrvZoneList, NewTempZoneFacs}
    end, {[], []}, ZoneFactionSvrsList),
    if FacSrvZoneList =/= [] andalso ZoneFacs =/= [] ->
            ets:insert(?ETS_FAC_SRV_ZONE, FacSrvZoneList),
            ets:insert(?ETS_FAC_ZONE_FACS, ZoneFacs),
            true;
        true ->
            false
    end.

%% 初始化阵营战场信息
init_fac_arena_info(State) ->
    #camp_war_state{extra_map = Map} = State,
    GuildInit     = maps:get(?FAC_GUILD_INIT, Map, 0),
    FaceArenaInit = maps:get(?FAC_ARENA_INIT, Map, 0),
    if
        GuildInit == 0 -> %% 社团信息未初始化,等待完成再操作
            State;
        FaceArenaInit == 1 -> %% 战场分配已完成
            State;
        true ->
            NewState = load_fac_arena_info(State),
            NewMap = maps:put(?FAC_ARENA_INIT, 1, NewState#camp_war_state.extra_map),
            NewState#camp_war_state{extra_map = NewMap}
    end.

%% 初始化社团积分数据
init_local_guild_info(State) ->
    #camp_war_state{extra_map = Map} = State,
    ZoneInit    = maps:get(?FAC_ZONE_INIT, Map, 0),
    GuildInit   = maps:get(?FAC_GUILD_INIT, Map, 0),
    if
        ZoneInit =/= 1 -> %% 分区信息未初始化
            State;
        GuildInit == 1 -> %% 社团数据已加载
            State;
        true ->
            case db:get_all(?SQL_SELECT_LOCAL_GUILD_SCORE, []) of
                DataList = [_|_] ->
                    SrvZoneList  = get_fac_guild_war_ets_data(?ETS_FAC_SRV_ZONE),
                    AllGuildInfo = init_local_guild_info_do(DataList, SrvZoneList, []),
                    ets:insert(?ETS_FAC_LOCAL_GWAR_INFO, AllGuildInfo);
                _ ->
                    ok
            end,
            NewMap = maps:put(?FAC_GUILD_INIT, 1, Map),
            State#camp_war_state{extra_map = NewMap}
    end.

%% 初始化上期团战战果
init_camp_war_ret(StateData) ->
    case db:get_all(?SQL_SELECT_CAMP_WAR_RESULT) of
        DataList = [_|_] ->
            CampWarRet = change_camp_war_ret(DataList),
            ets:insert(?ETS_FAC_LOG_RET, CampWarRet),
            StateData;
        _ ->
            StateData
    end.

% [{{ZoneId, FacId}, GuildRank},...]
change_camp_war_ret(DataList) ->
    CampWarRet =
    lists:foldl(fun([ZoneId, FacId, SvrId, GuildId, SvrNum, GuildName, Hurt, GuildPower, ChiefInfoBin], Acc) -> 
        CampGuild = #camp_war_guild{
            guild_id = GuildId, guild_name = GuildName, guild_power = GuildPower, hurt = Hurt, zone_facs = {ZoneId, FacId},
            chief_info = util:bitstring_to_term(ChiefInfoBin), server_id = SvrId, server_num = SvrNum
        },
        case lists:keyfind({ZoneId, FacId}, 1, Acc) of
            {_, FactionRank} ->
                NewFactionRank = lists:keystore(GuildId, #camp_war_guild.guild_id, FactionRank, CampGuild),
                lists:keystore({ZoneId, FacId}, 1, Acc, {{ZoneId, FacId}, NewFactionRank});
            _ ->
                NewFactionRank = [CampGuild],
                [{{ZoneId, FacId}, NewFactionRank}|Acc]
        end
    end, [], DataList),
    lists:map(fun({{ZoneIdX, FacIdX}, FactionRankX}) -> 
        SortedFacRanks = lists:reverse(lists:keysort(#camp_war_guild.hurt, FactionRankX)),
        {{ZoneIdX, FacIdX}, SortedFacRanks}
    end, CampWarRet).


%% 加载阵营内战场分配信息
load_fac_arena_info(State) ->
    #camp_war_state{fac_index = FacIndex, cls_type = ClsType} = State,
    %% 分区阵营社团列表
    ZoneFacGuildInfo  = get_fac_guild_war_ets_data(?ETS_FAC_LOCAL_GWAR_INFO),
    if ClsType == ?NODE_CENTER ->
            %% 节点开服时间
            ServOpenTime = clusters_center:get_nodes_open_time(),
            {NewZoneFacArenas, NewFacIndex} =
             lists:foldl(fun({{ZoneId, FacId}, GuildInfo}, {TempAcc, TmpFacIndex}) ->
                FacGuildArenaList = calc_guild_arena_info(GuildInfo, ServOpenTime),
                NewTempAcc = lists:keystore({ZoneId, FacId}, 1, TempAcc, {{ZoneId, FacId}, TmpFacIndex, FacGuildArenaList}),
                {NewTempAcc, TmpFacIndex+1}
            end, {[], FacIndex}, ZoneFacGuildInfo);
        true ->
            {NewZoneFacArenas, NewFacIndex} = 
            lists:foldl(fun({{ZoneId, FacId}, GuildInfo}, {TempAcc, TmpFacIndex}) ->
                SortedGuildInfo = lists:sort(
                    fun(#local_gwar_info{score = S1}, #local_gwar_info{score = S2}) ->  S1 >= S2
                end, GuildInfo),
                FacGuildArenaList = calc_guild_arena_info_do(SortedGuildInfo, 1, []),
                NewTempAcc = lists:keystore({ZoneId, FacId}, 1, TempAcc, {{ZoneId, FacId}, TmpFacIndex, FacGuildArenaList}),
                {NewTempAcc, TmpFacIndex+1}
            end, {[], FacIndex}, ZoneFacGuildInfo)
    end,
    ets:insert(?ETS_FAC_ARENA_INFO, NewZoneFacArenas),
    State#camp_war_state{fac_index = NewFacIndex}.


%% 新增注册的服务器分区
add_svrs_logic(Map, State) ->
    %% AddServers :: [{ServerId, ZoneId, Faction}]
    #{add_servers := AddServers} = Map,
    SrvZoneList = get_fac_guild_war_ets_data(?ETS_FAC_SRV_ZONE),
    ZoneFacs    = get_fac_guild_war_ets_data(?ETS_FAC_ZONE_FACS),
    %% 更新服务器与{分区,阵营}映射
    {_SrvZoneOldAndNew, SrvZoneChangeList} =
     lists:foldl(fun({ServId, ZoneId, FacId}, {SrvOldAndNew, ChangeList}) ->
        case lists:keyfind(ServId, 1, SrvZoneList) of
            {_, {ZoneId, FacId}} ->
                {SrvOldAndNew, ChangeList};
            {_, {OldZoneId, OldFacId}} ->
                NewSrvOldAndNew = [{ServId, {OldZoneId, OldFacId}, {ZoneId, FacId}}|SrvOldAndNew],
                NewChangeList = lists:keystore(ServId, 1, ChangeList, {ServId, {ZoneId, FacId}}),
                {NewSrvOldAndNew, NewChangeList};
            _ ->
                NewChangeList = lists:keystore(ServId, 1, ChangeList, {ServId, {ZoneId, FacId}}),
                {SrvOldAndNew, NewChangeList}
        end
    end, {[], []}, AddServers),
    ets:insert(?ETS_FAC_SRV_ZONE, SrvZoneChangeList),

    %% 更新服务器分区阵营列表
    ZoneFacChangeList = lists:foldl(fun({_ServId, ZoneId, FacId}, TempZoneFacs) ->
        case lists:keyfind(ZoneId, 1, ZoneFacs) of
            {_, Facs} ->
                case lists:member(FacId, Facs) of
                    true ->
                        TempZoneFacs;
                    _ ->
                        lists:keystore(ZoneId, 1, TempZoneFacs, {ZoneId, [FacId|Facs]})
                end;
            _ ->
                lists:keystore(ZoneId, 1, TempZoneFacs, {ZoneId, [FacId]})
        end
    end, [], AddServers),
    ets:insert(?ETS_FAC_ZONE_FACS, ZoneFacChangeList),
    State.

%% 动态分区调整
% CZState       分区各功能模块状态数据
% ZoneMap       #{OldZoneId  => NewZoneId}
% FactionMaps   #{OldZoneId  => FactionMap :: #{OldFaction => NewFaction}}
% （ZoneMap中，OldZoneId 等于 NewZoneId 说明该分区为主分区，未发生zone_id变化）
    % CBMap = #{
    %     cz_state => CZState
    %     ,svr_zone_map => NewSvrZoneMap
    %     ,zone_map => ZoneMap
    %     ,faction_maps => FactionMaps
    % },
czone_recalc_callback(Map, State) ->
    #camp_war_state{extra_map = CampMap} = State,
    ArenaRes = maps:get(?FAC_ARENA_INIT, CampMap, 0),
    TodayActRes = maps:get(?IS_TODAY_ACT, CampMap, 0),

    FacSrvZoneList = ets:tab2list(?ETS_FAC_SRV_ZONE),
    {SrvZoneChangeList, NewFacSrvZoneList} = recalc_srv_zone_fac(Map, FacSrvZoneList),
    ets:insert(?ETS_FAC_SRV_ZONE, NewFacSrvZoneList),
    
    ZoneFacs = ets:tab2list(?ETS_FAC_ZONE_FACS),
    {ChangeMap, NewZoneFacs} = recalc_zone_fac(Map, ZoneFacs),
    ets:insert(?ETS_FAC_ZONE_FACS, NewZoneFacs),
    
    FacGuildL = ets:tab2list(?ETS_FAC_LOCAL_GWAR_INFO),
    NewFacGuildL = recalc_guild_fac_info(TodayActRes, FacGuildL, ChangeMap, SrvZoneChangeList),
    ets:insert(?ETS_FAC_LOCAL_GWAR_INFO, NewFacGuildL),

    CampWarRet = ets:tab2list(?ETS_FAC_LOG_RET),
    NewCampWarRet = recalc_camp_war_rank_log(ChangeMap, CampWarRet),
    ets:insert(?ETS_FAC_LOG_RET, NewCampWarRet),
    
    %% 结合今日是否有活动及是否在活动中进行判断
    NewState = 
    if
        ArenaRes == 1 -> %% 若今天有活动则要删除有分区变动的战场信息
        if TodayActRes == 1 ->
                    recalc_fac_arena_info(ChangeMap),
                    State;
                true -> %% 今日无活动则正常更新战场信息
                    ets:delete_all_objects(?ETS_FAC_ARENA_INFO),
                    load_fac_arena_info(State)
            end;
        true -> %% 未初始化,忽略
            State
    end,
    NewState.

%% 服务器与{分区,阵营}映射调整
recalc_srv_zone_fac(Map, SrvZoneList) ->
    #{
        zone_map := NewZoneMap,     %% ZoneMap       #{OldZoneId  => NewZoneId}
        faction_maps := NewFacMap   %% FactionMaps   #{OldZoneId  => FactionMap :: #{OldFaction => NewFaction}}
    } = Map,
    {SrvZoneChangeList, NewSrvZoneList} =
    lists:foldl(fun({ServId, {OldZoneId, OldFacId}}, {TempChangeList, TempSrvZoneList}) ->
        {IsZoneChange, ZoneId1} =
        case maps:get(OldZoneId, NewZoneMap, false) of
            NewZoneId when not is_boolean(NewZoneId) ->
                {true, NewZoneId};
            _ ->
                {false, OldZoneId}
        end,
        {IsFacChange, FacId1} =
        case maps:get(OldZoneId, NewFacMap, false) of
            FacChangeMap when is_map(FacChangeMap) ->
                case maps:get(OldFacId, FacChangeMap, false) of
                    NewFacId when not is_boolean(NewFacId) ->
                        {true, NewFacId};
                    _ ->
                        {false, OldFacId}
                end;
            _ ->
                {false, OldFacId}
        end,
        if
            IsZoneChange orelse IsFacChange ->
                NewServZoneFac = {ServId, {ZoneId1, FacId1}},
                {[NewServZoneFac|TempChangeList], lists:keystore(ServId, 1, TempSrvZoneList, NewServZoneFac)};
            true ->
                {TempChangeList, TempSrvZoneList}
        end
    end, {[], SrvZoneList}, SrvZoneList),
    {SrvZoneChangeList, NewSrvZoneList}.

%% 分区阵营列表调整
recalc_zone_fac(Map, ZoneFacs) ->
    #{
        zone_map := NewZoneMap,         %% #{OldZoneId  => NewZoneId}
        faction_maps := NewFacMap       %% #{OldZoneId  => FactionMap :: #{OldFaction => NewFaction}}
    } = Map,
    NewFacMapList = maps:to_list(NewFacMap),
    {ChangeMap, NewZoneFacs} =
    lists:foldl(fun({OldZoneId, FacMap}, {TempChangeMap, TempZoneFacs}) ->
        {NewTempChangeMap, NewTempZoneFacs} =
         recalc_zone_fac_do(OldZoneId, FacMap, TempZoneFacs, NewZoneMap, TempChangeMap),
        {NewTempChangeMap, NewTempZoneFacs}
    end, {#{}, ZoneFacs}, NewFacMapList),
    {ChangeMap, NewZoneFacs}.

%% 清除旧分区阵营
%% 检查新分区阵营是否完备
%% 返回新旧分区阵营映射
recalc_zone_fac_do(OldZoneId, FacMap, ZoneFacs, NewZoneMap, ChangeMap) ->
    case maps:get(OldZoneId, NewZoneMap, 0) of
        0 ->
            {ChangeMap, ZoneFacs};
        NewZoneId ->
            NewZoneFacIds =
            case lists:keyfind(NewZoneId, 1, ZoneFacs) of
                {_, OldZoneFacIds} -> OldZoneFacIds;
                _  -> []
            end,
            {NewChangeMap, NewZoneFacIds1} =
            lists:foldl(fun({OldFacId, NewFacId}, {TempChangeMap, TempNewL}) ->
                case lists:member(NewFacId, TempNewL) of
                    true ->
                        NewTempNewL = TempNewL;
                    _ ->
                        NewTempNewL = [NewFacId|TempNewL]
                end,
                NewTempChangeMap = maps:put({OldZoneId, OldFacId}, {NewZoneId, NewFacId}, TempChangeMap),
                {NewTempChangeMap, NewTempNewL}
            end, {ChangeMap, NewZoneFacIds}, maps:to_list(FacMap)),
            NewZoneFacs  = lists:keydelete(OldZoneId, 1, ZoneFacs),
            ets:delete(?ETS_FAC_ZONE_FACS, OldZoneId),
            NewZoneFacs1 = lists:keystore(NewZoneId, 1, NewZoneFacs, {NewZoneId, NewZoneFacIds1}),
            {NewChangeMap, NewZoneFacs1}
    end.

%% 若当天无活动,则合并阵营数据,更新阵营信息
%% ChangeSrvZoneList :: [{ChangeServId, {NewZoneId, NewFacId}},...]
%% ChangeMap :: #{{OldZoneId, OldFacId} => {NewZoneId, NewFacId}}
recalc_guild_fac_info(_TodayActRes = 0, FacGuildL, ChangeMap, _ChangeSrvZoneList) ->
    lists:foldl(fun({{OldZoneId, OldFacId}, {NewZoneId, NewFacId}}, TempFacGuildL) -> 
        case lists:keyfind({OldZoneId, OldFacId}, 1, TempFacGuildL) of
            {_, GuildL} ->
                NewGuildL = recalc_guild_fac_info_do([], GuildL, {NewZoneId, NewFacId}),
                ets:delete(?ETS_FAC_LOCAL_GWAR_INFO, {OldZoneId, OldFacId}),
                db_recalc_guild_fac_info(NewGuildL),
                NewTempFacGuildL = lists:keydelete({OldZoneId, OldFacId}, 1, TempFacGuildL),
                NewTempFacGuildL1 = 
                case lists:keyfind({NewZoneId, NewFacId}, 1, NewTempFacGuildL) of
                    {_, NewZoneFacGuildL} ->
                        NewZoneFacGuildL1 = lists:append(NewGuildL, NewZoneFacGuildL),
                        lists:keystore({NewZoneId, NewFacId}, 1, NewTempFacGuildL, {{NewZoneId, NewFacId}, NewZoneFacGuildL1});
                    _ ->
                        lists:keystore({NewZoneId, NewFacId}, 1, NewTempFacGuildL, {{NewZoneId, NewFacId}, NewGuildL})
                end,
                NewTempFacGuildL1;
            _ ->
                TempFacGuildL
        end        
    end, FacGuildL, maps:to_list(ChangeMap));

%% 若当天有活动,则有分区阵营变动的都不开,删除数据
recalc_guild_fac_info(_TodayActRes = 1, FacGuildL, ChangeMap, _ChangeSrvZoneList) ->
    lists:foldl(fun({{OldZoneId, OldFacId}, {NewZoneId, NewFacId}}, TempFacGuildL) ->
        db_delete_guild_fac_info({OldZoneId, OldFacId}, {NewZoneId, NewFacId}),
        ets:delete(?ETS_FAC_LOCAL_GWAR_INFO, {OldZoneId, OldFacId}),
        ets:delete(?ETS_FAC_LOCAL_GWAR_INFO, {NewZoneId, NewFacId}),
        NewTempFacGuildL = lists:keydelete({OldZoneId, OldFacId}, 1, TempFacGuildL),
        NewTempFacGuildL1 = lists:keydelete({NewZoneId, NewFacId}, 1, NewTempFacGuildL),
        NewTempFacGuildL1
    end, FacGuildL, maps:to_list(ChangeMap)).


recalc_camp_war_rank_log(ChangeMap, CampWarRet) ->
    {DbList, NewCampWarRet} =
    maps:fold(fun({OldZoneId, OldFacId}, {NewZoneId, NewFacId}, {TempDbList, TempCampWarRet}) ->
        ets:delete(?ETS_FAC_LOG_RET, {OldZoneId, OldFacId}),
        {ChangeList, NewFactionRanks} = recalc_camp_faction_rank({OldZoneId, OldFacId}, {NewZoneId, NewFacId}, TempDbList, TempCampWarRet),
        {ChangeList, NewFactionRanks}
    end, {[], CampWarRet}, ChangeMap),
    DbList =/= [] andalso db:insert_batch(?REPLACE_INTO_CAMP_WAR_RESULT, DbList),
    NewCampWarRet.

recalc_camp_faction_rank({OldZoneId, OldFacId}, {NewZoneId, NewFacId}, DbList, CampWarRet) ->
    case lists:keyfind({NewZoneId, NewFacId}, 1, CampWarRet) of
        {_, FactionRanks} -> ok;
        _   -> FactionRanks = []
    end,
    case lists:keyfind({OldZoneId, OldFacId}, 1, CampWarRet) of
        {_, OldFactionRanks} ->
            NewDbList =
            lists:foldl(fun(CampGuild, TempDbL) ->
                #camp_war_guild{
                    guild_id = GuildId, guild_name = GuildName, guild_power = GuildPower, 
                    server_id = SvrId,  server_num = SvrNum, hurt = Hurt, chief_info = ChiefInfo
                } = CampGuild,
                [[GuildId, NewZoneId, NewFacId, SvrId, SvrNum, GuildName, Hurt, GuildPower, util:term_to_bitstring(ChiefInfo)]|TempDbL]
            end, DbList, OldFactionRanks),

            SortedFactionRanks  = lists:reverse(lists:keysort(#camp_war_guild.hurt, FactionRanks ++ OldFactionRanks)),
            NewCampWarRet       = lists:keystore({NewZoneId, NewFacId}, 1, CampWarRet, {{NewZoneId, NewFacId}, SortedFactionRanks}),
            NewCampWarRet1      = lists:keydelete({OldZoneId, OldFacId}, 1, NewCampWarRet),
            {NewDbList, NewCampWarRet1};
        _ ->
            {DbList, CampWarRet}
    end.


recalc_guild_fac_info_do(NewGuildL, [], {_, _}) ->
    NewGuildL;
recalc_guild_fac_info_do(Acc, [GuildInfo = #local_gwar_info{}|Rest], {NewZoneId, NewFacId}) ->
    NewGuildInfo = GuildInfo#local_gwar_info{
        zone_id = NewZoneId, fac_id = NewFacId
    },
    recalc_guild_fac_info_do([NewGuildInfo|Acc], Rest, {NewZoneId, NewFacId});
recalc_guild_fac_info_do(Acc, [_|Rest], {NewZoneId, NewFacId}) ->
    recalc_guild_fac_info_do(Acc, Rest, {NewZoneId, NewFacId}).

%% 数据库更新修改
db_recalc_guild_fac_info(GuildInfoL) ->
    GuildInfoL =/= [] andalso db_update_guild_info(GuildInfoL),
    ok.

db_delete_guild_fac_info({OldZoneId, OldFacId}, {NewZoneId, NewFacId}) ->
    db:execute(?SQL_DELETE_LOCAL_ONE_GUILD_SCORE, [OldZoneId, OldFacId, NewZoneId, NewFacId]),
    ok.

%% ChangeMap :: #{{OldZoneId, OldFacId} => {NewZoneId, NewFacId}}
recalc_fac_arena_info(ChangeMap) ->
    lists:foldl(fun({{OldZoneId, OldFacId}, {NewZoneId, NewFacId}}, Acc) -> 
        %% TODO 收集今日因动态分区而停开活动的服务器id
        ets:delete(?ETS_FAC_ARENA_INFO, {OldZoneId, OldFacId}),
        ets:delete(?ETS_FAC_ARENA_INFO, {NewZoneId, NewFacId}),
        Acc
    end, [], maps:to_list(ChangeMap)).

%% 合服处理
%% @doc MasterServId  主服serverid
%% @doc MasterServNum 主服server编号
%% @doc MergeServers  合服列表
handle_merge(MasterServId, MasterServNum, MergeServers, State) ->
    #camp_war_state{extra_map = CampMap, cls_type = _ClsType} = State,
    ArenaRes    = maps:get(?FAC_ARENA_INIT, CampMap, 0),
    % TodayActRes = maps:get(?IS_TODAY_ACT, CampMap, 0),

    %% 更新服务器id与分区
    SrvZones    = ets:tab2list(?ETS_FAC_SRV_ZONE),
    NewSrvZones = lists:foldl(fun({SrvId, {ZoneId, FacId}}, Acc) -> 
        case lists:member(SrvId, MergeServers) of
            true -> Acc; %% 过滤被合的服
            _    -> [{SrvId, {ZoneId, FacId}}|Acc]
        end
    end, [], SrvZones),
    ets:delete_all_objects(?ETS_FAC_SRV_ZONE),
    ets:insert(?ETS_FAC_SRV_ZONE, NewSrvZones),

    case ets:lookup(?ETS_FAC_SRV_ZONE, MasterServId) of
        [{_MasterServId, {MasterZoneId, MasterFaction}}|_] ->
            
            %% 更新百团大战社团战果信息(团战数据源)
            ZoneFacGuildInfo = ets:tab2list(?ETS_FAC_LOCAL_GWAR_INFO),
            case lists:keyfind({MasterZoneId, MasterFaction}, 1, ZoneFacGuildInfo) of
                {_, MasterFactionGuilds} -> ok;
                _ -> MasterFactionGuilds = []
            end,
            NewMasterFactionGuilds = lists:foldl(fun(ZoneFacGuilds, TempMasterFactionGuilds) ->
                {{ZoneId, FacId}, FacGuildList} = ZoneFacGuilds,
                {IsSrvChange, NewFacGuildList, NewTempMasterFactionGuilds}
                 = update_merge_svr_guild_info({MasterServId, MasterServNum, MasterZoneId, MasterFaction, TempMasterFactionGuilds}, MergeServers, FacGuildList),
                IsSrvChange andalso ets:insert(?ETS_FAC_LOCAL_GWAR_INFO, {{ZoneId, FacId}, NewFacGuildList}),
                NewTempMasterFactionGuilds
            end, MasterFactionGuilds, ZoneFacGuildInfo),
            ets:insert(?ETS_FAC_LOCAL_GWAR_INFO, {{MasterZoneId, MasterFaction}, NewMasterFactionGuilds}),

            %% 更新团战结果数据(国战数据源)
            CampWarRet = ets:tab2list(?ETS_FAC_LOG_RET),
            NewCampWarRet   = handle_camp_war_ret_when_merge(MasterServId, MasterServNum, MasterZoneId, MasterFaction, MergeServers, CampWarRet),
            ets:delete_all_objects(?ETS_FAC_LOG_RET),
            ets:insert(?ETS_FAC_LOG_RET, NewCampWarRet);
        _ ->
            skip
    end,

    %% 如果当天有活动,修正战场信息
    if
        ArenaRes == 1 ->
            ets:delete_all_objects(?ETS_FAC_ARENA_INFO),
            NewState = load_fac_arena_info(State);
        true ->
            NewState = State
    end,
    NewState.

%% @Paraments Desc
%% MasterServId     主服id 
%% MasterServNum    主服编号 
%% MergeServers     被合服id
%% {{ZoneId, FacId}, ZoneFacGuildList} 阵营内社团列表
%% @Return 
%% IsSrvChange      该阵营数据是否更新
%% NewFacGuildList  变动的阵营社团列表
update_merge_svr_guild_info({MasterServId, MasterServNum, MasterZoneId, MasterFaction, MasterFactionGuilds}, MergeServers, ZoneFacGuildList) ->
    {IsSrvChange, NewZoneFacGuildList, DbGuildList, NewMasterFactionGuilds} = update_merge_svr_guild_info_1(
        {MasterServId, MasterServNum, MasterZoneId, MasterFaction, MasterFactionGuilds}, MergeServers, ZoneFacGuildList, {false, [], []}),
    %% 更新合服变动的服信息
    db_update_guild_info(DbGuildList),
    {IsSrvChange, NewZoneFacGuildList, NewMasterFactionGuilds}.

update_merge_svr_guild_info_1({_, _, _, _, MasterFactionGuilds}, _MergeServers, [], {IsSrvChange, ZoneFacGuildList, DbGuildList}) ->
    {IsSrvChange, ZoneFacGuildList, DbGuildList, MasterFactionGuilds};
update_merge_svr_guild_info_1({MasterServId, MasterServNum, MasterZoneId, MasterFaction, MasterFactionGuilds}, MergeServers, [GwarInfo|Rest], {IsSrvChange, ZoneFacGuildList, DbGuildList}) ->
    #local_gwar_info{guild_id = GuildId, server_id = ServId} = GwarInfo,
    case lists:member(ServId, MergeServers) of
        true ->
            NewGwarInfo = GwarInfo#local_gwar_info{server_id = MasterServId, server_num = MasterServNum, zone_id = MasterZoneId, fac_id = MasterFaction},
            NewMasterFactionGuilds  = lists:keystore(GuildId, #local_gwar_info.guild_id, MasterFactionGuilds, NewGwarInfo), 
            NewDbGuildList = [NewGwarInfo|DbGuildList],
            update_merge_svr_guild_info_1({MasterServId, MasterServNum, MasterZoneId, MasterFaction, NewMasterFactionGuilds}, MergeServers, Rest, {true, ZoneFacGuildList, NewDbGuildList});
        _ ->
            NewZoneFacGuildList = [GwarInfo|ZoneFacGuildList],
            update_merge_svr_guild_info_1({MasterServId, MasterServNum, MasterZoneId, MasterFaction, MasterFactionGuilds}, MergeServers, Rest, {IsSrvChange, NewZoneFacGuildList, DbGuildList})
    end.

%% @desc:更新每个阵营的战果的服务器数据
%% CampWarRet :: [{{ZoneId, FacId}, GuildRank},...]
%% GUildRank :: 
handle_camp_war_ret_when_merge(MasterServId, MasterServNum, MasterZone, MasterFaction, MergeServers, CampWarRet) ->
    case lists:keyfind({MasterZone, MasterFaction}, 1, CampWarRet) of
        {_, MasterZoneFactionRet} -> ok;
        _ -> MasterZoneFactionRet = []
    end,
    handle_camp_war_ret_when_merge_1({MasterServId, MasterServNum, MasterZone, MasterFaction, MasterZoneFactionRet}, MergeServers, CampWarRet, [], []).

handle_camp_war_ret_when_merge_1({_, _, MasterZone, MasterFaction, MasterZoneFactionRet}, _MergeServers, [], CampWarRet, ChangeRet) ->
    %% 更新数据库战果服务器数据
    db_update_camp_war_ret_when_merge(ChangeRet),
    NewCampWarRet = lists:keystore({MasterZone, MasterFaction}, 1, CampWarRet, {{MasterZone, MasterFaction}, MasterZoneFactionRet}),
    NewCampWarRet;
handle_camp_war_ret_when_merge_1({MasterServId, MasterServNum, MasterZone, MasterFaction, MasterZoneFactionRet}, MergeServers, [{{ZoneId, FacId}, GuildRank}|Rest], TempCampWarRet, ChangeRet) ->
    {MasterZoneFactionRet1, NewGuildRank, ChangeGuildRank} = handle_svr_camp_war_ret_merge({MasterServId, MasterServNum, MasterZone, MasterFaction, MasterZoneFactionRet}, MergeServers, GuildRank, {[], []}),
    NewChangeRet = lists:append(ChangeGuildRank, ChangeRet),
    handle_camp_war_ret_when_merge_1({MasterServId, MasterServNum, MasterZone, MasterFaction, MasterZoneFactionRet1}, MergeServers, Rest, [{{ZoneId, FacId}, NewGuildRank}|TempCampWarRet], NewChangeRet).


%% 更新阵营内的社团战果的服务器数据
%% 将被合服的分区、阵营、服务器id等数据更新成主服所在分区、阵营、服务器id
handle_svr_camp_war_ret_merge({_, _, _, _, MasterZoneFactionRet}, _MergeServers, [], {NewGuildRank, ChangeGuildRank}) ->
    {MasterZoneFactionRet, NewGuildRank, ChangeGuildRank};
handle_svr_camp_war_ret_merge({MasterServId, MasterServNum, MasterZone, MasterFaction, ZoneFactionCampWarRet}, MergeServers, [Guild = #camp_war_guild{}|Rest], {GuildRank, ChangeGuildRank}) ->
    #camp_war_guild{guild_id = GuildId, server_id = SvrId} = Guild,
    case lists:member(SvrId, MergeServers) of
        true ->
            NewGuild = Guild#camp_war_guild{server_id = MasterServId, server_num = MasterServNum, zone_facs = {MasterZone, MasterFaction}},
            NewZoneFactionCampWarRet = lists:keystore(GuildId, #camp_war_guild.guild_id, ZoneFactionCampWarRet, NewGuild),
            handle_svr_camp_war_ret_merge({MasterServId, MasterServNum, MasterZone, MasterFaction, NewZoneFactionCampWarRet},
             MergeServers, Rest, {GuildRank, [NewGuild|ChangeGuildRank]});
        _ ->
            handle_svr_camp_war_ret_merge({MasterServId, MasterServNum, MasterZone, MasterFaction, ZoneFactionCampWarRet},
             MergeServers, Rest, {[Guild|GuildRank], ChangeGuildRank})
    end.

calc_act(StateData, ModuleSub) ->
    #camp_war_state{extra_map = Map, cls_type = ClsType} = StateData,
    GmType    = maps:get(?CAMP_WAR_GM_TYPE, Map, normal),
    if GmType == normal -> %% 正常开启
            calc_act_status(StateData, ModuleSub);
        true -> %% gm开启
            ClsType == ?NODE_CENTER andalso mod_cgwar_ctrl:clean_data(),
            NewStateData  = ensure_zone_calc(StateData),
            NewStateData1 = ensure_guild_load(NewStateData),
            NewStateData2 = ensure_face_arena_calc(NewStateData1),
            Now = utime:unixtime(),
            LastTime = lists:sum([Time || {_, Time} <- data_camp_war:get_kv(status_time)]),
            EndTime = Now + LastTime,
            NewStateData3 = NewStateData2#camp_war_state{end_time = EndTime},
            {?CAMP_WAR_OPENING_2, NewStateData3}
    end.

calc_act_status(StateData, ModuleSub) ->
    case lib_activitycalen_api:get_first_enabled_ac_id(?MOD_CAMP_WAR, ModuleSub) of
        {ok, ActId} ->
            NewStateData  = ensure_zone_calc(StateData),
            NewStateData1 = ensure_guild_load(NewStateData),
            NewStateData2 = ensure_face_arena_calc(NewStateData1),
            calc_act_status_1(ActId, ModuleSub, NewStateData2);
        _ ->
            {StateData#camp_war_state.status, StateData}
    end.

%% 确保分区已完成
ensure_zone_calc(State) ->
    #camp_war_state{extra_map = Map} = State,
    ZoneCheckRet = maps:get(?FAC_ZONE_INIT, Map, 0),
    if ZoneCheckRet == 0 ->
            init_zone_info(State);
        true ->
            SrvZones = ets:tab2list(?ETS_FAC_SRV_ZONE),
            ZoneFacs = ets:tab2list(?ETS_FAC_ZONE_FACS),
            if SrvZones == [] orelse ZoneFacs == [] ->
                    NewMap = maps:put(?FAC_ZONE_INIT, 0, Map),
                    init_zone_info(State#camp_war_state{extra_map = NewMap});
                true ->
                    State
            end
    end.

%% 确保社团数据已正常加载
ensure_guild_load(State) ->
    #camp_war_state{extra_map = Map} = State,
    case maps:get(?FAC_GUILD_INIT, Map, 0) of
        0 ->
            init_local_guild_info(State);
        _ ->
            State
    end.

%% 确保阵营内战场已分配
ensure_face_arena_calc(State) ->
    #camp_war_state{extra_map = Map} = State,
    case maps:get(?FAC_ARENA_INIT, Map, 0) of
        0 ->
            init_fac_arena_info(State);
        _ ->
            State
    end.

%% 活动开启
calc_act_status_1(ActId, ModuleSub, State) ->
    Act = data_activitycalen:get_ac(?MOD_CAMP_WAR, ModuleSub, ActId),
    #base_ac{time_region = TimeRegion} = Act,
    {_NowDay, _} = calendar:local_time(),
    Now = utime:unixtime(),
    case ulists:find(fun
        ({{SHX, SMX}, {EHX, EMX}}) ->
            MinTime = utime:unixtime({_NowDay, {SHX, SMX, 0}}),
            MaxTime = utime:unixtime({_NowDay, {EHX, EMX, 0}}),
            MinTime =< Now andalso Now =< MaxTime
    end, TimeRegion) of
        {ok, {{_SH, _SM}, {EH, EM}}} ->
            Etime = utime:unixtime({_NowDay, {EH, EM, 0}}),
            Status = ?CAMP_WAR_OPENING_2,
            {Status, State#camp_war_state{end_time = Etime, status = Status}};
        _ ->
            {State#camp_war_state.status, State}
    end.

%%
get_zone_fac_by_svr_id(ServId) ->
    case ets:lookup(?ETS_FAC_SRV_ZONE, ServId) of
        [{_, {ZoneId, FacId}}|_] ->
            {ZoneId, FacId};
        _ ->
            {0, 0}
    end.

%% 分区重置秘籍-跨服团战功能处理
gm_reset_zone(StateData) ->
    #camp_war_state{extra_map = Map, worker_pids = PidMap} = StateData,
    IntervalRef = maps:get(?ZONE_INIT_INTERVAL, Map, undefined),
    util:cancel_timer(IntervalRef),
    NewMap = maps:put(?ZONE_INIT_INTERVAL, undefined, Map),
    [erlang:send(Pid, {stop}) || {{_ZoneId, _Faction}, Pid} <- maps:to_list(PidMap)],
    StateData#camp_war_state{extra_map = NewMap, worker_pids = #{}}.

calc_next_status_time(Now, Type) ->
    StatusTimes = data_camp_war:get_kv(status_time),
    case lists:keyfind(Type, 1, StatusTimes) of
        {_, LastTime} ->
            {LastTime, round(Now+LastTime)};
        _ -> %% 默认给个5分钟
            {300, round(Now+300)}
    end.

get_next_status_msg(?CAMP_WAR_OPENING_1) ->
    {collect_mon_stage};
get_next_status_msg(?CAMP_WAR_OPENING_2) ->
    {kill_mon_stage};
get_next_status_msg(_) ->
    error.

get_fac_guild_war_ets_data(EtsName) ->
    List = ets:tab2list(EtsName),
    List.


%% 筛选出符合条件的社团参与活动
init_local_guild_info_do([], _SrvZoneList, Acc) -> Acc;
init_local_guild_info_do([Guild = [GuildId, GuildName, GuildFlag, GuildPower, ChiefInfoBin, Score, ServId, ServerNum, _OldZoneId, _OldFacId]|Rest], SrvZoneList, Acc) ->
    case lists:keyfind(ServId, 1, SrvZoneList) of
        {_, {ZoneId, FacId}} ->
            ChiefInfo = util:bitstring_to_term(ChiefInfoBin),
            GuildInfo = #local_gwar_info{
                guild_id = GuildId, server_id = ServId, server_num = ServerNum,
                guild_name = GuildName, score = Score, guild_flag = GuildFlag,
                guild_power = GuildPower, chief_info = ChiefInfo, zone_id = ZoneId, fac_id = FacId
            },
            case lists:keyfind({ZoneId, FacId}, 1, Acc) of
                {_, FacGuildInfos} ->
                    case lists:keyfind(GuildId, #local_gwar_info.guild_id, FacGuildInfos) of
                        #local_gwar_info{} ->
                            init_local_guild_info_do(Rest, SrvZoneList, Acc);
                        _ ->
                            NewAcc = lists:keystore({ZoneId, FacId}, 1, Acc, {{ZoneId, FacId}, [GuildInfo|FacGuildInfos]}),
                            init_local_guild_info_do(Rest, SrvZoneList, NewAcc)
                    end;
                _ ->
                    NewAcc = lists:keystore({ZoneId, FacId}, 1, Acc, {{ZoneId, FacId}, [GuildInfo]}),
                    init_local_guild_info_do(Rest, SrvZoneList, NewAcc)
            end;
        _ ->
            ClsType = config:get_cls_type(),
            if ClsType =/= ?NODE_GAME -> 
                    ?ERR("guild info error ~p ~p ~p", [Guild, ServId, SrvZoneList]);
                true ->
                    skip
            end,
            init_local_guild_info_do(Rest, SrvZoneList, Acc)
    end.


%% 开启阵营战场进程
start_fac_guild_room(ClsType, PidMap) ->
    %% 分区所有阵营
    ZoneFacs   = get_fac_guild_war_ets_data(?ETS_FAC_ZONE_FACS),
    %% 所有阵营管理进程
    NewPidMaps =
     lists:foldl(fun({ZoneId, FacIds}, TempPidMap) ->
        lists:foldl(fun(FacId, TempPidMap1) ->
            case camp_war_worker:start_link([ClsType, ZoneId, FacId, normal]) of
                {ok, Pid}               -> maps:put({ZoneId, FacId}, Pid, TempPidMap1);
                {already_started, Pid}  -> maps:put({ZoneId, FacId}, Pid, TempPidMap1);
                _                       -> TempPidMap1
            end
        end, TempPidMap, FacIds)
    end, PidMap, ZoneFacs),
    NewPidMaps.

%% 上载游戏服社团数据
update_guild_info({ZoneId, FacId, ServId}, ServerNum, GuildAdd) ->
    GuildInfoFormat = to_local_gwar_info({ZoneId, FacId, ServId}, ServerNum, GuildAdd),
    db_update_guild_info(GuildInfoFormat),
    NewGuildInfo = case ets:lookup(?ETS_FAC_LOCAL_GWAR_INFO, {ZoneId, FacId}) of
        [{_, OldGuildInfo}|_] ->
            update_guild_info_do(GuildInfoFormat, OldGuildInfo);
        _ ->
            GuildInfoFormat
    end,
    % ?ERR("upload ~p", [NewGuildInfo]),
    ets:insert(?ETS_FAC_LOCAL_GWAR_INFO, [{{ZoneId, FacId}, NewGuildInfo}]),
    ok.

update_guild_info_do([], GuildInfo) -> GuildInfo;
update_guild_info_do([Guild|Rest], OldGuildInfo) ->
    #local_gwar_info{guild_id = GuildId} = Guild,
    NewGuildInfo = lists:keystore(GuildId, #local_gwar_info.guild_id, OldGuildInfo, Guild),
    update_guild_info_do(Rest, NewGuildInfo).


to_local_gwar_info({ZoneId, FacId, ServId}, ServerNum, GuildInfo) ->
    lists:foldl(fun(Guild, Acc) ->
        #guild_war_ret{
            guild_id = GuildId, guild_name = GuildName, score = Score, guild_flag = GuildFlag,
            guild_power = GuildPower, chief_info = ChiefRecPic
        } = Guild,
        [#local_gwar_info{
            guild_id = GuildId, guild_name = GuildName, guild_flag = GuildFlag, score = Score,
            server_id = ServId, server_num = ServerNum, zone_id = ZoneId, fac_id = FacId,
            guild_power = GuildPower, chief_info = ChiefRecPic
            }|Acc]
    end, [], GuildInfo).

db_update_guild_info(GuildInfoFormat) ->
    SqlList = [
    io_lib:format(?SQL_BATCH_REPLACE_LOCAL_GUILD_SCORE_VAL,
        [GuildId, GuildName, GuildFlag, GuildPower, util:term_to_bitstring(ChiefInfo), Score, ServId, ServerNum, ZoneId, FacId])
        || #local_gwar_info{
            guild_id = GuildId, guild_name = GuildName, guild_flag = GuildFlag,
            score = Score, server_id = ServId, server_num = ServerNum, zone_id = ZoneId, fac_id = FacId,
            guild_power = GuildPower, chief_info = ChiefInfo
            } <- GuildInfoFormat],
    SQL = io_lib:format(?SQL_BATCH_REPLACE_LOCAL_GUILD_SCORE, [string:join(SqlList, ",")]),
    SqlList =/= [] andalso db:execute(SQL),
    ok.

db_update_fact_guild_rank(ZoneId, FacId, GuildRank) ->
    % {_, SortedGuilds} = lists:foldl(fun(Guild, {Index, Acc}) ->
    %     {Index+1, [{Index, Guild}|Acc]}
    % end, {1, []}, GuildRank),
    spawn_link(fun() -> db_update_fact_guild_rank_do(GuildRank, ZoneId, FacId) end),
    ok.

db_update_fact_guild_rank_do([], _, _) ->
    ok;
db_update_fact_guild_rank_do(SortedGuilds, ZoneId, FacId) ->
    GuildLen = length(SortedGuilds),
    if GuildLen > 20 ->
            {DbList, RestGuilds} = ulists:sublist(SortedGuilds, 20),
            DbGuilds = [[GuildId, ZoneId, FacId, SvrId, SvrNum, GuildName, Hurt, GuildPower, util:term_to_bitstring(ChiefInfo)] ||
             #camp_war_guild{guild_id = GuildId, guild_name = GuildName, guild_power = GuildPower, server_id = SvrId, server_num = SvrNum, hurt = Hurt, chief_info = ChiefInfo} <- DbList],
            timer:sleep(urand:rand(100, 200)),
            db:insert_batch(?REPLACE_INTO_CAMP_WAR_RESULT, DbGuilds),
            db_update_fact_guild_rank_do(RestGuilds, ZoneId, FacId);
        true ->
            DbGuilds = [[GuildId, ZoneId, FacId, SvrId, SvrNum, GuildName, Hurt, GuildPower, util:term_to_bitstring(ChiefInfo)] ||
             #camp_war_guild{guild_id = GuildId, guild_name = GuildName, guild_power = GuildPower, server_id = SvrId, server_num = SvrNum, hurt = Hurt, chief_info = ChiefInfo} <- SortedGuilds],
            db:insert_batch(?REPLACE_INTO_CAMP_WAR_RESULT, DbGuilds)
    end.

db_update_camp_war_ret_when_merge([]) ->
    ok;
db_update_camp_war_ret_when_merge(ChangeRet = [_|_]) ->
    DbGuilds = [[GuildId, ZoneId, FacId, SvrId, SvrNum, GuildName, Hurt, GuildPower, util:term_to_bitstring(ChiefInfo)] ||
     #camp_war_guild{
        guild_id = GuildId, guild_name = GuildName, guild_power = GuildPower, 
        server_id = SvrId, server_num = SvrNum, hurt = Hurt, chief_info = ChiefInfo,
        zone_facs = {ZoneId, FacId}} <- ChangeRet],
    db:insert_batch(?REPLACE_INTO_CAMP_WAR_RESULT, DbGuilds),
    ok.

%% 阵营内战场分配
%% 先筛选开服超过5天的服,再根据百团积分分配战场
calc_guild_arena_info(GuildInfo, _ServOpenTime) ->
    % TarTime = get_act_next_start_time(utime:unixtime()),
    % FilterGuildInfo = lists:filtermap(
    %     fun(#local_gwar_info{server_id = ServId}) ->
    %         case lists:keyfind(ServId, 1, ServOpenTime) of
    %             {_, OpenTime} ->
    %                 case utime:day_span(TarTime, OpenTime) >= 5 of
    %                     true -> true;
    %                     _    -> false
    %                 end;
    %             _ -> false
    %         end
    % end, GuildInfo),
    SortedGuildInfo = lists:sort(fun(#local_gwar_info{score = S1}, #local_gwar_info{score = S2}
        ) ->  S1 >= S2
    end, GuildInfo),
    calc_guild_arena_info_do(SortedGuildInfo, 1, []).

calc_guild_arena_info_do([], _ArenaIndex, Acc) ->
    lists:reverse(Acc);
calc_guild_arena_info_do(GuildInfo, ArenaIndex, Acc) ->
    {ArenaGuilds, LessGuildInfo} = camp_war_api:list_head_n(GuildInfo, 3),
    NewAcc = update_guild_arena(ArenaGuilds, ArenaIndex, Acc),
    calc_guild_arena_info_do(LessGuildInfo, ArenaIndex+1, NewAcc).

update_guild_arena(Guilds, ArenaId, List) ->
    GuildServs =
    lists:map(fun(#local_gwar_info{guild_id = GuildId, server_id = ServId}) ->
        {GuildId, ServId}
    end, Guilds),
    lists:keystore(ArenaId, 1, List, {ArenaId, GuildServs}).

% 统计各阵营前一
calc_upload_data(CampWarRet) ->
    TopData = calc_upload_data_1(CampWarRet, []),
    TopData.

calc_upload_data_1([], TopData) ->
    TopData;
calc_upload_data_1([{{ZoneId, FacId}, GuildRank}|Rest], TopData) ->
    [TopGuild|_] = GuildRank,
    GuildData = trans_data(ZoneId, FacId, TopGuild),
    NewTopData =
    case lists:keyfind(ZoneId, 1, TopData) of
        {_, ZoneTopData} ->
            lists:keystore(ZoneId, 1, TopData, {ZoneId, [GuildData|ZoneTopData]});
        _ ->
            lists:keystore(ZoneId, 1, TopData, {ZoneId, [GuildData]})
    end,
    calc_upload_data_1(Rest, NewTopData).

trans_data(ZoneId, FactId, Guild)->
    #camp_war_guild{
        guild_id = Gid, guild_name = GName, guild_power = GPower,
        chief_info = ChiefInfo, server_id = SerID, server_num = SNum
    } = Guild,
    case ChiefInfo of
        #rec_picture{id = ChiefId, name = ChiefName, power = CPower} -> ok;
        _ ->
            ChiefId = 0, ChiefName = <<>>, CPower = 0
    end,
    #cgw_guild_info{
        guild_id = Gid, guild_name = GName, guild_power = GPower,
        chief_id = ChiefId, chief_name = ChiefName, chief_power = CPower,
        server_id = SerID, server_num = SNum, zone_id = ZoneId, fact_id = FactId
    }.

%% 获取下次活动当天的某个时间
% get_act_next_start_time(Now) ->
%     % Now = utime:unixtime(),
%     case lib_activitycalen_api:get_time(?MOD_CAMP_WAR, 1) of
%         [[{_SH, _SM}|_]|_] -> %% 今天的活动
%             Now;
%         _ ->
%             Week = utime:day_of_week(),
%             #base_ac{week = CfgWeeks} = data_activitycalen:get_ac(?MOD_CAMP_WAR, 1, 1),
%             %% 距离下次活动天数
%             LastDay            = camp_war_api:get_next_day(Week, CfgWeeks),
%             {{Y, M, D}, _}     = calendar:local_time(),
%             %% 活动当天日期
%             {TarY, TarM, TarD} = utime:get_before_day({Y, M, D}, LastDay, 1),
%             %% 活动当天时间 时分秒无实际意义
%             TarTime            = utime:unixtime({{TarY, TarM, TarD}, {12, 0, 0}}),
%             TarTime
%     end.

calc_today_act(State) ->
    #camp_war_state{extra_map = Map, cls_type = ClsType} = State,
    ModuleSub = ?IF(ClsType == ?NODE_CENTER, ?CLS_ACT_MOD, ?LOC_ACT_MOD),
    case lib_activitycalen_api:get_time(?MOD_CAMP_WAR, ModuleSub) of
        [{_SH, _SM}|_] -> %% 今天的活动
            NewMap = maps:put(?IS_TODAY_ACT, 1, Map),
            State#camp_war_state{extra_map = NewMap};
        _ ->
            NewMap = maps:put(?IS_TODAY_ACT, 0, Map),
            State#camp_war_state{extra_map = NewMap}
    end.

clear_arena_worker(_Pid, StateData) ->
    StateData.

get_guild_arena_info(ZoneId, FacId, GuildId, RankType, PageSize, PageNum) ->
    case ets:lookup(?ETS_FAC_ARENA_INFO, {ZoneId, FacId}) of
        [{_, _, ArenaInfos}|_] -> %% [{arena_id, [{guild_id,server_id}|_]}]
            if
                RankType == 1 -> %% 所有社团
                    TotalPage = calc_page(PageSize, PageNum, ArenaInfos),
                    TargetGuilds = get_guild_arena_info_by_page(PageSize, PageNum, ArenaInfos),
                    GuildList = pack_guild_arena_info({ZoneId, FacId}, TargetGuilds),
                    {TotalPage, GuildList};
                RankType == 0 -> %% 自己社团
                    TotalPage = calc_page(PageSize, PageNum, ArenaInfos),
                    TargetGuilds = get_person_guild_arena_info(GuildId, ArenaInfos),
                    GuildList = pack_guild_arena_info({ZoneId, FacId}, TargetGuilds),
                    {TotalPage, GuildList};
                true ->
                    {0, []}
            end;
        _ ->
            {0, []}
    end.

get_person_guild_arena_info(GuildId, ArenaInfos) ->
    lists:filtermap(fun({_ArenaId, Guilds}) ->
        case lists:keymember(GuildId, 1, Guilds) of
            true ->
                true;
            _ ->
                false
        end
    end, ArenaInfos).

calc_page(_PageSize, PageNum, ArenaInfos) ->
    Length = lists:foldl(fun({_ArenaId, Guilds}, Acc) ->
        Acc + length(Guilds)
    end, 0, ArenaInfos),
    if PageNum == 0 ->
            Length;
        true ->
            umath:ceil(Length/PageNum)
    end.

%% PageSize 页码大小
%% PageNum  第几页
get_guild_arena_info_by_page(PageSize, PageNum, ArenaInfos) ->
    SortedArenaInfos = lists:keysort(1, ArenaInfos),
    %% 起始位置
    StartLen = round(max(0, PageNum-1)*PageSize) + 1,
    %% 结束位置
    EndLen   = PageNum*PageSize,
    TotalNum = length(SortedArenaInfos),
    if TotalNum == 0 ->
            [];
        StartLen == 0 ->
            SubArenaInfos = lists:sublist(SortedArenaInfos, 1, max(0, EndLen)),
            SubArenaInfos;
        StartLen > TotalNum+1 ->
            [];
        true ->
            SubArenaInfos = lists:sublist(SortedArenaInfos, StartLen, max(0, EndLen-StartLen)),
            SubArenaInfos
    end.

pack_guild_arena_info({ZoneId, FacId}, Guilds) ->
    case ets:lookup(?ETS_FAC_LOCAL_GWAR_INFO, {ZoneId, FacId}) of
        [{_, FacGuildInfos}|_] -> ok;
        _  -> FacGuildInfos = []
    end,
    lists:foldl(fun({ArenaId, GuildInfos}, Acc) ->
        GuildData = [begin
            case lists:keyfind(GuildId, #local_gwar_info.guild_id, FacGuildInfos) of
                #local_gwar_info{guild_name = GuildName, guild_flag = GuildFlag, server_num = ServerNum} ->
                    {GuildId, GuildName, GuildFlag, ServerNum};
                _ ->
                    {GuildId, <<>>, 0, 0}
            end
        end|| {GuildId, _ServId} <- GuildInfos],
        [{ArenaId, GuildData}|Acc]
    end, [], Guilds).

%% 获取社团简要信息
get_short_guild_info({ZoneId, FacId}, GuildId) ->
    case ets:lookup(?ETS_FAC_LOCAL_GWAR_INFO, {ZoneId, FacId}) of
        [{_, GuildList}|_] ->
            case lists:keyfind(GuildId, #local_gwar_info.guild_id, GuildList) of
                #local_gwar_info{chief_info = ChiefInfo, guild_power = GuildPower} ->
                    [ChiefInfo, GuildPower];
                _ ->
                    [[], 0]
            end;
        _ ->
            [[], 0]
    end.

%% 分发消息给阵营管理进程
broad_fac_worker(PidMap, cast, Msg) ->
    lists:map(fun({_, Pid}) -> camp_war_worker:cast(Pid, Msg) end, maps:to_list(PidMap)),
    ok;
broad_fac_worker(PidMap, info, Msg) ->
    lists:map(fun({_, Pid}) -> camp_war_worker:info(Pid, Msg) end, maps:to_list(PidMap)),
    ok.

broad_target_fac_worker(cast, Pids = [_|_], Msg) ->
    lists:map(fun(Pid) -> camp_war_worker:cast(Pid, Msg) end, Pids),
    ok;
broad_target_fac_worker(cast, {ZoneId, FacId}, Msg) ->
    camp_war_worker:cast({ZoneId, FacId}, Msg);

broad_target_fac_worker(cast, ServId, Msg) when is_integer(ServId) ->
    case ets:lookup(?ETS_FAC_SRV_ZONE, ServId) of
        [{_, {ZoneId, FacId}}|_] ->
            broad_target_fac_worker(cast, {ZoneId, FacId}, Msg);
        _ ->
            ok
    end;

broad_target_fac_worker(_CastType, Des, Msg) ->
    ?ERR("broad_target_fac_worker error des ~p msg ~p", [Des, Msg]),
    ok.

