%%%------------------------------------
%%% @Module  : lib_activitycalen_mod
%%% @Author  :  xiaoxiang
%%% @Created :  2017-02-05
%%% @description: 活动日历时间管理
%%%------------------------------------

-module(lib_activitycalen_mod).
-include("common.hrl").
-include("activitycalen.hrl").
-include("def_module.hrl").
-include("def_fun.hrl").
-include("def_daily.hrl").
-include("server.hrl").
-include("clusters.hrl").
-include("figure.hrl").
-include("vip.hrl").
-compile(export_all).

-export([

    ]).
%% 根据当前节点类型，获取不符合条件的配置值
%% 配置中，data_activitycalen:get_ac_list/0接口获取的值：{Mod, ModSub, ActionSub, NodeType}
%% 其中，NodeType表示生效节点，其值可能为： 0游戏服 1跨服中心 2跨服中心和游戏服
get_invalid_node_type(ClusterType) ->
    case ClusterType of
        ?CLUSTER_NODE   -> 1;
        ?CLUSTER_CENTER -> 0
    end.

%% 每分钟检查一次活动开启与结束
timer_check(State = #ac_mgr_state{cluster_type = ClusterType}, _CheckType) ->
    Now = utime:unixtime(),
    IdList = data_activitycalen:get_ac_list(),
    InvalidNodeType = get_invalid_node_type(ClusterType),
    F = fun
            ({Module, ModuleSub, AcSub, NodeType}) when NodeType =/= InvalidNodeType ->
                BaseAc = data_activitycalen:get_ac(Module, ModuleSub, AcSub),
                CheckList = [fix_time, week, month, time, region, open_day, merge_day],
                case lib_activitycalen_util:do_check_ac_sub(BaseAc,  CheckList) of
                    true -> timer_start_ac(Module, ModuleSub, AcSub, Now);
                    _ ->
                        case lib_activitycalen_util:do_check_ac_sub(BaseAc, [fix_time, week, month, time, open_day, merge_day, region_end]) of
                            true -> timer_end_ac(Module, ModuleSub, AcSub, Now);
                            _ ->    skip
                        end
                end;
            (_) ->
                ignore
        end,
    lists:foreach(F, IdList),
    State.

%%% 各个活动定时开启
timer_start_ac(Module, ModuleSub, AcSub, Now) ->
    %% 管理进程记录活动状态
    lib_activitycalen_api:success_start_activity(Module, ModuleSub, AcSub),
    case Module of
        ?MOD_GUILD when ModuleSub =:= 7 ->
            mod_guild_tribe_mgr:activitycalen_start(AcSub);
        ?MOD_TOPPK ->
            mod_top_pk_local:apply_cast({'act_start', AcSub});
        ?MOD_BEACH ->
            lib_charm_beach:act_start(AcSub);
        ?MOD_VOID_FAM ->
            lib_void_fam:activitycalen_start(AcSub);
        ?MOD_GLAMOUR ->
            mod_glamour_ctrl:activitycalen_start(AcSub);
        ?MOD_GUILD_BOSS ->
            mod_guild_boss_mgr:activitycalen_start(AcSub);
        ?MOD_GUILD_COLLECT ->
            lib_guild_collect:act_start(AcSub);
        ?MOD_GUILD_WAR ->
            guild_war_mgr:activitycalen_start(Module, ModuleSub, AcSub, Now);
        ?MOD_CAMP_WAR ->
            camp_war_mgr:act_start(Module, ModuleSub, AcSub, Now);
        ?MOD_MADNESS_LAND ->
            madness_land:act_start(Module, ModuleSub, AcSub);
        ?MOD_WASTELAND_WAR ->
            lib_wasteland_war:act_start(AcSub);
        ?MOD_CONVOY ->
            lib_chat:send_TV({all}, ?MOD_CONVOY, 1, []);
        _ ->
            ok
    end.

%%% 各个活动定时关闭
timer_end_ac(Module, ModuleSub, AcSub, _Now) ->
    %% 管理进程更新活动状态
    lib_activitycalen_api:success_end_activity(Module, ModuleSub, AcSub),
    case Module of
        ?MOD_GUILD_COLLECT ->
            lib_guild_collect:act_end(AcSub);
        ?MOD_GUILD_WAR ->
            guild_war_mgr:activitycalen_end();
        _ ->
            ok
    end.

%% 各个活动开启预告
%% 活动开启前xx分钟预告  手动配置data_activitycalen_m:get_advance(Module, ModuleSub) -> Time.
ac_advance(Module, ModuleSub, AcSub, Now) ->
    catch lib_log_api:log_ac_start(Module, ModuleSub, AcSub, ?LOG_TYPE_AC_ADVANCE_BY_CALEN, Now),
    case {Module, ModuleSub} of
        {?MOD_BEACH, _} ->
            Minute = data_activitycalen_m:get_advance(Module, ModuleSub),
            lib_charm_beach:act_ready(Minute * 60);
        {?MOD_TOPPK, _} ->
            mod_top_pk_local:apply_cast('advance');
        _ ->
            skip
    end.

%% 活动开启
success_start_activity(Module, ModuleSub, AcSub, State) ->
    Now = utime:unixtime(),
    catch lib_log_api:log_ac_start(Module, ModuleSub, AcSub, ?LOG_TYPE_AC_START_BY_AC, Now),
    EndTime = lib_activitycalen_api:get_ac_end_time(Module, ModuleSub, AcSub, Now),
    send_15706(Module, ModuleSub, AcSub, ?AC_OPEN, EndTime),
    #ac_mgr_state{ac_maps = AcMaps} = State,
    NewAcMaps = maps:put({Module, ModuleSub, AcSub}, {?AC_OPEN, EndTime}, AcMaps),
    State#ac_mgr_state{ac_maps = NewAcMaps}.

%% 活动结束
success_end_activity(Module, ModuleSub, AcSub, State) ->
    catch lib_log_api:log_ac_start(Module, ModuleSub, AcSub, ?LOG_TYPE_AC_END_BY_AC, utime:unixtime()),
    send_15706(Module, ModuleSub, AcSub, ?AC_END, 0),
    #ac_mgr_state{ac_maps = AcMaps} = State,
    NewAcMaps = maps:remove({Module, ModuleSub, AcSub}, AcMaps),
    State#ac_mgr_state{ac_maps = NewAcMaps}.

%% GM开启活动
gm_end_act(Module, ModuleSub, State) ->
    #ac_mgr_state{ac_maps = AcMaps} = State,
    AcSubList = data_activitycalen:get_ac_sub(Module, ModuleSub),
    F = fun(AcSub, Map) ->
        case maps:get({Module, ModuleSub, AcSub}, Map, false) of
            {?AC_OPEN, _} ->
                catch lib_log_api:log_ac_start(Module, ModuleSub, AcSub, ?LOG_TYPE_AC_END_BY_AC, utime:unixtime()),
                send_15706(Module, ModuleSub, AcSub, ?AC_END, 0),
                maps:remove({Module, ModuleSub, AcSub}, Map);
            _ -> Map
        end
        end,
    NewAcMaps = lists:foldl(F, AcMaps, AcSubList),
    State#ac_mgr_state{ac_maps = NewAcMaps}.

%% GM结束活动
gm_end_act_state(Module, ModuleSub, AcSub, State) ->
    catch lib_log_api:log_ac_start(Module, ModuleSub, AcSub, ?LOG_TYPE_AC_END_BY_AC, utime:unixtime()),
    send_15706(Module, ModuleSub, AcSub, ?AC_END, 0),
    #ac_mgr_state{ac_maps = AcMaps} = State,
    NewAcMaps = maps:remove({Module, ModuleSub, AcSub}, AcMaps),
    State#ac_mgr_state{ac_maps = NewAcMaps}.

%% 客户端更新
send_act_status(Module, ModuleSub, RoleId, Lv, State) ->
    AcSub = lib_activitycalen:get_ac_sub_with_end(Module, ModuleSub),
    send_15707(Module, ModuleSub, AcSub, RoleId, Lv),
    State.

send_15707(Module, ModuleSub, AcSub, RoleId, Lv) ->
    case data_activitycalen:get_ac(Module, ModuleSub, AcSub) of
        #base_ac{start_lv = MinLv, end_lv = MaxLv, ac_type = AcType} ->
            case Lv >= MinLv andalso Lv =< MaxLv of
                 true  ->
                    lib_server_send:send_to_uid(RoleId, pt_157, 15707, [AcType]);
                 false ->
                     skip
            end;
        _ -> skip
    end.

send_15706(Module, ModuleSub, AcSub, Status, EndTime) ->
    case data_activitycalen:get_ac(Module, ModuleSub, AcSub) of
        #base_ac{start_lv = MinLv, end_lv = MaxLv, ac_type = ActType} ->
            {ok, Bin} = pt_157:write(15706, [Module, ModuleSub, AcSub, Status, EndTime]),
            {ok, Bin1} = pt_157:write(15707, [ActType]),
            Bin2 = << Bin/binary, Bin1/binary >>,
            lib_server_send:send_to_all(all_lv, {MinLv, MaxLv}, Bin2);
        _ -> skip
    end.

 %% -----------------------init -------------------
init() ->
    ClusterType = clusters_api:get_cluster_type(),
    if ClusterType == ?CLUSTER_NODE ->
            self() ! {ets_activitycalen_init};
        true ->
            skip
    end,
    #ac_mgr_state{cluster_type = ClusterType}.

%%玩家每日活跃度统计这里放入ets
ets_activitycalen_init() ->
    case lib_activitycalen:db_select_daily_live() of
        [] -> ok;
        List ->
            Date = erlang:date(),
            FiveDay = utime:get_before_day(Date, 5, 0),
            FinalTime = utime:unixtime({FiveDay, {0, 0, 0}}),
            EtsList = make_ets(List, FinalTime, []),
            ets:insert(?ETS_ACTIVITYCALEN, EtsList)
    end.

make_ets([], _FinalTime, EtsList) -> EtsList;
make_ets([[RoleId, Creatime, LiveNessList] | T], FinalTime, EtsList) ->
    TermLiveNess = util:bitstring_to_term(LiveNessList),
    LiveNess = [{Time, Val} || {Time, Val} <- TermLiveNess, Time >= FinalTime],
    case LiveNess == [] of
        true -> make_ets(T, FinalTime, EtsList);
        false ->
            EtsAct = #ets_activitycalen{id = RoleId, create_time = Creatime, liveness_list = LiveNess},
            make_ets(T, FinalTime, [EtsAct | EtsList])
    end.

%% 日常界面信息
ask_activity_num(RoleId, Lv, VipLv, OnHookTime, Type,TCoin,THonor,PowerLive,OtherData,State) ->
    #ac_mgr_state{ac_maps = AcMaps}  = State,
    IdList = data_activitycalen:get_ac_list(),
    %% 等级达到的活动
    F = fun({Module, ModuleSub, AcSub, _}, TempList) ->
            #ac_liveness{start_lv = StartLv, end_lv = EndLv, act_type = ActType} = data_activitycalen:get_live_config(Module, ModuleSub),
            %% 分必做 和 限时类型
            case ActType == Type of
                true ->
                    case Lv >= StartLv andalso EndLv >= Lv  of
                        true ->
                            case Type == ?ACTIVITY_TYPE_DAILY of
                                true -> ActStatus = ?AC_OPEN;
                                _ ->
                                    {ActStatus, _} =  maps:get({Module, ModuleSub, AcSub}, AcMaps, {?AC_END, 0})
                            end,
                             [{{Module, ModuleSub, ActStatus}, AcSub} | TempList];
                        _ -> TempList
                    end;
                  _ -> TempList
            end
    end,
    TmpActL = lists:foldl(F, [], IdList),
    %% 即将到达等级段活动
    NextLv = lib_activitycalen:get_next_act_lv(Lv, Type),
    TmpActs = data_activitycalen:get_ac_by_lv(NextLv, Type),
    F1 = fun({TmpMod, TmpModSub, TmpActSub}, TmpL) ->
        case lists:member({{TmpMod, TmpModSub, ?AC_LV_LIMIT}, TmpActSub}, TmpL) of
            true -> TmpL;
            _ -> [{{TmpMod, TmpModSub, ?AC_LV_LIMIT}, TmpActSub} | TmpL]
        end
    end,
    TmpActL1 = lists:foldl(F1, TmpActL, TmpActs),
    %% 需要活跃度的活动
    F2 = fun({Module, ModuleSub}, TmpL) ->
         case lists:keyfind({Module, ModuleSub, ?AC_LV_LIMIT}, 1, TmpActL1) of
            {{_, _, _}, TmpActSub} -> [{Module, ModuleSub, TmpActSub, ?AC_LV_LIMIT} | TmpL];
            _ ->
                case lists:keyfind({Module, ModuleSub, ?AC_OPEN}, 1, TmpActL1) of
                   {{_,_,_}, TmpActSub} -> [{Module, ModuleSub, TmpActSub, ?AC_OPEN} | TmpL];
                   _ ->
                      case lists:keyfind({Module, ModuleSub, ?AC_END}, 1, TmpActL1) of
                            {{_,_,_}, _} ->
                                TmpActSub  = lib_activitycalen_util:get_near_act(Module, ModuleSub), %% 未开启的找最靠近的下一个子活动
                                %?PRINT("~p, ~p, ~p~n", [Module, ModuleSub, TmpActSub]),
                                [{Module, ModuleSub, TmpActSub, ?AC_END} | TmpL];
                           _ -> TmpL
                      end
                end
         end
    end,
    ActList = lists:foldl(F2, [], data_activitycalen:get_live_key()),
    %% 要请求的计数列表一次call
    TmpL = lib_daily:get_count_offline(RoleId, [{?MOD_ACTIVITY, ?MOD_ACTIVITY_NUM, TmpMod * ?AC_LIVE_ADD + TmpModSub}||{TmpMod, TmpModSub, _, _} <- ActList]),
    %% 解析回来模块和子模块
    CountList = [{{TmpType div ?AC_LIVE_ADD, TmpType rem ?AC_LIVE_ADD}, Count}||{{_, _, TmpType}, Count} <- TmpL],
    F3 = fun({Module, ModuleSub, AcSub, ActStatus}, TempList) ->
            case ActStatus of
                ?AC_LV_LIMIT ->
                    Max   = 0,
                    Value = Live = 0;
                _ ->
                    case lib_activitycalen:check_ac_live_day(Module, ModuleSub) of
                        true ->
                            #ac_liveness{max = Max0,live=LivePer} = data_activitycalen:get_live_config(Module, ModuleSub),
                            Player = #player_status{vip_status = #vip_status{type = ?PER_SUP_VIP, lv = VipLv}, figure = #figure{vip = VipLv}},
                            Max01 = lib_activitycalen:get_vip_max(Module, ModuleSub, Player,Max0),
                            #other_data{is_sup_vip = IsSupVip, main_line_times = MainLineTimes} = OtherData,
                            IsSupVipAdd   = lists:member({Module, ModuleSub}, [{?MOD_DUNGEON, 15}]),
                            IsMainLineDun = lists:member({Module, ModuleSub}, [{?MOD_DUNGEON, 20}]),
                            Max02 = case IsSupVip of
                                        true when IsSupVipAdd -> Max01 + ?SUP_VIP_ADD_TIMES;
                                        _ -> Max01
                                    end,
                            case MainLineTimes of
                                {UseTimes, CfgTimes} when IsMainLineDun ->
                                    Max = CfgTimes, Value = UseTimes, Live = 0;
                                _ ->
                                    Max = Max02,
                                    TempValue = case lists:keyfind({Module, ModuleSub}, 1, CountList) of
                                                    {_, Count} -> Count;
                                                    _ -> 0
                                                end,
                                    Value = min(Max, TempValue),
                                    Live = Value * LivePer
                            end;
                        _ ->
                            Max = 0,
                            Value = Live = 0
                    end
            end,
            [{Module, ModuleSub, AcSub, Value,Max,Live, ActStatus}|TempList]
        end,
    Info =  lists:foldl(F3, [], ActList),
    % ?PRINT("Info:~p ~p~n", [Info, OnHookTime]),
    lib_server_send:send_to_uid(RoleId, pt_157, 15701, [Type, OnHookTime, PowerLive,TCoin,THonor, Info]),
    State.

%% 查询活动状态
ask_activity_status(RoleId, State) ->
    #ac_mgr_state{ac_maps = AcMaps}  = State,
    IdList = data_activitycalen:get_ac_list(),
    {_NowDay, {NowH,NowM,_}} = calendar:local_time(),
    F = fun({Module, ModuleSub, AcSub, _}, Temp) ->
        case maps:get({Module, ModuleSub, AcSub}, AcMaps, false) of
            {?AC_OPEN, EndTime} ->
                [{Module, ModuleSub, AcSub, ?AC_OPEN, EndTime}|Temp];
            _ -> %% 判断
                BaseAc = data_activitycalen:get_ac(Module, ModuleSub, AcSub),
                case check_act_status(Module, ModuleSub, AcSub, BaseAc) of
                    true->
                        TimeRegion = BaseAc#base_ac.time_region,
                        TimeList = [{NowH,NowM}||{{H,M},_}<-TimeRegion, H*60+M>=NowH*60+NowM],
                        case lists:member({NowH,NowM}, TimeList) of
                            true ->
                                [{Module, ModuleSub, AcSub, ?AC_WAIT, 0}|Temp];
                            _ ->
                                [{Module, ModuleSub, AcSub, ?AC_END, 0}|Temp]
                        end;
                    false-> Temp
                end
        end
    end,
    Info = lists:foldl(F, [], IdList),
    % ?PRINT("ACTITYCALENDAR :~w ~n", [Info]),
    lib_server_send:send_to_uid(RoleId, pt_157, 15702, [Info]),
    State.

%%检测活动状态
check_act_status(Module, _ModuLeSub, _AcSub, BaseAc) ->
    TodayMerge = util:get_merge_day(),%%当前合服第几天
    TodayOpen = util:get_open_day(),  %%当前开服第几天
    CheckList = get_open_or_merge_first_day(Module, TodayMerge, TodayOpen),
    CheckResult = lib_activitycalen_util:do_check_ac_sub(BaseAc, CheckList),
    CheckResult andalso is_list(BaseAc#base_ac.time_region).

%%获取开服或者合服第一天开启的检测列表
get_open_or_merge_first_day(_Module, TodayMerge, TodayOpen) when TodayOpen == 1 orelse TodayMerge == 1->
    if
        %%后续区分活动
        true -> [fix_time, week, month, time, open_day, merge_day]
    end;
get_open_or_merge_first_day(_Module, _TodayMerge, _TodayOpen) ->
    [fix_time, week, month, time, open_day, merge_day].

%%获取单个活动状态（主做倒计时用）
% 只适用于定时活动
ask_activity(RoleId, Module, ModuleSub, State) ->
    #ac_mgr_state{ac_maps = AcMaps}  = State,
    IdList = data_activitycalen:get_ac_sub(Module, ModuleSub),
    HasOpen = get_open_sub(Module, ModuleSub, IdList, AcMaps),
    case HasOpen of
        {AcSub, EndTime} ->
            lib_server_send:send_to_uid(RoleId, pt_157, 15715, [Module, ModuleSub, AcSub, ?AC_OPEN, EndTime]);
        _ ->
            next_open_sub(RoleId, Module, ModuleSub)
    end.

%% 获取开着的活动
get_open_sub(_Module, _ModuleSub, [], _AcMaps) -> [];
get_open_sub(Module, ModuleSub, [AcSub| T], AcMaps) ->
    case maps:get({Module, ModuleSub, AcSub}, AcMaps, false) of
        {?AC_OPEN, EndTime} -> {AcSub, EndTime};
        _ -> get_open_sub(Module, ModuleSub, T, AcMaps)
    end.

next_open_sub(RoleId, Module, ModuleSub)->
    IdList = data_activitycalen:get_ac_sub(Module, ModuleSub),
    List = get_act_time_list(IdList, Module, ModuleSub, []),
    case List == [] of
        true-> skip;
        false->
            {AcSub, Time} = hd(lists:keysort(2, List)),
            lib_server_send:send_to_uid(RoleId, pt_157, 15715, [Module, ModuleSub, AcSub, ?AC_WAIT, Time])
    end.

get_act_time_list([], _Module, _ModuleSub, List) -> List;
get_act_time_list([AcSub| T], Module, ModuleSub, List) ->
    case get_act_time(Module, ModuleSub, AcSub) of
        Time when is_integer(Time) andalso Time>0 ->
            get_act_time_list(T, Module, ModuleSub, [{AcSub, Time}|List]);
        _ -> get_act_time_list(T, Module, ModuleSub, List)
    end.

%%获取下次活动时间
get_act_time(Module, ModuleSub, AcSub) ->
    Now = utime:unixtime(),
    #base_ac{time_region = TimeRegion1, week = Week, merge_day = Merge, open_day = Open} = ActCfg = data_activitycalen:get_ac(Module, ModuleSub, AcSub),
    TimeRegion = lists:keysort(1, TimeRegion1),
    {H, M} = case TimeRegion =/= [] of
        true->
            {{SH, SM},{_EH, _EM}} = hd(TimeRegion),
            {SH, SM};
        false-> {0, 0}
    end,
    TodayTime = case lib_activitycalen_util:do_check_ac_sub(ActCfg, [fix_time, week, time, open_day, merge_day]) of
        true -> get_today_time(TimeRegion, Now);
        false -> 0
    end,
    WeekTime = case lib_activitycalen_util:do_check_ac_sub(ActCfg, [fix_time, open_day, merge_day]) of
        true -> get_week_time(Week, {H, M});
        false -> 0
    end,
    %%判断是否合过服
    FixTime = case util:is_merge_game() of
        true-> get_merge_time(Merge, {H, M}, Now);
        false-> get_open_time(Open, {H, M}, Now)
    end,
    TimeList = [TodayTime, WeekTime, FixTime],
    FilterList = [Time||Time<-TimeList, Time>0, Time>Now],
    case FilterList == [] of
        true -> 0;
        false ->
            hd(lists:sort(FilterList))
    end.

%%获取今日的下次开启时间
get_today_time([], _Now) -> 0;
get_today_time([{{SH, SM},{_EH, _EM}}| T], Now) ->
    Date = erlang:date(),
    OpenTime = utime:unixtime({Date, {SH, SM, 0}}),
    case OpenTime > Now of
        true-> OpenTime;
        false-> get_today_time(T, Now)
    end.

%%获取周的下次开启时间
get_week_time(_Week, {0, 0}) -> 0;
get_week_time([], {H, M}) -> %% 明天开
    Tomorrow = utime:get_before_day(erlang:date(), 1, 1),
    utime:unixtime({Tomorrow, {H, M, 0}});
get_week_time(Week, {H, M}) ->
    NowWeek = utime:day_of_week(),
    MaxFilterWeek = [W||W <- Week, NowWeek < W],
    MinFilterWeek = [W||W <- Week, NowWeek >= W],
    CalcWeek = ?IF(MaxFilterWeek == [], 7 + hd(MinFilterWeek), hd(MaxFilterWeek)),
    DiffDay = max(0,(CalcWeek - NowWeek)),
    ThatDay = utime:get_before_day(erlang:date(), DiffDay, 1),
    utime:unixtime({ThatDay, {H, M, 0}}).

%%获取合服的下次开启时间
get_merge_time(_Merge, {0, 0}, _Now) -> 0;
get_merge_time([], _, _Now) -> 0;
get_merge_time([{Min, Max}| T], {H, M}, Now) ->
    MergeDay = util:get_merge_day(),
    if
        MergeDay == Min andalso MergeDay == Max -> get_merge_time(T, {H, M}, Now);
        MergeDay>Min andalso MergeDay <Max ->
            Tomorrow = utime:get_before_day(erlang:date(), 1, 1),
            utime:unixtime({Tomorrow, {H, M, 0}});
        MergeDay<Min ->
            ThatDay = utime:get_before_day(erlang:date(), Min - MergeDay, 1),
            utime:unixtime({ThatDay, {H, M, 0}});
        true -> get_merge_time(T, {H, M}, Now)
    end.

%%获取开服的下次开启时间
get_open_time(_Open, {0, 0}, _Now) -> 0;
get_open_time([], _, _Now) -> 0;
get_open_time([{Min, Max}| T], {H, M}, Now) ->
    OpenDay = util:get_open_day(),
    if
        OpenDay == Min andalso OpenDay == Max -> get_open_time(T, {H, M}, Now);
        OpenDay>Min andalso OpenDay <Max ->
            Tomorrow = utime:get_before_day(erlang:date(), 1, 1),
            utime:unixtime({Tomorrow, {H, M, 0}});
        OpenDay<Min ->
            ThatDay = utime:get_before_day(erlang:date(), Min - OpenDay, 1),
            utime:unixtime({ThatDay, {H, M, 0}});
        true -> get_open_time(T, {H, M}, Now)
    end.

%%%% ----------------------------------------------------------------------

db_inset_ac_start(Module, ModuleSub, AcSub) ->
    Sql = io_lib:format(?sql_inset_ac_start, [Module, ModuleSub, AcSub, utime:unixtime()]),
    db:execute(Sql).

db_select_ac_start() ->
    Sql = io_lib:format(?sql_select_ac_start, []),
    db:get_all(Sql).
