%%-----------------------------------------------------------------------------
%% @Module  :       lib_custom_act_dispatcher
%% @Author  :       YanWeiFan
%% @Email   :       389853407@qq.com
%% @Created :       2019-05-05
%% @Description:	定制活动分发器
%%-----------------------------------------------------------------------------
-module(lib_custom_act_dispatcher).

-include("custom_act.hrl").
-include("daily.hrl").
-include("common.hrl").
-include("server.hrl").
-include("errcode.hrl").
-include("def_fun.hrl").
-include("goods.hrl").
-include("figure.hrl").
-include("predefine.hrl").
-include("consume_rank_act.hrl").
-include_lib("stdlib/include/ms_transform.hrl").

%% 分发接口
-export ([ %% lib_custom_act_check
        check_cfg/1,						%% 检测活动的条件配置是否完善
        check_receive_reward_conditions/3,  %% 检测领取奖励是否符合条件
        check_reward_receive_times/3,		%% 检测领取奖励次数
        check_receive_reward_special/3		%% 领奖特殊检测（与conditions检测不同）
    ]).

-export ([ %% lib_custom_act
        %% ----------------- 活动开启 -------------------
        notify_other_module/5,				%% 开启活动通知其他模块
        do_timer_check_other/2,				%% 开启活动额外检测
        %% ----------------- 领奖状态计算 -------------------
        ask_reward_status/3,				%% 请求奖励领取状态
        ask_act_red_gift_status/3,          %% 请求红点礼包奖励领取状态
        send_reward_status/2,				%% 发送活动领取状态
        count_reward_progress/4,			%% 计算奖励进度
        count_common_progress/2,			%% 计算通用奖励进度
        count_reward_status/4,				%% 计算可领取状态
        count_receive_times/3,				%% 计算已领取次数
        %% ----------------- 领奖相关 -------------------
        receive_reward/4,					%% 领取奖励
        receive_red_gift_reward/4,          %% 领取红点奖励
        do_receive_reward/4,				%% 发奖励
        update_receive_times_normal/5,		%% 更新领取次数
        get_extra_log/1						%% 获取领取奖励日志额外数据
        , auto_receive_reward/3
    ]).

-export ([ %% lib_custom_act_api
        %% ----------------- 发送未领取奖励 --------------------------
        send_forgot_rewards/1,
        check_has_rewards_for_forget/4,		%% 检测活动结束时是否有忘记领取的奖励
        check_has_rewards_for_merge/4,		%% 检测合服时是否有未领取的奖励
        get_act_roles/1,					%% 获取参与活动的玩家
        make_role_info_for_check/3,			%% 获取玩家定制活动的检测数据
        calc_got_reward_times/3,			%% 计算获奖次数
        %% ----------------- 0点更新数据 -----------------------------
        is_need_daily_update/2				%% 用于判断该活动是否需要0点更新
    ]).

-export ([ %% lib_custom_act_kf
        kf_notify_other_module/4			%% 跨服中心检测跨服活动状态改变，通知其他进程
    ]).

-export ([
        count_act_reward_other/2
    ]).

-export([
        init_personal_act_data/2
    ]).
%% -------------------------------------------------------
%% 后续开发者在主流程中看到调用了分发器的，
%% 可以直接到lib_custom_act_do_normal中查看通用处理逻辑
%% 建议后续开发单独开模块
%% 可从normal模块中复制export部分到新模块
%% 再根据具体活动需要做删减，以免漏掉参数
%% 若逻辑确实较少可直接写入normal对应函数特殊处理
%% --------------------------------------------------------

%% custom_act                                    定制活动主目录
%%     |-custom_act_do                           定制活动分发逻辑代码目录，主要用来存放由分发器发出的逻辑代码
%%         |-lib_custom_act_do_normal.erl        处理一些通用的分发逻辑以及少量的活动逻辑
%%         |-lib_custom_act_do_xx.erl            处理活动的特殊分发逻辑
%%     |-xx                                      活动子目录，用于存放某一特定活动的逻辑代码
%%         |-mod_xx.erl
%%         |-lib_xx.erl
%%         |-lib_custom_act_do_xx.erl            当活动有自己的目录时，把do文件也放进活动目录去
%%     |-lib_custom_act.erl                      定制活动流程控制逻辑
%%     |-lib_custom_act_api.erl                  定制活动接口
%%     |-lib_custom_act_check.erl                定制活动检测逻辑
%%     |-lib_custom_act_dispatchar.erl           定制活动逻辑分发器
%%     |-lib_custom_act_dynamic_compile.erl      额外定制活动代码动态生成器
%%     |-lib_custom_act_util.erl                 定制活动工具模块
%%     |-mod_custom_act.erl                      定制活动进程控制主文件
%%     |-mod_custom_act_kf.erl                   跨服定制活动进程控制主文件
%%     |-lib_custom_act_kf.erl                   跨服定制活动流程控制逻辑
%%     |-pp_custom_act.erl                       定制活动协议入口文件，有一些活动的逻辑代码也在里面
%%     |-pp_xx.erl                               有一些定制活动额外开协议，也放在主目录下

