%% ---------------------------------------------------------------------------
%% @doc 自增Id服务
%% @author hek
%% @since  2016-11-30
%% @deprecated
%% ---------------------------------------------------------------------------
-module (mod_id_create).
-behaviour(gen_server).
-include ("common.hrl").
-include ("def_id_create.hrl").

%% API
-export([get_new_id/1, get_serid_by_id/1, start_link/1, stop/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

%%% Usage:
%%% 新增Id类型步骤
%%% 1. def_id_create.hrl中定义一个Id类型（IdType），并加入id类型列表
%%% 2. gsrv_server_base中添加mod_id_create:start_link(IdType)
%%% 3. mod_id_create中实现该IdType的get_last_id函数
%%% End.

get_new_id(IdType) ->
    gen_server:call(misc:get_autoid_process(IdType), 'get_new_id').

get_serid_by_id(Id) ->
    <<SerId:16, _/binary>> = <<Id:48>>,
    SerId.

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

stop(IdType) ->
    gen_server:call(misc:get_autoid_process(IdType), 'stop').

%% --------------------------------- %% ---------------------------------
%% 注：新增Id类型，
%% --------------------------------- %% ---------------------------------

get_last_id(?GOODS_ID_CREATE) ->
    db:get_row(io_lib:format(<<"select max(id) from goods">>, []));

get_last_id(?GUILD_ID_CREATE) ->
    db:get_row(io_lib:format(<<"select max(id) from guild">>, []));

get_last_id(?AUCTION_ID_CREATE) ->
    db:get_row(io_lib:format(<<"select max(auction_id) from auction">>, []));

get_last_id(?AUCTION_GOODS_ID_CREATE) ->
    db:get_row(io_lib:format(<<"select max(goods_id) from auction_goods">>, []));

get_last_id(?SELL_ID_CREATE) ->
    db:get_row(io_lib:format(<<"select max(id) from market_goods">>, []));

get_last_id(?CHARGE_PAY_NO_CREATE) ->
    db:get_row(io_lib:format(<<"select max(id) from charge">>, []));

get_last_id(?FLOWER_GIFT_RECORD_ID_CREATE) ->
    db:get_row(io_lib:format(<<"select max(id) from flower_gift_record">>, []));

get_last_id(?RED_ENVELOPES_ID_CREATE) ->
    db:get_row(io_lib:format(<<"select max(id) from red_envelopes">>, []));

get_last_id(?ORDER_ID_CREATE) ->
    db:get_row(io_lib:format(<<"select max(id) from guild_order">>, []));

get_last_id(?SUPPORT_ID_CREATE) ->
    db:get_row(io_lib:format(<<"select max(support_sid) from guild_support">>, []));

get_last_id(_IdType) ->
    ?ERR("unkown id_type:~p", [_IdType]),
    [].

do_init([IdType, ProcessName]) ->
    process_flag(priority, high),
    misc:register(global, ProcessName, self()),
    AutoId = case db:get_row(io_lib:format(<<"select count from auto_id where type=~w">>, [IdType])) of
        [TmpAutoId|_] when is_integer(TmpAutoId) -> TmpAutoId;
        _ -> 0
    end,
    SerId = config:get_server_id(),
    LastId = case get_last_id(IdType) of
        [Id|_] when is_integer(Id) ->
            <<_:16, TmpLastId:32>> = <<Id:48>>,
            max(TmpLastId, AutoId);
        _Other -> AutoId
    end,
    {ok, #create_state{last_id = LastId, server_id = SerId, id_type = IdType}}.

do_call('get_new_id', _From, #create_state{last_id=OldLastId, left_num = 0, server_id=_SerId, id_type = IdType} = State) ->
    EveryCreateNum = every_create_num(),
    NewCount = OldLastId + EveryCreateNum,
    case catch db:execute(io_lib:format(<<"replace into auto_id set type=~w, count=~w">>, [IdType, NewCount])) of
        {'EXIT', _} = Reason -> ?ERR("get_new_id error = ~p", [Reason]);
        _ -> skip
    end,
    NewState = State#create_state{left_num = EveryCreateNum},
    do_call('get_new_id', _From, NewState);

do_call('get_new_id', _From, #create_state{last_id=OldLastId, left_num = OldLeftNum, server_id=SerId, id_type = _IdType} = State) ->
    LastId = OldLastId+1,
    <<AutoId:48>> = <<SerId:16, LastId:32>>,
    LeftNum = max(OldLeftNum - 1, 0),
    {reply, AutoId, State#create_state{last_id = LastId, left_num = LeftNum}};

do_call('stop', _From, #create_state{last_id=OldLastId, left_num = OldLeftNum, server_id=_SerId, id_type = IdType} = State) ->
    case catch db:execute(io_lib:format(<<"replace into auto_id set type=~w, count=~w">>, [IdType, OldLastId - OldLeftNum])) of
        {'EXIT', _} = Reason -> ?ERR("stop error = ~p", [Reason]);
        _ -> skip
    end,
    {reply, ok, State}.

do_cast('stop', State) ->
    {stop, normal, State};

do_cast(_Msg, State) ->
    {noreply, State}.

do_info(_Info, State) ->
    {noreply, State}.

%% --------------------------------------------------------------------------
%% Function: init/1
%% Description: Initiates the server
%% Returns: {ok, State}          |
%%          {ok, State, Timeout} |
%%          ignore               |
%%          {stop, Reason}
%% --------------------------------------------------------------------------
init(Args) ->
    case catch do_init(Args) of
        {'EXIT', Reason} ->
            ?ERR("init error:~p~n", [Reason]),
            {stop, Reason};
        {ok, State} ->
            {ok, State};
        Other ->
            {stop, Other}
    end.

%% --------------------------------------------------------------------------
%% Function: handle_call/3
%% Description: Handling call messages
%% Returns: {reply, Reply, State}          |
%%          {reply, Reply, State, Timeout} |
%%          {noreply, State}               |
%%          {noreply, State, Timeout}      |
%%          {stop, Reason, Reply, State}   | (terminate/2 is called)
%%          {stop, Reason, State}            (terminate/2 is called)
%% --------------------------------------------------------------------------
handle_call(Request, From, State) ->
    case catch do_call(Request, From, State) of
        {'EXIT', Reason} ->
            ?ERR("handle_call error:~p~n", [Reason]),
            {reply, error, State};
        {reply, Reply, NewState} ->
            {reply, Reply, NewState};
        _ ->
            {reply, true, State}
    end.

%% --------------------------------------------------------------------------
%% Function: handle_cast/2
%% Description: Handling cast messages
%% Returns: {noreply, State}          |
%%          {noreply, State, Timeout} |
%%          {stop, Reason, State}            (terminate/2 is called)
%% --------------------------------------------------------------------------
handle_cast(Msg, State) ->
    case catch do_cast(Msg, State) of
        {'EXIT', Reason} ->
            ?ERR("handle_cast error:~p~n", [Reason]),
            {noreply, State};
        {noreply, NewState} ->
            {noreply, NewState};
        {stop, normal, NewState} ->
            {stop, normal, NewState};
        _ ->
            {noreply, State}
    end.

%% --------------------------------------------------------------------------
%% Function: handle_info/2
%% Description: Handling all non call/cast messages
%% Returns: {noreply, State}          |
%%          {noreply, State, Timeout} |
%%          {stop, Reason, State}            (terminate/2 is called)
%% --------------------------------------------------------------------------
handle_info(Info, State) ->
    case catch do_info(Info, State) of
        {'EXIT', Reason} ->
            ?ERR("handle_info error:~p~n", [Reason]),
            {noreply, State};
        {noreply, NewState} ->
            {noreply, NewState};
        _ ->
            {noreply, State}
    end.

%% --------------------------------------------------------------------------
%% Function: terminate/2
%% Description: Shutdown the server
%% Returns: any (ignored by gen_server)
%% --------------------------------------------------------------------------
terminate(_Reason, _State) ->
    ok.

%% --------------------------------------------------------------------------
%% Func: code_change/3
%% Purpose: Convert process state when code is changed
%% Returns: {ok, NewState}
%% --------------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

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

every_create_num() -> max(?EVERY_CREATE_NUM, 1).
