%%%-------------------------------------------------------------------
%%% @doc    经验海副本 - 管理进程
%%% (负责记录玩家数据，分线数据和离线重连处理)
%%% Module  : mod_exp_sea.erl
%%% Created : 2021-07-27
%%% @end
%%% @author : tyl
%%%-------------------------------------------------------------------
-module(mod_exp_sea).

-include("exp_sea.hrl").
-include("common.hrl").
-include("server.hrl").
-include("scene.hrl").
-include("role.hrl").
-include("figure.hrl").
-include("predefine.hrl").
-include("errcode.hrl").

%% API
-export([
	get_floor_pool/1        %% 获取分线Id
	,enter_scene/3
	,exit_scene/3
]).

-export([start_link/0, cast/1 ,call/1 ,info/1]).

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

%% ---------------------------------------------------------------------------
%% 获取分线
get_floor_pool(Floor) ->
	gen_server:call(?MODULE, {get_floor_pool, Floor}, 3000).

enter_scene(RoleId, Floor, PoolId) ->
	gen_server:cast(?MODULE, {enter_scene, RoleId, Floor, PoolId}).

%% 退出场景后重置数据
exit_scene(RoleId, Floor, PoolId) ->
	gen_server:cast(?MODULE, {exit_scene, RoleId, Floor, PoolId}).

%% ---------------------------------------------------------------------------
start_link() ->
	gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

cast(Msg) ->
	gen_server:cast(?MODULE, Msg).

call(Msg) ->
	gen_server:call(?MODULE, Msg).

info(Msg) ->
	erlang:send(?MODULE, Msg).

init([]) ->
	process_flag(trap_exit, true),
	State = #exp_sea_mgr{},
	{ok, State}.

handle_call(Msg, From, State) ->
	try do_handle_call(Msg, From, State) of
		Reply ->
			Reply
	catch ?EXCEPTION(Class, Reason, StackTrace) ->
		Error = {Class, Reason, StackTrace},
		?ERR("~w:handle_call error:~p~n", [?MODULE, Error]),
		{error, Reason}
	end.

handle_cast(Msg, State) ->
	try do_handle_cast(Msg, State) of
		Result ->
			Result
	catch ?EXCEPTION(Class, Reason, StackTrace) ->
		Error = {Class, Reason, StackTrace},
		?ERR("~w:handle_cast error:~p~n", [?MODULE, Error]),
		{noreply, State}
	end.

handle_info(Info, State) ->
	try do_handle_info(Info, State) of
		Result ->
			Result
	catch ?EXCEPTION(Class, Reason, StackTrace) ->
		Error = {Class, Reason, StackTrace},
		?ERR("~w:handle_info error:~p~n", [?MODULE, Error]),
		{noreply, State}
	end.

terminate(_Reason, _State) ->
	ok.

code_change(_OldVsn, State, _Extra) ->
	{ok, State}.

%% ---------------------------------------------------------------------------
do_handle_call({get_floor_pool, Floor}, _From, State) ->
	#exp_sea_mgr{scene_pools = PoolMap} = State,
	Pools = maps:get(Floor, PoolMap, []),
	MaxNum = case data_scene_other:get(?EXP_SEA_SCENE) of
		         #ets_scene_other{room_max_people = TMaxNum} -> TMaxNum;
		         _ -> ?EXP_SEA_MAX_PEOPLE
	         end,
	PoolId =
	case select_floor_pool(Floor, Pools, MaxNum) of
		{new, TPoolId} ->
			%% 创建分线 && 生成怪物
			exp_sea_logic:create_mons(?EXP_SEA_SCENE, TPoolId, 0),
			TPoolId;
		{_, TPoolId} ->
			TPoolId
	end,
	%% 先保存新的分线
	NewPools = case lists:keyfind(PoolId, 1, Pools) of
		           {_, _Num} -> Pools;
		           _ -> lists:keystore(PoolId, 1, Pools, {PoolId, 0})
	           end,
	NewPoolMap = maps:put(Floor, NewPools, PoolMap),
	NewState = State#exp_sea_mgr{scene_pools = NewPoolMap},
	{reply, PoolId, NewState};

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

%% ---------------------------------------------------------------------------
do_handle_cast({enter_scene, RoleId, Floor, PoolId}, State) ->
	#exp_sea_mgr{role_map = RoleMap, scene_pools = PoolMap} = State,

	%% 玩家数据
	InitRoleRecord = #role_exp_sea_record{},
	RoleRecord = maps:get(RoleId, RoleMap, InitRoleRecord),
	NewRoleRecord = RoleRecord#role_exp_sea_record{
		scene_id = ?EXP_SEA_SCENE, pool_id = PoolId, copy_id = RoleId
	},
	NewRoleMap = maps:put(RoleId, NewRoleRecord, RoleMap),

	%% 场景数据
	Pools = maps:get(Floor, PoolMap, []),
	NewPools =
	case lists:keyfind(PoolId, 1, Pools) of
		{_, Num} -> lists:keystore(PoolId, 1, Pools, {PoolId, Num + 1});
		_ -> lists:keystore(PoolId, 1, Pools, {PoolId, 1})
	end,
	NewPoolMap = maps:put(Floor, NewPools, PoolMap),
	NewState = State#exp_sea_mgr{role_map = NewRoleMap, scene_pools = NewPoolMap},
	{noreply, NewState};

do_handle_cast({exit_scene, RoleId, Floor, PoolId}, State) ->
	#exp_sea_mgr{role_map = RoleMap, scene_pools = PoolMap} = State,
	% InitRoleRecord = #role_exp_sea_record{},
	% RoleRecord = maps:get(RoleId, RoleMap, InitRoleRecord),
	% #role_exp_sea_record{
	% 	scene_id = SceneId, pool_id = PoolId, copy_id = CopyId
	% } = RoleRecord,
	% lib_mon:clear_scene_mon(SceneId, PoolId, CopyId, 1),

	%% 玩家数据
	NewRoleRecord = #role_exp_sea_record{},
	NewRoleMap = maps:put(RoleId, NewRoleRecord, RoleMap),

	%% 场景数据
	Pools = maps:get(Floor, PoolMap, []),
	NewPools =
		case lists:keyfind(PoolId, 1, Pools) of
			{_, Num} -> lists:keystore(PoolId, 1, Pools, {PoolId, max(0, Num - 1)});
			_ -> Pools
		end,
	NewPoolMap = maps:put(Floor, NewPools, PoolMap),

	NewState = State#exp_sea_mgr{role_map = NewRoleMap, scene_pools = NewPoolMap},
	{noreply, NewState};

do_handle_cast(_Info, State) ->
	?ERR("Handle unknow msg[~w]~n", [_Info]),
	{noreply, State}.

%% ---------------------------------------------------------------------------
do_handle_info(_Info, State) ->
	?ERR("Handle unknow msg[~w]~n", [_Info]),
	{noreply, State}.


select_floor_pool(Floor, Pools, MaxNum) ->
	case Pools of
		[] ->
			PoolId = Floor * 2000 + 1,
			{new, PoolId};
		_ ->
			NotFullPools = [{TId, TNum}||{TId, TNum}<-Pools, TNum < MaxNum],
			SortPools = lists:keysort(2, NotFullPools),
			case SortPools of
				[{PoolId, _}|_] -> {old, PoolId};
				_ ->
					PoolIds = [TPoolId||{TPoolId, _}<-Pools],
					PoolId  = lists:max(PoolIds) + 1,
					{new, PoolId}
			end
	end.

