%%% -------------------------------------------------------
%%% @author huangyongxing@yeah.net
%%% @doc
%%% @end
%%% -------------------------------------------------------
-ifndef(CROSS_ZONE_HRL).
-define(CROSS_ZONE_HRL, ok).

%% 保存跨服小分区进程信息的ETS表
-define(CROSS_ZONE_WORKER, cross_zone_worker).

%% 未定义delay_time时，默认的延迟分区时间（毫秒）
-ifdef(DEV_SERVER).
-define(DELAY_DEFAULT, 35000).
-else.
-define(DELAY_DEFAULT, 600000).
-endif.

%% 进程状态标记
-define(STATE_WAITING, 0).                  % 延迟等待状态，暂不接收新节点加入
-define(STATE_RUNNING, 1).                  % 分区运转状态，可加入新节点

%% 进程初始化返回值（也可以作为初始传入参数）
%% （用于约束init回调时返回的结果，未设置的字段使用此处的默认值）
%% 部分字段补充说明：
%% zone_type
%%   open_time  按开服时间（公共）
%%   ...        其他公共的规则（后面视需要补充）
%%   czone      czone模块方式，唯一，有比较独立的分区维护规则（2个同阶子分区合并扩展）
%%   Other      回调模块自定义
%%
%%   关于分区类型为czone的特别说明：
%%     czone模块定义的是标准分区模式，跨服中只有一个该类分区。
%%     大部分功能基于该分区进行数据维护。
%%     此类型下，只有module_state与init_zones有效，
%%     later_join自动设置为true（用于获知节点连接通知），
%%     其他参数在主程序中将忽略，没有实际意义
%% filter
%%   检查过滤节点的接口，真实参数会加上节点信息：[#game_node{} | Args]
%%   filter定义的接口，调用后返回true表示节点参与跨服小分区，否则不参与
%%   如果filter值为undefined，则表示不检查，相当于所有服都参与跨服小分区
-record(zone_init_ret, {
        %% 分区方式
        zone_type       = open_time         :: term()
        %% 跨服小分区中游戏服数量，在模块中进行了范围限制
        ,num_per_zone   = 4                 :: non_neg_integer()
        %% 默认的延迟分区时间（如定义了值为false则表示不自动分区，如果init_zones设置了分区，则不生效）
        ,delay_time     = ?DELAY_DEFAULT    :: non_neg_integer() | false
        %% 后面连接到跨服中心的游戏服是否自动加入到后面分区
        ,later_join     = true              :: boolean()
        %% 检查节点是否参与跨服小分区（可自定义筛选条件，与join_day共同作用）
        ,filter         = undefined         :: {Mod :: atom(), Fun :: atom(), Args :: list()} | undefined
        %% 允许加入跨服小分区的开服天数
        ,join_day       = 0                 :: non_neg_integer()
        %% 回调模块数据，结构由业务实现模块自定义
        ,module_state    = undefined        :: term() | undefined
        %% init_zones初始分区结果（适用于需要保存分区，启动时加载的情况，模板不负责数据保存与加载工作）
        %%      结果为undefined表示未进行分区
        %%      结果为[ZoneInfo :: #zone_info{}]，表示初始已有分区结果（不自动分区，此时delay_time不生效）
        ,init_zones     = undefined         :: list() | undefined
        %% 在特殊分区管理逻辑中，用于存储自定义的分区运算逻辑相关核心数据
        ,zone_sys       = undefined         :: any() | undefined
    }).

%% 进程栈State与回调模块交换数据时的中间参数
%%
%% 跨服小分区模块回调handle_event/3接口时传递的参数
%% 以下两个接口，也会给回调函数增加一个#zone_state{}数据作为首个参数
%% cross_zone:apply_cast_with_data/2
%% cross_zone:apply_call_with_data/2
-record(zone_state, {
        max_zone_id = 0                     % 当前最大的分区编号，业务模块只读
        ,svr_zone_map = #{}                 % 分区的ServerId与ZoneId映射关系，业务模块只读
        ,zone_sys = undefined               % 在特殊分区管理逻辑中，用于存储自定义的分区运算逻辑相关核心数据
        ,module_state = undefined           % 用于记录用户模块自定义的数据，一般功能系统通常只更改此数据进行返回
    }).

%% -------------------------------------------------------
%% 进程字典中存储分区相关核心数据
%% 不要在以下结构中添加额外字段
%%
%% 为保证接口清晰和便于维护，
%% 以下数据结构中，通常只存储与分区管理逻辑相关核心数据，
%%
%% 业务相关数据通常可存储于：
%%      进程状态数据： #zone_proc_state.module_state
%%      进程字典：     #zone_info.zone_data + #zone_svr.svr_data
%%      进程字典：     自行维护的数据结构
%%
%% #zone_info.zone_ext 、 #zone_svr.svr_ext 用于存储特殊
%% 分区管理相关的扩展数据
%% -------------------------------------------------------

%% 跨服分区数据
-record(zone_info, {
        zone_id = 0                         % 分区编号
        ,servers = []                       % 包含的服务器信息 [ #zone_svr{} ]
        ,zone_ext = undefined               % 分区管理扩展信息，由特殊分区方法模块自定义
        ,zone_data = undefined              % 功能模块相关数据
    }).

%% 跨服分区中单节点数据
%% PS：
%% 为保证接口清晰和便于维护，这里通常只存储与分区管理逻辑相关核心数据，
%% 各功能业务数据请自行存储，不要添加在此，通常可存储于module_state
-record(zone_svr, {
        server_id = 0                       % 游戏服server_id
        ,server_num = 0                     % 游戏服server_num
        ,node = undefined                   % 节点信息
        ,conn = true                        % 节点连接状态
        ,svr_ext = undefined                % 分区管理扩展信息，由特殊分区方法模块自定义
        ,svr_data = undefined               % 功能模块相关数据
    }).

%% 跨服小分区进程信息(ETS表中数据结构)
%% （主要用于回调检测，不要添加非必要的字段）
-record(cross_zone_worker, {
        pid = undefined                     % 分区管理进程pid
        ,name = undefined                   % 进程注册名称
        ,later_join = true                  % 是否需要通知回调
        ,proc_state = ?STATE_RUNNING        % 进程状态标记
    }).

-endif.
