%%%===================================================================
%%% @author zmh
%%% @doc 跨服 服务器分区
%%% 跨服中心管理进程
%%% @end
%%%===================================================================
%%  说明 : 1. 支持后台修改编辑分区划定，游戏停服更新后会生效
-module(clusters_zone).
-behaviour(gen_server).
-include("server.hrl").
-include("common.hrl").
-include("clusters_zone.hrl").
-include("def_fun.hrl").
-include("def_gen_server.hrl").

%% API
-export([start_link/1, stop/1,
        apply_cast_all_server/5, apply_cast_all_server/6,
        apply_cast_all_zone/4, apply_cast_all_zone/5,
        apply_cast_center/4, apply_cast_center/5, do_apply_cast_center/6,
        apply_call_center/4, apply_call_center/5, apply_call_center/6, do_apply_call_center/6,
        server_connected/5, fix_all_zone/1, call_mgr/2, call_mgr/3, cast_mgr/2
    ]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-ifdef(DEV_SERVER).
-define(RECALC_ZONE_TIME, 10000).
-else.
-define(RECALC_ZONE_TIME, 600000).      %% 定时分区计算
-endif.
%% 分区启动服务
-define(ZONE_START_KEY(ZoneType, ZoneId), {?MODULE, zone_start_key, ZoneType, ZoneId}).

start_link(ZoneType) ->
    ProcessName = misc:zone_process_name(ZoneType),
    gen_server:start_link({global, ProcessName}, ?MODULE, [ZoneType, ProcessName], []).

stop(ZoneType)->
    cast_mgr(ZoneType, stop).

%% 跨服中心分发到对应分区所有服执行MFA
apply_cast_all_server(ModuleId, ZoneId, M, F, A)->
    apply_cast_all_server(ModuleId, 0, ZoneId, M, F, A).

apply_cast_all_server(ModuleId, SubModuleId, ZoneId, M, F, A)->
    ZoneType = data_clusters_zone:get_zone_type(ModuleId, SubModuleId),
    cast_mgr(ZoneType, {apply_cast_all_server, ZoneId, M, F, A}).

%% 跨服中心分发到所有跨服分区执行MFA
apply_cast_all_zone(ModuleId, M, F, A)->
    apply_cast_all_zone(ModuleId, 0, M, F, A).

apply_cast_all_zone(ModuleId, SubModuleId, M, F, A)->
    ZoneType = data_clusters_zone:get_zone_type(ModuleId, SubModuleId),
    cast_mgr(ZoneType, {apply_cast_all_zone, M, F, A}).

%% 本地 -> 跨服中心 Msg = [{start, args}]
%% 添加ZoneId作为A的第一个参数
apply_cast_center(ModuleId, M, F, A) ->
    apply_cast_center(ModuleId, 0, M, F, A).

apply_cast_center(ModuleId, SubModuleId, M, F, A) ->
    ServerId = config:get_server_id(),
    clusters_node:apply_cast(?MODULE, do_apply_cast_center, [ModuleId, SubModuleId, ServerId, M, F, A]).

do_apply_cast_center(ModuleId, SubModuleId, ServerId, M, F, A) ->
    ZoneType = data_clusters_zone:get_zone_type(ModuleId, SubModuleId),
    ZoneId = clusters_zone_api:get_zone(ZoneType, ServerId),
    apply(M, F, [ZoneId|A]).

%% 本地 -> 跨服中心 Msg = [{start, args}]
%% 添加ZoneId作为A的第一个参数
apply_call_center(ModuleId, M, F, A) ->
    apply_call_center(ModuleId, 0, M, F, A, 5000).

apply_call_center(ModuleId, M, F, A, Timeout) ->
    apply_call_center(ModuleId, 0, M, F, A, Timeout).

apply_call_center(ModuleId, SubModuleId, M, F, A, _Timeout) ->
    ServerId = config:get_server_id(),
    clusters_node:apply_call(?MODULE, do_apply_call_center, [ModuleId, SubModuleId, ServerId, M, F, A]).

do_apply_call_center(ModuleId, SubModuleId, ServerId, M, F, A) ->
    ZoneType = data_clusters_zone:get_zone_type(ModuleId, SubModuleId),
    ZoneId = clusters_zone_api:get_zone(ZoneType, ServerId),
    apply(M, F, [ZoneId|A]).

%% 新连接的游戏申请区域
server_connected(ZoneType, ServerId, Time, WorldLv, MergeSerIds) ->
    cast_mgr(ZoneType, {server_connected, ServerId, Time, WorldLv, MergeSerIds}).

%% 修正所有的区域(一般不允许这样操作)
fix_all_zone(ZoneType)->
    cast_mgr(ZoneType, fix_all_zone).

%% 跨服中心分发到管理进程
call_mgr(ZoneType, Msg) ->
    call_mgr(ZoneType, Msg, 5000).

call_mgr(ZoneType, Msg, TimeOut) ->
    gen_server:call(misc:get_zone_process(ZoneType), Msg, TimeOut).

cast_mgr(ZoneType, Msg) ->
    gen_server:cast(misc:get_zone_process(ZoneType), Msg).

init(Args) ->
    ?DO_INIT(Args).
handle_call(Request, From, State) ->
    ?DO_HANDLE_CALL(Request, From, State).
handle_cast(Msg, State) ->
    ?DO_HANDLE_CAST(Msg, State).
handle_info(Info, State) ->
    ?DO_HANDLE_INFO(Info, State).
terminate(Reason, State) ->
    ?DO_TERMINATE(Reason, State).
code_change(OldVsn, State, Extra) ->
    ?DO_CODE_CHANGE(OldVsn, State, Extra).

do_init([ZoneType, ProcessName]) ->
    process_flag(priority, high),
    misc:register(global, ProcessName, self()),
    {ok, State} = do_init_core(#clusters_zone{}, ZoneType),
    {ok, State}.

%% 通用回调
do_handle_call({mod, Module, Method, Args}, _From, State)->
    Result = Module:Method(Args, State),
    {reply, Result, State};

%% 获取分区平均世界等级
do_handle_call({get_zone_average_lv, ZoneId, DefaultLv}, _From, State)->
    List = [X#zone_base.world_lv ||X <- State#clusters_zone.zones, X#zone_base.zone == ZoneId],
    Length = length(List),
    Result = ?IF(Length>0, round(lists:sum(List) / Length), DefaultLv),
    {reply, Result, State};

%% 获取分区服务器ids
do_handle_call({get_zone_server_ids, ZoneId, DefaultServerIds}, _From, State)->
    List = [X#zone_base.server_id ||X <- State#clusters_zone.zones, X#zone_base.zone == ZoneId],
    Result = ?IF(List == [], DefaultServerIds, List),
    {reply, Result, State};

%% 获取分区服务器信息列表
do_handle_call({get_zone_server_infos, ZoneId, DefaultServerInfos}, _From, State)->
    List = [X ||X <- State#clusters_zone.zones, X#zone_base.zone == ZoneId],
    Result = ?IF(List == [], DefaultServerInfos, List),
    {reply, Result, State};

%% 获取分区类型的分区最大值id, 即分区数量
do_handle_call({get_zone_type_max_id, DefaultNum}, _From, State) ->
    Result = ?IF(State#clusters_zone.next > 1, State#clusters_zone.next - 1, DefaultNum),
    {reply, Result, State};

do_handle_call(_Request, _From, State) ->
    {reply, ok, State}.

%% 通用回调
do_handle_cast({mod, Module, Method, Args}, State)->
    NewState = Module:Method(Args, State),
    {noreply, NewState};

%% 更新分区服务器世界等级
do_handle_cast({update_world_lv, ServerId, WorldLv}, State)->
    #clusters_zone{zone_type = ZoneType, zones = Zones} = State,
    case lists:keyfind(ServerId, #zone_base.server_id, Zones) of
        #zone_base{} = ZoneBase ->
            NewZoneBase = ZoneBase#zone_base{world_lv = WorldLv},
            NewZones = lists:keystore(ServerId, #zone_base.server_id, Zones, NewZoneBase),
            db_replace_into_zone(ZoneType, [NewZoneBase]);
        _ -> NewZones = Zones
    end,
    {noreply, State#clusters_zone{ zones = NewZones}};

%% 发送分区多有服执行
do_handle_cast({apply_cast_all_server, ZoneId, M, F, A}, State)->
    [clusters_center:apply_cast(X#zone_base.server_id, M, F, A) ||
        X <- State#clusters_zone.zones, X#zone_base.zone == ZoneId],
    {noreply, State};

%% 发送分区执行
do_handle_cast({apply_cast_all_zone, M, F, A}, State)->
    Zones = State#clusters_zone.zones,
    ZoneIds = lists:usort([ZoneBase#zone_base.zone||ZoneBase<-Zones]),
    Fun = fun(ZoneId) ->
            case catch apply(M, F, [ZoneId|A]) of
                {'EXIT', Reason} -> ?ERR("apply_cast_all_zone error:~n~p,~p,~p,~p~n~p~n", [ZoneId, M, F, A, Reason]);
                _ -> skip
            end
    end,
    [Fun(ZoneId) || ZoneId <- ZoneIds],
    {noreply, State};

%% 游戏服链接跨服中心成功，申请加入分区
do_handle_cast({server_connected, ServerId, Time, WorldLv, MergeSerIds}, State)->
    {ok, NewState} = do_server_connected(ServerId, Time, WorldLv, MergeSerIds, State),
    {noreply, NewState};

%% 重新整理分区列表:所有数据都重新划分,但是分区的功能数据不做处理
do_handle_cast(fix_all_zone, State)->
    #clusters_zone{zone_type = ZoneType, zones=Zones} = State,
    {NewZones, NewNext} = calc_zone(ZoneType, [ Zone#zone_base{zone = 0} || Zone <- Zones ], 1),
    F = fun(#zone_base{zone=Zone, merge_ids=MSerIds}) ->
            [ets:insert(?ETS_ZONE_ROUTE, #zone_route{key = {ZoneType, ServerId}, zone = Zone}) || ServerId <- MSerIds]
    end,
    lists:map(F, NewZones),
    {noreply, State#clusters_zone{zones=NewZones, next=NewNext}};

%% 停止进程
do_handle_cast(stop, State)->
    {stop, normal, State};
do_handle_cast(_Msg, State) ->
    {noreply, State}.

do_handle_info({start_zone, ZoneIdList}, State) ->
    #clusters_zone{zone_type = ZoneType}=State,
    [begin
                clusters_zone_base:start(ZoneType, ZoneId),
                put(?ZONE_START_KEY(ZoneType, ZoneId), 1)
        end||ZoneId<-ZoneIdList],
    {ok, State};
do_handle_info(recalc_zone, State) ->
    #clusters_zone{zone_type = ZoneType, zones = Zones, next = Next, ref = ZoneRef}=State,
    util:cancel_timer(ZoneRef),
    {NewZones, NewNext} = calc_zone(ZoneType, Zones, Next),
    %% 发起同步API
    sync_all_zone_func(ZoneType, NewNext, NewZones),
    %% 标记为已分区操作
    {noreply, State#clusters_zone{zones = NewZones, next = NewNext, is_zone = 1, ref = undefined}};
do_handle_info(_Info, State) ->
    {noreply, State}.
do_terminate(_Reason, _State) ->
    ok.
do_code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%% ---------------------------------------------------------------------------
%%% Internal functions
%% ---------------------------------------------------------------------------


%% ---------------------------------------------------------------------------
%% @doc 初始化已有分区
-spec do_init_core(State, ZoneType) -> {ok, NewState} when
    State           :: #clusters_zone{},    %% State
    ZoneType        :: integer(),           %% 分区类型
    NewState        :: #clusters_zone{}.    %% NewState
%% ---------------------------------------------------------------------------
do_init_core(State, ZoneType) ->
    %% 创建分区路由信息表
    EtsZoneRouteArgs = [named_table, public, set, {keypos, #zone_route.key}, {read_concurrency, true}],
    case ets:info(?ETS_ZONE_ROUTE) of
        undefined -> ets:new(?ETS_ZONE_ROUTE, EtsZoneRouteArgs);
        _ -> skip
    end,
    %% 加载已有的分区数据
    {Zones, Next} = load_zones(ZoneType, 1),
    %% 等待游戏服的连接
    ZoneRef = erlang:send_after(?RECALC_ZONE_TIME, self(), recalc_zone),
    {ok, State#clusters_zone{zone_type = ZoneType, zones = Zones, next = Next, ref = ZoneRef, is_zone = 0}}.

%% 加载已有的分区数据
load_zones(ZoneType, Num)->
    %% 加载分区数据
    {Zones, Next} = case db_select_server_zone(ZoneType) of
        [] -> {[], Num};
        ZoneBases when is_list(ZoneBases)-> make_zone(ZoneType, ZoneBases, [], Num);
        _ -> {[], Num}
    end,

    %% 分区启动服务
    F = fun(#zone_base{zone = ZoneId}, ZoneIdList) ->
            case {ZoneId>0, lists:member(ZoneId, ZoneIdList)} of
                {true, false} -> [ZoneId|ZoneIdList];
                _ -> ZoneIdList
            end
    end,
    ZoneIdList = lists:sort(lists:foldl(F, [], Zones)),
    % [clusters_zone_base:start(ZoneType, ZoneId)||ZoneId<-ZoneIdList],
    self() ! {start_zone, ZoneIdList},
    {Zones, Next}.

make_zone(_ZoneType, [], Zones, Num)->
    {Zones, Num};
make_zone(ZoneType, [[ServerId, Zone, Time, WorldLv, MergeSrvIdsStr]|ZoneBases], Zones, Num)->
    MergeSrvIds = case util:bitstring_to_term(MergeSrvIdsStr) of
        List when is_list(List) -> List;
        _ -> []
    end,
    ZoneBase = #zone_base{
        server_id = ServerId,
        zone = Zone,
        time = Time,
        world_lv = WorldLv,
        merge_ids=MergeSrvIds
    },
    NewNum = max(Zone+1, Num),
    if
        Zone == 0 -> skip;
        true -> save_ets_zone_route(ZoneType, [ZoneBase])
    end,
    make_zone(ZoneType, ZoneBases, [ZoneBase|Zones], NewNum).

%% 内存写入
save_ets_zone_route(ZoneType, [H|T]) ->
    #zone_base{server_id = ServerId, zone = Zone, merge_ids = MergeIds} = H,
    %% 合服id添加到分区表
    Fun = fun(MegId) ->
            Key = {ZoneType, MegId},
            ets:insert(?ETS_ZONE_ROUTE, #zone_route{key = Key, zone = Zone})
    end,
    [Fun(MId) || MId <- MergeIds],
    RouteKey = {ZoneType, ServerId},
    ets:insert(?ETS_ZONE_ROUTE, #zone_route{key = RouteKey, zone = Zone}),
    save_ets_zone_route(ZoneType, T);
save_ets_zone_route(_ZoneType, _) ->
    ok.

%% ---------------------------------------------------------------------------
%% @doc 划定分区
-spec calc_zone(ZoneType, AllZones, CurrentZoneId) -> {NewZones, NextZoneId} when
    ZoneType        :: integer(),           %% 分区类型
    AllZones        :: [#zone_base{}],      %% 原分区列表
    CurrentZoneId   :: integer(),           %% 原最后分区id
    NewZones        :: [#zone_base{}],      %% 新的分区列表
    NextZoneId      :: integer().           %% 新的最后分区id
%% ---------------------------------------------------------------------------
calc_zone(_ZoneType, [], CurrentZoneId) -> {[], CurrentZoneId};
calc_zone(ZoneType, AllZones, CurrentZoneId)->
    MaxServerNum = ?ZONE_MAX_SERVER_NUM(ZoneType),
    %% 未分区的游戏服
    case [ Z || Z <- AllZones, Z#zone_base.zone == 0 ] of
        [] -> {AllZones, CurrentZoneId};
        UnZones ->
            %% 找出上一分区
            LastZoneId = max(CurrentZoneId - 1, 1),
            LastZones = [ Z || Z <- AllZones, Z#zone_base.zone == LastZoneId ],
            LenLastZone = length(LastZones),
            %% 排序所有未分区的服
            SortUnZones = lists:keysort(#zone_base.time, UnZones),
            if
                LenLastZone < MaxServerNum -> %% 上一区未满
                    %% 从n个开始加入MaxServerNum-n个服
                    for_calc_new_zone(ZoneType, SortUnZones, LastZoneId, AllZones, [], LenLastZone);
                true ->
                    for_calc_new_zone(ZoneType, SortUnZones, CurrentZoneId, AllZones, [], 0)
            end
    end.

%% 对未分区的服进行分区
for_calc_new_zone(ZoneType, [], CurrentZoneId, Zones, OneZones, Count)->
    if
        OneZones == [] -> skip;
        true -> save_zones(ZoneType, CurrentZoneId, OneZones)
    end,
    %% 计算下一个分区id
    Next = if
        Count == 0 -> CurrentZoneId;
        true -> CurrentZoneId + 1
    end,
    {Zones, Next};
for_calc_new_zone(ZoneType, [UnZone|SortUnZones], CurrentZoneId, AllZones, OneZones, Count)->
    MaxServerNum = ?ZONE_MAX_SERVER_NUM(ZoneType),
    NewUnZone = UnZone#zone_base{zone = CurrentZoneId},
    NewOneZones = [NewUnZone|OneZones],
    NewAllZones = lists:keystore(UnZone#zone_base.server_id, #zone_base.server_id, AllZones, NewUnZone),
    NewCount = Count + 1,
    if
        %% 服数大于等于默认单区服数，开启新的分区id
        NewCount >= MaxServerNum ->
            save_zones(ZoneType, CurrentZoneId, NewOneZones),
            for_calc_new_zone(ZoneType, SortUnZones, CurrentZoneId+1, NewAllZones, [], 0);
        true ->
            %% 持续分区Id
            for_calc_new_zone(ZoneType, SortUnZones, CurrentZoneId, NewAllZones, NewOneZones, NewCount)
    end.

save_zones(_ZoneType, _ZoneId, [])-> ignore;
save_zones(ZoneType, ZoneId, Zones)->
    save_ets_zone_route(ZoneType, Zones),
    db_replace_into_zone(ZoneType, Zones),
    %% 分区启动服务
    case get(?ZONE_START_KEY(ZoneType, ZoneId)) of
        1 -> skip;
        _ ->
            clusters_zone_base:start(ZoneType, ZoneId),
            put(?ZONE_START_KEY(ZoneType, ZoneId), 1)
    end.

%% ---------------------------------------------------------------------------
%% @doc 游戏服链接跨服中心成功，申请加入分区
-spec do_server_connected(ServerId, Time, WorldLv, MergeSerIds, State) -> {ok, NewState} when
    ServerId        :: integer(),           %% 服务器id
    Time            :: integer(),           %% 开服时间
    WorldLv         :: integer(),           %% 世界等级
    MergeSerIds     :: list(),              %% 被合服服务器id列表
    State           :: #clusters_zone{},    %% State
    NewState        :: #clusters_zone{}.    %% NewState
%% ---------------------------------------------------------------------------
do_server_connected(ServerId, Time, WorldLv, MergeSerIds, State) ->
    #clusters_zone{zone_type = ZoneType, zones = Zones, next = Next} = State,
    MaxServerNum = ?ZONE_MAX_SERVER_NUM(ZoneType),
    case lists:keyfind(ServerId, #zone_base.server_id, Zones) of
        #zone_base{zone = Z, world_lv = OldWorldLv, merge_ids=OldMergeSerIds} = OldZone when Z /= 0 ->
            if
                State#clusters_zone.is_zone == 0 -> skip;
                true -> sync_zone_func(ZoneType, OldZone, 60)
            end,
            %% 老区重连，则有可能已经合服，需做合服处理
            ?PRINT("server_connected:have zone, zone_type:~w,server_id:~w,zone:~w!~n", [ZoneType, ServerId, Z]),
            FixZones = merge_fix(ZoneType, ServerId, lists:delete(ServerId, MergeSerIds), Zones, Z),
            %% 更新世界等级 或 者合服ids
            MergeZones = case OldWorldLv =/= WorldLv orelse OldMergeSerIds=/=MergeSerIds of
                true ->
                    NewZoneBase = OldZone#zone_base{world_lv = WorldLv, merge_ids=MergeSerIds},
                    save_zones(ZoneType, Z, [NewZoneBase]),
                    lists:keystore(ServerId,#zone_base.server_id, FixZones, NewZoneBase);
                false -> FixZones
            end,
            NewState = State#clusters_zone{zones = MergeZones};
        _ ->
            %% 新服第一次连接
            ?PRINT("server_connected:no zone, zone_type:~w,server_id:~w!~n", [ZoneType, ServerId]),
            ZoneBase = #zone_base{
                server_id = ServerId, time = Time, world_lv = WorldLv,
                merge_ids = lists:delete(ServerId, MergeSerIds)},

            %% 上一分区Id
            LastZoneId = max(Next - 1, 1),
            LastZones = [Z || Z <- Zones, Z#zone_base.zone == LastZoneId],
            LenLastZone = length(LastZones),
            case {State#clusters_zone.is_zone, LenLastZone >= MaxServerNum} of
                %% 还未分区，直接加入列表
                {0, _} ->
                    NewZones = lists:keystore(ServerId, #zone_base.server_id, Zones, ZoneBase),
                    NewState = State#clusters_zone{zones = NewZones};
                {1, true} ->
                    NewZoneBase = ZoneBase#zone_base{zone = Next},
                    AllZones = [NewZoneBase|Zones],
                    save_zones(ZoneType, Next, [NewZoneBase]),
                    %% 分区结束后同步数据
                    sync_zone_func(ZoneType, NewZoneBase, 60),
                    NewNext = Next + 1,
                    NewState = State#clusters_zone{zones = AllZones, next = NewNext};
                %% 将加入的新服添加到最后的分区
                {1, false} ->
                    NewZoneBase = ZoneBase#zone_base{zone = LastZoneId},
                    AllZones = [NewZoneBase|Zones],
                    save_zones(ZoneType, LastZoneId, [NewZoneBase]),
                    %% 分区结束后同步数据
                    sync_zone_func(ZoneType, NewZoneBase, 60),
                    NewState = State#clusters_zone{zones = AllZones}
            end
    end,
    {ok, NewState}.

%% 合服时清理旧服区域数据
merge_fix(ZoneType, MainServerId, [MergeSrvId|T], Zones, ZoneId)->
    %% 查看区域路由中，该MergeSrvId中是否变更了区域
    case clusters_zone_api:get_zone(ZoneType, MergeSrvId) of
        0 ->
            Key = {ZoneType, MergeSrvId},
            ets:insert(?ETS_ZONE_ROUTE, #zone_route{key = Key, zone = ZoneId});
        ZoneId -> skip;
        OldZoneId ->
            %% 分区改变的情况
            clusters_zone_api:zone_change(ZoneType, MergeSrvId, OldZoneId, ZoneId, MainServerId)
    end,
    %% 删除区域列表数据
    case lists:keyfind(MergeSrvId, #zone_base.server_id, Zones) of
        #zone_base{zone = OZoneId} ->
            if
                ZoneId =/= OZoneId -> skip;
                true ->
                    %% 分区不变的情况
                    clusters_zone_api:remove_same_zone_func(ZoneType, OZoneId, MainServerId, MergeSrvId)
            end,
            db:execute(io_lib:format(<<"delete from server_zone where server_id=~w">>, [MergeSrvId])),
            NewZones = lists:keydelete(MergeSrvId, #zone_base.server_id, Zones),
            merge_fix(ZoneType, MainServerId, T, NewZones, ZoneId);
        _ ->
            merge_fix(ZoneType, MainServerId, T, Zones, ZoneId)
    end;
merge_fix(_ZoneType, _MainServerId, _, Zones, _)-> Zones.

%% 同步分区跨服数据
sync_all_zone_func(ZoneType, NewNext, Zones)->
    if
        NewNext =< 0 -> skip;
        true ->
            F = fun(ZoneBase) when ZoneBase#zone_base.zone == NewNext->
                    clusters_zone_api:sync_zone_func(ZoneType, ZoneBase);
                (_ZoneBase) -> skip
            end,
            lists:foreach(F, Zones),
            sync_all_zone_func(ZoneType, NewNext-1, Zones)
    end.

%% 延迟广播同步
sync_zone_func(ZoneType, ZoneBase, Time)->
    spawn(
        fun() ->
                timer:sleep(Time*1000),
                clusters_zone_api:sync_zone_func(ZoneType, ZoneBase)
        end
    ).

%% --------------------------------------------------------------------------
%% db 操作
%% --------------------------------------------------------------------------
db_select_server_zone(ZoneType) ->
    Sql = io_lib:format(<<"select server_id, zone, time, world_lv, merge_ids from server_zone where zone_type = ~p">>, [ZoneType]),
    db:get_all(Sql).

%% 批量回写
db_replace_into_zone(_ZoneType, [])-> ignore;
db_replace_into_zone(ZoneType, Zones)->
    DataStr = format_bin_string(ZoneType, Zones, <<>>),
    Sql  = io_lib:format(<<"replace into server_zone (zone_type, server_id, zone, time, world_lv, merge_ids) values~s">>, [DataStr]),
    db:execute(Sql).

%% sql语句封装
format_bin_string(ZoneType, [H], ResultBin) ->
    #zone_base{server_id=ServerId, zone = Zone, time = Time, world_lv = WorldLv, merge_ids = MergeIds} = H,
    list_to_binary([ ResultBin, io_lib:format(<<" (~w,~w,~w,~w,~w,'~s')">>, [ZoneType, ServerId, Zone, Time, WorldLv, util:term_to_bitstring(MergeIds)]) ]);
format_bin_string(ZoneType, [H|T], ResultBin) ->
    #zone_base{server_id=ServerId, zone = Zone, time = Time,  world_lv = WorldLv, merge_ids = MergeIds} = H,
    ResultBin1 = list_to_binary([ ResultBin, io_lib:format(<<" (~w,~w,~w,~w,~w,'~s')">>, [ZoneType, ServerId, Zone, Time, WorldLv, util:term_to_bitstring(MergeIds)]), <<",">> ]),
    format_bin_string(ZoneType, T, ResultBin1);
format_bin_string(_ZoneType, _, ResultBin) -> ResultBin.