%% --------------------------------------------------------
%% 定制活动开发目录规范
%%
%% 1、
%% 单独的pp协议文件放在custom_act主目录下，便于查找逻辑入口，
%% 将相同的活动逻辑文件尽量放在同一个目录下，有助于查阅和二次开发。
%%
%% 2、
%% 当一个活动有多个逻辑文件时，请在custom_act主目录下创建新目录用于放置该活动的所有逻辑文件；
%% 当一个活动创建了额外的逻辑分发文件(lib_custom_act_do_)且仅有该文件时，
%% 可以把该文件放置在custom_act_do目录下(该目录只存放只有一个逻辑分发文件的无处安放的活动)，
%% 或者在custom_act主目录下额外开子目录存放；
%%
%% eg1.集字活动colword仅有一个逻辑分发文件lib_custom_act_do_colword处理该活动的所有逻辑，
%%     因此它可以被放在custom_act_do目录下，或者额外在主目录下开子目录colword存放；
%% eg2.限购活动limit_buy有一个逻辑分发文件lib_custom_act_do_limit_buy和另一个文件mod_limit_buy，
%%     因此它们需要主目录下另外开子目录limit_buy存放这俩文件。
%%
%% 3、
%% 理论上，分发器分发出的逻辑函数不一定非要新开文件处理，
%% 当分发的逻辑较少时可以发至活动现拥有的erl文件中，
%% 但是为了避免有同名函数冲突，建议文件不要使用 -compile(export_all).
%% 在代码结构上，将分发过去的逻辑代码整理在一起（建议放在开头），与其余逻辑代码区分开。
%%
%%                                                ———— Create by YanWeiFan 2019.6.20
%% --------------------------------------------------------


%% 需要特殊处理的活动模块，未定义就会走到normal模块
get_mod_by_acttype(?CUSTOM_ACT_TYPE_RECHARGE_CONSUME)       -> lib_custom_act_do_recharge_consume;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_INVESTMENT)             -> lib_custom_act_investment;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_DAILY_TARGET)           -> lib_custom_act_do_daily_target;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_REPEAT_RECHARGE_REWARD) -> lib_custom_act_do_repeat_recharge_reward;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_DAILY_ACTIVITY)         -> lib_custom_act_do_daily_activity;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_ACT_EXCHANGE)           -> lib_custom_act_do_act_exchange;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_CONTINUE_CONSUME)       -> lib_custom_act_do_continue_consume;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_LIMIT_BUY)              -> lib_custom_act_do_limit_buy;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_COLWORD)                -> lib_custom_act_do_colword;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_JOY_WISH)               -> lib_custom_act_do_joy_wish;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_VIP_BAG_ONSALE)         -> lib_custom_act_do_vip_bag_onsale;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_LIMIT_GIFT)             -> custom_act_limit_gift;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_RECHARGE)               -> lib_custom_act_do_recharge;
get_mod_by_acttype(?CUSTOM_ACT_THEME_FIRST_RECHARGE)        -> lib_custom_act_do_recharge;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_LIMIT_MALL)             -> limit_mall;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_SMALL_RECHARGE)         -> custom_act_small_recharge;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_FREE_GIFT)              -> zero_gift;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_CIRCLE_FOSTER)          -> custom_act_circle_foster;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_SELLSWORDS_RESUPPLY)    -> custom_act_sellswords_resupply;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_HOPE_GIFT)              -> custom_act_hope_gift;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_DAILY_CHARGE_CONSUME)   -> custom_act_pellet;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_GROUP_BUY)              -> group_buy_api;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_MOBILIZE)               -> custom_act_mobilize;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_SINGLE_RECHARGE)        -> custom_act_single_recharge;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_CONSUME)                -> lib_custom_act_do_consume;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_LUCKY_TURNTABLE)        -> lib_lucky_turntable;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_SECKILL)                -> custom_act_seckill;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_SIGN_REWARD)            -> sign_reward;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_DISCOUNT_MALL)          -> lib_custom_act_do_discount_mall;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_VIE_RANK)               -> mod_vie_rank_center;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_ADVENTURE_ROLE)         -> custom_act_adventure;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_PUZZLE)                 -> puzzle;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_GREAT_REWARD)           -> lib_great_rewards;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_JOURNEY)                -> custom_act_journey;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_JUMP_ACT)               -> custom_act_jump_act;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_UNITE_BUFF)             -> custom_unite_buff;
get_mod_by_acttype(?CUSTOM_ACT_TYPE_SAKURA_GIFT)            -> sakura_gift;
get_mod_by_acttype(_ActType) -> undefined.

