%%%-----------------------------------
%%% @Author		: gaomeng 595088880@qq.com
%%% @Created	: 2017/1/30
%%% @Doc		: 发送相关
%%%-----------------------------------
-module(lib_send).
-include("common.hrl").
-include("scene.hrl").
-include("move.hrl").
-include("guild.hrl").
-include_lib("stdlib/include/ms_transform.hrl").

-export([
   send/2,
   pack_send/3,
   pack_send/4,
   pack_send_msg/2,

   send_to_scene/1,
   send_to_scene/2,

   async_send_scene/2,
   async_send_scene/3,

   send_to_world/1,
   send_to_world/2,
   send_to_world/3,

   send_to_guild/3,

   async_online/3,
   async_online/4
]).

%% @doc 全服异步在线玩家执行函数
async_online(M, F, Args) ->
   async_online(0, M, F, Args).

async_online(RoleId, M, F, Args) ->
   spawn(fun() ->
      case ets:info(?ETS_ONLINE) of
         undefined ->
            ok;
         _ ->
            L = ets:tab2list(?ETS_ONLINE),
            [svr_role:apply(async, Pid, {M, F, Args}) || #role{pid = Pid, id = TemRoleId} <- L, RoleId =/= TemRoleId]
      end
         end).

%% @doc 公会广播
send_to_guild(GuildId, Cmd, List) when is_integer(GuildId) ->
   svr_guild:apply(async, GuildId, {lib_send, send_to_guild, [Cmd, List]});
send_to_guild(#guild{members = Members}, Cmd, List) ->
   case catch prot:encode(Cmd, List) of
      {ok, Bin} ->
         F = fun(#guild_member{role_id = RoleId}) ->
            case lib_account:get_role_pid(RoleId) of
               Pid when is_pid(Pid) ->
                  send(Pid, Bin);
               _ ->
                  ok
            end
             end,
         [F(M) || M <- Members];
      Ret ->
         ?ERR("Cmd:~w use pack_send, reason:~w", [Cmd, Ret]),
         ok
   end,
   ok.

%%世界广播
send_to_world(RoleId, Bin) ->
   spawn(fun() ->
      [send(Sid, Bin) || #role{id = Id, sid = Sid} <- ets:tab2list(?ETS_ONLINE), Id =/= RoleId]
         end).

send_to_world(Bin) ->
   spawn(fun() ->
      [send(Sid, Bin) || #role{sid = Sid} <- ets:tab2list(?ETS_ONLINE)]
         end).

%% @doc 世界广播(有等级限制)
send_to_world(level, ReqLevel, Bin) ->
   spawn(fun() ->
      [send(Sid, Bin) || #role{level = Level, sid = Sid} <- ets:tab2list(?ETS_ONLINE), Level >= ReqLevel]
         end);

send_to_world(RoleId, Cmd, List) ->
   case catch prot:encode(Cmd, List) of
      {ok, Bin} ->
         spawn(fun() ->
            [send(Sid, Bin) || #role{id = Id, sid = Sid} <- ets:tab2list(?ETS_ONLINE), Id =/= RoleId]
               end);
      Ret ->
         ?ERR("Cmd:~w use pack_send, reason:~w", [Cmd, Ret]),
         ok
   end.

%%场景广播
send_to_scene(Rid, BinData) ->
   AllRole = svr_scene_role:get_all(),
   F = fun(Role) ->
      case Role#scene_role.id =/= Rid of
         true ->
            send(Role#scene_role.sid, BinData);
         _ ->
            ok
      end
       end,
   [F(P) || P <- AllRole].

send_to_scene(BinData) ->
   AllRole = svr_scene_role:get_all(),
   F = fun(Role) ->
      send(Role#scene_role.sid, BinData)
       end,
   [F(P) || P <- AllRole].

%% @doc 其他进程发送场景广播
async_send_scene(ScenePid, BinData) ->
   async_send_scene(ScenePid, BinData, 0).

async_send_scene(ScenePid, BinData, RoleId) when is_pid(ScenePid) ->
   svr_scene:apply(async, ScenePid, {svr_scene_info, async_send_scene, [RoleId, BinData]});
async_send_scene(_, _, _) ->
   ok.

%% @doc 打包
pack_send(Node, Rid = #node_rid{id = RoleId}, Cmd, List) ->
   case Node =:= node() of
      true ->
         pack_send(RoleId, Cmd, List);
      _ ->
         svr_kfnode:send_role(Node, [Rid], lib_send, pack_send, [Cmd, List])
   end.

pack_send(RoleId, Cmd, List) when is_integer(RoleId) ->
   case lib_account:get_role_pid(RoleId) of
      Pid when is_pid(Pid) ->
         pack_send(Pid, Cmd, List);
      _ ->
         ok
   end;
pack_send(#node_rid{id = RoleId}, Cmd, List) ->
   pack_send(RoleId, Cmd, List);
pack_send(#role{sid = Sid}, Cmd, List) ->
   pack_send(Sid, Cmd, List);
pack_send(Sid, Cmd, List) ->
   case misc:is_process_alive(Sid) of
      true ->
         case catch prot:encode(Cmd, List) of
            {ok, Bin} ->
               send(Sid, Bin);
            Ret ->
               ?ERR("Cmd:~w use pack_send, reason:~w", [Cmd, Ret]),
               ok
         end;
      _R ->
         ok
   end,
   ok.

send(#role{sid = Sid}, Bin) ->
   send(Sid, Bin);
send(Sid, Bin) ->
   case catch config:config(print_send_cmd) of
      true ->
         <<_L:32, Cmd:32, _Data/binary>> = Bin,
         svr_handle_mgr:listen_cmd(Cmd, byte_size(Bin));
      _ ->
         ok
   end,
   Sid ! {'send', Bin},
   ok.

pack_send_msg(#node_rid{id = RoleId}, List) ->
   pack_send_msg(RoleId, List);
pack_send_msg(RoleId, List) when is_integer(RoleId) ->
   case ets:lookup(?ETS_ONLINE, RoleId) of
      [#role{sid = Sid} | _] ->
         case misc:is_process_alive(Sid) of
            true ->
               pack_send_msg(Sid, List);
            _ ->
               ok
         end;
      _ ->
         ok
   end;
pack_send_msg(#role{sid = Sid}, List) ->
   pack_send_msg(Sid, List);
pack_send_msg(Sid, [Type, {Code, Vals}]) ->
   pack_send_msg(Sid, [Type, 0, Code, Vals]);
pack_send_msg(Sid, [Type, Code]) ->
   pack_send_msg(Sid, [Type, 0, Code, ""]);
pack_send_msg(Sid, [Type, SubType, {Code, Vals}]) ->
   pack_send_msg(Sid, [Type, SubType, Code, Vals]);
pack_send_msg(Sid, [Type, SubType, Code]) ->
   pack_send_msg(Sid, [Type, SubType, Code, ""]);
pack_send_msg(Sid, List) ->
   pack_send(Sid, 10100, List),
   ok.