%% ---------------------- 各个分发器接口 -----------------------------
%% 将活动具体逻辑从定制活动流程中解耦
%% 在流程中有需要分发的具体逻辑时添加子分发器
%% ----------------------- lib_custom_act_check ---------------------
-spec check_cfg(ActCfg) -> Return when
    ActCfg :: #custom_act_cfg{},		%% 活动配置
    Return :: true | false.             %% 是否可开启
check_cfg(#custom_act_cfg{type = ActType, subtype = SubType} = ActCfg) ->
    Args = [ActCfg],
    dispatcher(ActType, SubType, Args, check_cfg, {func, lib_custom_act_do_normal, check_cfg, Args}).

%% 检测领奖条件是否满足
-spec check_receive_reward_conditions(Info, ActInfo, RwCfg) -> Return when
    Info    :: any(), 					%% 用于检测的信息 可以是PS、RoleId;当活动类型为投资时可能为投资信息
    ActInfo :: #act_info{},				%% 开启中的活动数据
    RwCfg   :: #custom_act_reward_cfg{},%% 奖励配置
    Return 	:: true | {false, ErrCode},	%% 返回数据依据调用的方法决定
    ErrCode :: integer().				%% 错误码
check_receive_reward_conditions(Info, #act_info{key = {ActType, SubType}} = ActInfo, RwCfg) ->
    Args = [Info, ActInfo, RwCfg],
    dispatcher(ActType, SubType, Args, check_receive_reward_conditions, {func, lib_custom_act_do_normal, check_receive_reward_conditions, Args}).

%% 检测领取奖励次数
-spec check_reward_receive_times(Player, ActInfo, RwCfg) -> Return when
    Player  :: #player_status{},		%% 玩家数据
    ActInfo :: #act_info{},				%% 开启中的活动数据
    RwCfg   :: #custom_act_reward_cfg{},%% 奖励配置
    Return 	:: {true, NewReceiveTimes} | false,	%% 返回数据依据调用的方法决定
    NewReceiveTimes :: integer().		%% 新的已领取次数，返回的次数作为领取后的最新领取次数保存
check_reward_receive_times(Player, #act_info{key = {ActType, SubType}} = ActInfo, RwCfg) ->
    Args = [Player, ActInfo, RwCfg],
    dispatcher(ActType, SubType, Args, check_reward_receive_times, {func, lib_custom_act_do_normal, check_reward_receive_times, Args}).

%% 领奖特殊检测
-spec check_receive_reward_special(Player, ActInfo, RwCfg) -> Return when
    Player  :: #player_status{},		%% 玩家数据
    ActInfo :: #act_info{},				%% 开启中的活动数据
    RwCfg   :: #custom_act_reward_cfg{},%% 奖励配置
    Return 	:: {true, RewardList} | {false, ErrCode},	%% 返回数据依据调用的方法决定
    RewardList :: list(),				%% 奖励物品列表 [{GoodsType, GoodsId, Num}]
    ErrCode :: integer().				%% 错误码
check_receive_reward_special(Player, #act_info{key = {ActType, SubType}} = ActInfo, RwCfg) ->
    Args = [Player, ActInfo, RwCfg],
    dispatcher(ActType, SubType, Args, check_receive_reward_special, {func, lib_custom_act_do_normal, check_receive_reward_special, Args}).


%% ----------------------- lib_custom_act ---------------------
%% 开启活动通知其他模块
-spec notify_other_module(ActStatus, IsKfActType, ActInfo, Stime, Etime) -> any() when
    ActStatus  	:: integer(),			%% 活动配置
    IsKfActType :: true|false,			%% 返回数据依据调用的方法决定
    ActInfo 	:: #act_info{},			%% 返回数据依据调用的方法决定
    Stime 		:: integer(),			%% 返回数据依据调用的方法决定
    Etime 		:: integer().			%% 返回数据依据调用的方法决定
notify_other_module(ActStatus, IsKfActType, #act_info{key = {ActType, SubType}} = ActInfo, Stime, Etime) ->
    case custom_act_personal:is_personal_act(ActType) of
        true  -> custom_act_personal:notify_other_module(ActStatus, ActInfo);
        false ->
            Args = [ActStatus, IsKfActType, ActInfo, Stime, Etime],
            dispatcher(ActType, SubType, Args, notify_other_module, {func, lib_custom_act_do_normal, notify_other_module, Args})
    end.

%% 特殊活动开启时的额外检测
-spec do_timer_check_other(ActCfg, ArgsMap) -> true | false when
    ActCfg  :: #custom_act_cfg{},		%% 活动配置
    ArgsMap :: map().					%% 返回数据依据调用的方法决定
do_timer_check_other(#custom_act_cfg{type = ActType, subtype = SubType} = ActCfg, ArgsMap) ->
    Args = [ActCfg, ArgsMap],
    dispatcher(ActType, SubType, Args, do_timer_check_other, {func, lib_custom_act_do_normal, do_timer_check_other, Args}).

%% 请求励领取状态
-spec ask_reward_status(Player, Type, SubType) -> Return when
    Player  :: #player_status{},		%% 玩家数据
    Type 	:: integer(),
    SubType :: integer(),
    Return 	:: any().					%% 返回数据依据调用的方法决定
ask_reward_status(Player, Type, SubType) ->
    case custom_act_personal:is_personal_act(Type) of
        true  -> custom_act_personal:ask_reward_status(Player, Type, SubType);
        false ->
            Args = [Player, Type, SubType],
            dispatcher(Type, SubType, Args, ask_reward_status, {func, lib_custom_act_do_normal, ask_reward_status, Args})
    end.

%% 请求励领取状态
-spec send_reward_status(Player, ActInfo) -> Return when
    Player  :: #player_status{},		%% 玩家数据
    ActInfo :: #act_info{},				%% 开启中的活动数据
    Return 	:: any().					%% 返回数据依据调用的方法决定
send_reward_status(Player, #act_info{key = {ActType, SubType}} = ActInfo) ->
    Args = [Player, ActInfo],
    dispatcher(ActType, SubType, Args, send_reward_status, {func, lib_custom_act_do_normal, send_reward_status, Args}).


%% 计算奖励可领取状态
-spec count_reward_status(Player, ActInfo, Progress, RwCfg) -> Return when
    Player  :: #player_status{},		%% 玩家数据
    ActInfo :: #act_info{},				%% 开启中的活动数据
    Progress :: integer(),
    RwCfg   :: #custom_act_reward_cfg{},%% 奖励配置
    Return 	:: integer().				%% 可领取状态 0条件未满足 1可领取 2已领取 3奖励超时
count_reward_status(Player, #act_info{key = {ActType, SubType}} = ActInfo, Progress, RwCfg) ->
    Args = [Player, ActInfo, Progress, RwCfg],
    dispatcher(ActType, SubType, Args, count_reward_status, {func, lib_custom_act_do_normal, count_reward_status, Args}).

%% 计算奖励领取次数
-spec count_receive_times(Player, ActInfo, RwCfg) -> Return when
    Player  :: #player_status{},		%% 玩家数据
    ActInfo :: #act_info{},				%% 开启中的活动数据
    RwCfg   :: #custom_act_reward_cfg{},%% 奖励配置
    Return 	:: integer().				%% 领取次数
count_receive_times(Player, #act_info{key = {ActType, SubType}} = ActInfo, RwCfg) ->
    Args = [Player, ActInfo, RwCfg],
    dispatcher(ActType, SubType, Args, count_receive_times, {func, lib_custom_act_do_normal, count_receive_times, Args}).

%% 计算奖励进度
-spec count_reward_progress(Player, ActInfo, CommonProgress, RwCfg) -> Return when
    Player  :: #player_status{},		%% 玩家数据
    ActInfo :: #act_info{},				%% 开启中的活动数据
    CommonProgress :: integer(),
    RwCfg   :: #custom_act_reward_cfg{},%% 奖励配置
    Return 	:: integer().				%% 默认为0
count_reward_progress(Player, #act_info{key = {ActType, SubType}} = ActInfo, CommonProgress, RwCfg) ->
    Args = [Player, ActInfo, CommonProgress, RwCfg],
    dispatcher(ActType, SubType, Args, count_reward_progress, {func, lib_custom_act_do_normal, count_reward_progress, Args}).

%% 计算通用奖励进度
count_common_progress(Player, #act_info{key = {ActType, SubType}} = ActInfo) ->
    Args = [Player, ActInfo],
    dispatcher(ActType, SubType, Args, count_common_progress, {func, lib_custom_act_do_normal, count_common_progress, Args}).

%% 领取奖励
-spec receive_reward(Player, ActType, SubType, GradeId) -> Return when
    Player  :: #player_status{},			%% 玩家数据
    ActType :: integer(),					%% 活动类型
    SubType :: integer(),					%% 活动子类
    GradeId :: integer(),					%% 奖励档次
    Return  :: {ok, #player_status{}}|any().
receive_reward(Player, ActType, SubType, GradeId) ->
    Args = [Player, ActType, SubType, GradeId],
    dispatcher(ActType, SubType, Args, receive_reward, {func, lib_custom_act_do_normal, receive_reward, Args}).

%% 领取红点礼包奖励
-spec receive_red_gift_reward(Player, ActType, SubType, GradeId) -> Return when
    Player :: #player_status{},
    ActType :: integer(),
    SubType :: integer(),
    GradeId :: integer(),
    Return :: {ok, #player_status{}}|any().
receive_red_gift_reward(Player, ActType, SubType, GradeId) ->
    Args = [Player, ActType, SubType, GradeId],
    dispatcher(ActType, SubType, Args, receive_red_gift_reward, {func, lib_custom_act_do_normal, receive_red_gift_reward, Args}).

%% 领取奖励
-spec do_receive_reward(Player, ActInfo, RewardList, RwCfg) -> Return when
    Player  	:: #player_status{},			%% 玩家数据
    ActInfo 	:: #act_info{},					%% 开启中的活动数据
    RewardList	:: list(),						%% 奖励列表{GoodsType, GoodsId, Num}
    RwCfg   	:: #custom_act_reward_cfg{},	%% 奖励配置
    Return  	:: any().						%%
do_receive_reward(Player, #act_info{key = {ActType, SubType}} = ActInfo, RewardList, RwCfg) ->
    Args = [Player, ActInfo, RewardList, RwCfg],
    dispatcher(ActType, SubType, Args, do_receive_reward, {func, lib_custom_act_do_normal, do_receive_reward, Args}).


%% 领奖日志额外数据 记录在定制活动奖励日志的'附加记录'字段
-spec get_extra_log(RwCfg) -> Return when
    RwCfg  :: #custom_act_reward_cfg{},
    Return :: list().
get_extra_log(#custom_act_reward_cfg{type = ActType, subtype = SubType} = RwCfg) ->
    Args = [RwCfg],
    dispatcher(ActType, SubType, Args, get_extra_log, {func, lib_custom_act_do_normal, get_extra_log, Args}).

%% 更新领取次数
-spec update_receive_times_normal(Player, ActType, SubType, GradeId, NewReceiveTimes) -> Return when
    Player  		:: #player_status{},		%% 玩家数据
    ActType 		:: integer(),				%% 活动类型
    SubType 		:: integer(),				%% 活动子类
    GradeId 		:: integer(),				%% 奖励档次
    NewReceiveTimes :: integer(),				%% 玩家id
    Return  		:: any().					%% 检测所需数据，根据不同活动返回也不同。默认为RoleId
update_receive_times_normal(Player, ActType, SubType, GradeId, NewReceiveTimes) ->
    Args = [Player, ActType, SubType, GradeId, NewReceiveTimes],
    dispatcher(ActType, SubType, Args, update_receive_times_normal, {func, lib_custom_act_do_normal, update_receive_times_normal, Args}).


%% ----------------------- lib_custom_act_api ------------------------
%% 活动结束发送未领取的奖励
send_forgot_rewards(#act_info{key = {ActType, SubType}} = ActInfo) ->
    Args = [ActInfo],
    dispatcher(ActType, SubType, Args, send_forgot_rewards, {func, lib_custom_act_api, send_forgot_rewards_common, Args}).

%% 检测活动结束时是否有忘记领取的奖励 {ok, 可领取次数} | false
-spec check_has_rewards_for_forget(RoleId, ActInfo, RwCfg, GotTimes) -> Return when
    RoleId  :: integer(),					%% 玩家id
    ActInfo :: #act_info{},					%% 开启中活动数据
    RwCfg   :: #custom_act_reward_cfg{},	%% 奖励配置
    GotTimes:: integer(),					%% 已领取次数
    Return  :: {ok, CanReceiveTimes}|false, %% false为没有
    CanReceiveTimes :: integer().			%% 可领取次数
check_has_rewards_for_forget(RoleId, #act_info{key = {ActType, SubType}} = ActInfo, RwCfg, GotTimes) ->
    Args = [RoleId, ActInfo, RwCfg, GotTimes],
    dispatcher(ActType, SubType, Args, check_has_rewards_for_forget, {func, lib_custom_act_do_normal, check_has_rewards_for_forget, Args}).

%% 检测合服时是否有未领取的奖励 {ok, 可领取次数} | false
-spec check_has_rewards_for_merge(RoleId, ActInfo, RwCfg, GotTimes) -> Return when
    RoleId  :: integer(),					%% 玩家id
    ActInfo :: #act_info{},					%% 开启中活动数据
    RwCfg   :: #custom_act_reward_cfg{},	%% 奖励配置
    GotTimes:: integer(),					%% 已领取次数
    Return  :: {ok, CanReceiveTimes}|false, %% 默认为false
    CanReceiveTimes :: integer().			%% 可领取次数
check_has_rewards_for_merge(RoleId, #act_info{key = {ActType, SubType}} = ActInfo, RwCfg, GotTimes) ->
    Args = [RoleId, ActInfo, RwCfg, GotTimes],
    dispatcher(ActType, SubType, Args, check_has_rewards_for_merge, {func, lib_custom_act_do_normal, check_has_rewards_for_merge, Args}).

%% 获取玩家定制活动的检测数据 无固定返回，默认RoleId
-spec make_role_info_for_check(ActType, SubType, RoleId) -> Return when
    ActType :: integer(),					%% 活动类型
    SubType :: integer(),					%% 活动子类
    RoleId  :: integer(),					%% 玩家id
    Return  :: any().						%% 检测所需数据，根据不同活动返回也不同。默认为RoleId
make_role_info_for_check(ActType, SubType, RoleId) ->
    Args = [ActType, SubType, RoleId],
    dispatcher(ActType, SubType, Args, make_role_info_for_check, {func, lib_custom_act_do_normal, make_role_info_for_check, Args}).

%% 用于判断该活动是否需要0点更新
-spec is_need_daily_update(Player, ActInfo) -> Return when
    Player  :: #player_status{},		%% 玩家数据
    ActInfo :: #act_info{},				%% 开启中的活动数据
    Return 	:: true | false.			%% 是否需要更新
is_need_daily_update(Player, #act_info{key = {ActType, SubType}} = ActInfo) ->
    Args = [Player, ActInfo],
    dispatcher(ActType, SubType, Args, is_need_daily_update, {func, lib_custom_act_do_normal, is_need_daily_update, Args}).

%% 获取参与活动的玩家
-spec get_act_roles(ActInfo) -> Return when
    ActInfo :: #act_info{},				%% 开启中的活动数据
    Return  :: [RoleId],				%% 参与活动的玩家id列表
    RoleId  :: integer().				%% 玩家id
get_act_roles(#act_info{key = {ActType, SubType}} = ActInfo) ->
    Args = [ActInfo],
    dispatcher(ActType, SubType, Args, get_act_roles, {func, lib_custom_act_do_normal, get_act_roles, Args}).

%% 计算领奖次数
-spec calc_got_reward_times(StatusCustomAct, ActInfo, GradeId) -> Return when
    StatusCustomAct  :: #status_custom_act{},
    ActInfo          :: #act_info{},
    GradeId          :: integer(),
    Return           :: integer().
calc_got_reward_times(StatusCustomAct, #act_info{key = {ActType, SubType}} = ActInfo, GradeId) ->
    Args = [StatusCustomAct, ActInfo, GradeId],
    dispatcher(ActType, SubType, Args, calc_got_reward_times, {func, lib_custom_act_do_normal, calc_got_reward_times, Args}).

%% 奖励物品额外处理，有效时间转换
-spec count_act_reward_other(ActInfo, RewardList) -> NewRewardList when
    ActInfo          :: #act_info{},
    RewardList       :: list(),
    NewRewardList    :: list().
count_act_reward_other(#act_info{key = {ActType, SubType}} = ActInfo, RewardList) ->
    Args = [ActInfo, RewardList],
    dispatcher(ActType, SubType, Args, count_act_reward_other, {func, lib_custom_act_do_normal, count_act_reward_other, Args}).

%% ------------------------------------------------------------------
%% 跨服中心检测跨服活动状态改变，通知其他进程
-spec kf_notify_other_module(ActStatus, ActInfo, Stime, Etime) -> any() when
    ActStatus		 :: integer(),
    ActInfo  		 :: #act_info{},
    Stime    		 :: integer(),
    Etime   		 :: integer().
kf_notify_other_module(ActStatus, #act_info{key = {ActType, SubType}} = ActInfo, Stime, Etime) ->
    Args = [ActStatus, ActInfo, Stime, Etime],
    dispatcher(ActType, SubType, Args, kf_notify_other_module, {func, lib_custom_act_do_normal, kf_notify_other_module, Args}).

%% ------------------------------------------------------------------
%% 角色差异化活动初始化
-spec init_personal_act_data(Player, ActInfo) -> any() when
    Player		 :: #player_status{},
    ActInfo  	 :: #act_info{}.
init_personal_act_data(Player, #act_info{key = {ActType, SubType}} = ActInfo) ->
    Args = [Player, ActInfo],
    dispatcher(ActType, SubType, Args, init_personal_act_data, {func, custom_act_personal, init_personal_act_data, Args}).

%% 请求通用活动红点礼包状态
-spec ask_act_red_gift_status(Player, Type, SubType) -> Return when
    Player  :: #player_status{},        %% 玩家数据
    Type    :: integer(),
    SubType :: integer(),
    Return  :: any().                   %% 返回数据依据调用的方法决定
ask_act_red_gift_status(Player, Type, SubType) ->
    Args = [Player, Type, SubType],
    dispatcher(Type, SubType, Args, ask_act_red_gift_status, {func, lib_custom_act_do_normal, ask_act_red_gift_status, Args}).

%% 一键领取奖励
auto_receive_reward(Player, Type, SubType) ->
    Args = [Player, Type, SubType],
    dispatcher(Type, SubType, Args, auto_receive_reward, {func, lib_custom_act_do_normal, auto_receive_reward, Args}).

%% 通用分发器
-spec dispatcher(ActType, SubType, Args, Function, DefaultReturn) -> Return when
    ActType 		:: integer(),		%% 活动类型
    SubType 		:: integer(),		%% 活动子类
    Args    		:: list(),			%% 参数列表
    Function		:: atom(),			%% 要调用的方法
    DefaultReturn	:: term(),			%% 默认返回{func, Mod, Func, Args}|{func, Func, Args}|要返回的默认值
    Return 			:: any().			%% 返回数据依据调用的方法决定
dispatcher(ActType, SubType, Args, Function, DefaultReturn) ->
    ArgsNum = length(Args),
    case get_special_api_mod(ActType, SubType, Function, ArgsNum) of
        undefined ->
            dispatcher_normal(DefaultReturn);
        Module ->
            apply(Module, Function, Args)
    end.

get_special_api_mod(ActType, _SubType, Function, ArgsNum) ->
    Module = get_mod_by_acttype(ActType),
    if
        Module =/= undefined ->
            case lists:member({Function, ArgsNum}, Module:module_info(exports)) of
                true -> Module;
                _ -> undefined
            end;
        true -> undefined
    end.

%%触发通用函数
dispatcher_normal({func, Mod, Fun, Args}) ->
    apply(Mod, Fun, Args);
dispatcher_normal({func, Fun, Args}) ->
    apply(?MODULE, Fun, Args);
%%触发通用返回值
dispatcher_normal(DefaultReturn) ->
    DefaultReturn.