%% --------------------------------
%% module   :mod_legion_mgr.erl
%% desc     :跨服指挥室保存
%% author   :zmh
%% time     :21/01/25
%% --------------------------------

-module (mod_legion_mgr).

-behaviour (gen_server).

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

-export ([
    start_link/0,
    get_director_roles/4,
    report_directors/2,
    upload_figure/3,
    res_upload_figure/4,
    load_director_map/0,
    check_point_mass/7
    ]).


-include("kf_legion.hrl").
-include("figure.hrl").
-include("def_fun.hrl").
-include("czone.hrl").
-include("common.hrl").
-include("errcode.hrl").

%% 同步形象数据
-ifdef(DEV_SERVER).
-define(UPLOAD_TIME, 15000).
-else.
-define(UPLOAD_TIME, (900 * 1000)).
-endif.


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

get_director_roles(Zone,Fact,Node,RoleID)->
    gen_server:cast(?MODULE,{get_director_roles,Zone,Fact,Node,RoleID}).

%%指挥官上报
report_directors(Type,TempRoles)->
    gen_server:cast(?MODULE,{report_directors,Type,TempRoles}).

%%形象上传
upload_figure(Zone,Fact,Figure)->
    gen_server:cast(?MODULE,{upload_figure,Zone,Fact,Figure}).

%%请求得到上报
res_upload_figure(Zone,Fact,RoleID,Figure)->
    gen_server:cast(?MODULE,{res_upload_figure,Zone,Fact,RoleID,Figure}).

%% 沙盘插旗检查
check_point_mass(Zone, Fact, Node, RoleID, Name, PointId, Status) ->
    gen_server:cast(?MODULE, {check_point_mass, Zone, Fact, Node, RoleID, Name, PointId, Status}).

init(_) ->
    erlang:send_after(1000, self(), {init_director}),
    {ok, #legion_mgr{}}.


handle_call(Msg, From, State) ->
    try
        do_handle_call(Msg, From, State)
    catch _:_Error ->
        io:format("do_handle_call Msg:~p, Error:~p, ~p~n", [Msg, _Error, erlang:get_stacktrace()]),
        {reply, error, State}
    end.

handle_cast(Msg, State) ->
    try
        do_handle_cast(Msg, State)
    catch _:_Error ->
        io:format("handle_cast Msg:~p, Error:~p, ~p~n", [Msg, _Error, erlang:get_stacktrace()]),
        {noreply, State}
    end.

handle_info(Msg, State) ->
    try
        do_handle_info(Msg, State)
    catch _:_Error ->
        io:format("handle_info Msg:~p~n Error:~p~n ~p~n", [Msg, _Error, erlang:get_stacktrace()]),
        {noreply, State}
    end.

terminate(_Reason, _State) ->
    ok.

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


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

do_handle_cast({get_director_roles,Zone,Fact,Node,RoleID},State)->
    #legion_mgr{directors=ZoneMap}=State,
    FactRankMap = maps:get(Zone,ZoneMap,#{}),
    Directors0  = maps:get(Fact,FactRankMap,[]),
    Directors   = pack_60300(Directors0,[]),
    {ok,Bin}    = pt_603:write(60300,[Directors]),
    lib_server_send:send_to_uid(Node,RoleID,Bin),
    {noreply,State};

%%指挥官上报 副官 4
do_handle_cast({report_directors,1,Sevenors},State)->
     #legion_mgr{directors=ZoneMap}=State,
     PosList = [4,5,6,7],
     {UseRoles,NZoneMap} = set_vice_director(Sevenors,PosList,ZoneMap,[]),
     spawn(fun()->timer:sleep(1000),sync_notice_upload(UseRoles) end),
     clusters_center:apply_to_all_node(local_legion_mgr,director_log,[UseRoles]),
     {noreply,State#legion_mgr{directors=NZoneMap}};
%%指挥官上报 主官 3
do_handle_cast({report_directors,_,Threers},State)->
    #legion_mgr{directors=ZoneMap}=State,
    PosList = [1,2,3],
    NZoneMap = set_director(Threers,PosList,ZoneMap),
    clusters_center:apply_to_all_node(local_legion_mgr,director_log,[Threers]),
    {noreply,State#legion_mgr{directors=NZoneMap}};

%%形象上传更新
do_handle_cast({upload_figure,Zone,Fact,Figure},State)->
    #legion_mgr{directors=ZoneMap}=State,
    FactMap = maps:get(Zone,ZoneMap,#{}),
    Directors = maps:get(Fact,FactMap,[]),
    Now = utime:unixtime(),
    NDirectors = update_figure(Directors,Figure,Now,[]),
    NFactMap = maps:put(Fact,NDirectors,FactMap),
    NZoneMap = maps:put(Zone,NFactMap,ZoneMap),
    {noreply,State#legion_mgr{directors=NZoneMap}};

do_handle_cast({res_upload_figure,Zone,Fact,RoleID,Figure},State)->
    #legion_mgr{directors=ZoneMap}=State,
    FactMap = maps:get(Zone,ZoneMap,#{}),
    Directors = maps:get(Fact,FactMap,[]),
    Now = utime:unixtime(),
    NDirectors = update_figure(Directors,Figure,Now,[]),
    NFactMap = maps:put(Fact,NDirectors,FactMap),
    NZoneMap = maps:put(Zone,NFactMap,ZoneMap),
    Node = clusters_center:get_node_by_role_id(RoleID),
    {ok,Bin} = pt_603:write(60306,[Figure,Now]),
    lib_server_send:send_to_uid(Node,RoleID,Bin),
    {noreply,State#legion_mgr{directors=NZoneMap}};

%% 沙盘插旗判断
do_handle_cast({check_point_mass, Zone, Fact, Node, RoleId, Name, PointId, Status},State)->
    #legion_mgr{directors=ZoneMap}=State,
    FactMap = maps:get(Zone,ZoneMap,#{}),
    Directors = maps:get(Fact,FactMap,[]),
    IsChief =
    case lists:keyfind(RoleId, #director_role.rid, Directors) of
        #director_role{pos = Pos} -> Pos =< 3;
        false -> false
    end,
    cross_point_fight_center:set_mass_status(Zone, Fact, Node, RoleId, Name, PointId, Status, IsChief),
    {noreply,State};

do_handle_cast(_Msg, State) ->
    {noreply, State}.

do_handle_info({init_director},_State)->
    ZoneMap = load_director_map(),
    erlang:send_after(?UPLOAD_TIME,self(),sync_all_figure),
    {noreply,#legion_mgr{directors=ZoneMap}};

%%通知各自上传形象
do_handle_info(sync_all_figure,State)->
    #legion_mgr{directors=ZoneMap}=State,
    Zones = maps:to_list(ZoneMap),
    spawn(fun()-> sync_all_figure(Zones) end),
    {noreply,State};

do_handle_info(_Msg, State) ->
    {noreply, State}.

pack_60300([],Roles)->
    Roles;
pack_60300([H|T],Roles)->
    #director_role{
        pos = Pos,
        rid = Rid,
        figure = Figure0,
        time = Time
    }=H,
    Figure = case Figure0 of
        #figure{}->
            Figure0;
        _->
            #figure{}
    end,
    pack_60300(T,[{Pos,Rid,Figure,Time}|Roles]).

%%副官设置
set_vice_director([],_PosList,ZoneMap,UseRoles)->
    {UseRoles,ZoneMap};
set_vice_director([{Zone,FactRoles}|T],PosList,ZoneMap,UseRoles)->
    FactMap = maps:get(Zone,ZoneMap,#{}),
    [NUseRoles,NFactMap] = set_fact_vice_director(Zone,FactRoles,PosList,FactMap,[]),
    NZoneMap = maps:put(Zone,NFactMap,ZoneMap),
    set_vice_director(T,PosList,NZoneMap,[{Zone,NUseRoles}|UseRoles]).

set_fact_vice_director(_Zone,[],_,FactMap,UseRoles)->
    [UseRoles,FactMap];
set_fact_vice_director(_Zone,[{Fact,Roles}|T],PosList,FactMap,UseRoles)->
    Directors = maps:get(Fact,FactMap,[]),
    [NUseRoles,NDirectors] = do_set_fact_vice_director(Roles,PosList,Directors,[]),
    NFactMap = maps:put(Fact,NDirectors,FactMap),
    set_fact_vice_director(_Zone,T,PosList,NFactMap,[{Fact,NUseRoles}|UseRoles]).

do_set_fact_vice_director([],_PosList,Directors,UseRoles)->
    [UseRoles,Directors];
do_set_fact_vice_director(_,[],Directors,UseRoles)->
    [UseRoles,Directors];
do_set_fact_vice_director([H|T],[Pos|Tail],Directors,UseRoles)->
    #director_role{rid=Rid}=H,
    case lists:keyfind(Rid,#director_role.rid,Directors) of
        #director_role{pos=P} when P=<3->
            do_set_fact_vice_director(T,[Pos|Tail],Directors,UseRoles);
        _->
            NewH = H#director_role{pos=Pos},
            save_director(NewH),
            do_set_fact_vice_director(T,Tail,[NewH|Directors],[NewH|UseRoles])
    end.

%%主官设置
set_director([],_PosList,ZoneMap)->
    ZoneMap;
set_director([{Zone,FactRoles}|T],PosList,ZoneMap)->
    FactMap = maps:get(Zone,ZoneMap,#{}),
    NFactMap = set_fact_director(Zone,FactRoles,PosList,FactMap),
    NZoneMap = maps:put(Zone,NFactMap,ZoneMap),
    set_director(T,PosList,NZoneMap).

set_fact_director(_Zone,[],_,FactMap)->
    FactMap;
set_fact_director(Zone,[{Fact,Roles}|T],PosList,FactMap)->
    batch_del_director(Zone,Fact),
    NDirectors = do_set_fact_director(Roles,PosList,[]),
    NFactMap = maps:put(Fact,NDirectors,FactMap),
    set_fact_director(Zone,T,PosList,NFactMap).

do_set_fact_director([],_PosList,Directors)->
    Directors;
do_set_fact_director(_,[],Directors)->
    Directors;
do_set_fact_director([H|T],[Pos|Tail],Directors)->
    NewH = H#director_role{pos=Pos},
    save_director(NewH),
    NDirectors = lists:keystore(Pos,#director_role.pos,Directors,NewH),
    do_set_fact_director(T,Tail,NDirectors).

%%首次通知上传新的形象数据
sync_notice_upload([])->
    skip;
sync_notice_upload([{_,FactRoles}|T])->
    sync_fact_notice_upload(FactRoles),
    sync_notice_upload(T).
sync_fact_notice_upload([])->
    skip;
sync_fact_notice_upload([{_,Roles}|T])->
    [begin
        Node = clusters_center:get_node_by_role_id(RoleID),
        MFA = {lib_role_legion,upload_figure,[RoleID]},
        clusters_center:apply_cast(Node,MFA)
    end || #director_role{rid=RoleID}<-Roles],
    sync_fact_notice_upload(T).

%%更新形象
update_figure([],_Figure,_Now,Directors)->
    Directors;
update_figure([H|T],Figure,Now,Directors)->
    #director_role{rid=Rid}=H,
    case Figure#figure.id == Rid of
        true->
            update_figure(T,Figure,Now,[H#director_role{figure=Figure,time=Now}|Directors]);
        _->
            update_figure(T,Figure,Now,[H|Directors])
    end.

%%加载
load_director_map()->
    case db:get_all(?SQL_LEGION_DIRECTOR_GET) of
        DataList when is_list(DataList) andalso DataList =/= []->
            DirRoles = to_director_roles(DataList,[]),
            DirectMap = init_director_map(DirRoles),
            DirectMap;
        _->
            #{}
    end.

to_director_roles([],RankRoles)->
    RankRoles;
to_director_roles([[Zone, Fact, Pos, RoleId, Name, Sex,Career]|T],RankRoles)->
    Figure = #figure{
        id = RoleId,
        name = Name,
        sex = Sex,
        career = Career
    },
    Role = #director_role{
        pos = Pos,
        rid = RoleId,
        zone = Zone,
        fact = Fact,
        figure = Figure,
        time = 0
    },
    to_director_roles(T,[Role|RankRoles]).


init_director_map(Roles)->
    init_director_map(Roles,#{}).

init_director_map([],DirectMap)->
    DirectMap;
init_director_map([H|T],DirectMap)->
    #director_role{zone=Zone,fact=Fact}=H,
    FactMap = maps:get(Zone,DirectMap,#{}),
    Roles   = maps:get(Fact,FactMap,[]),
    NRoles  = [H|Roles],
    NFactMap = maps:put(Fact,NRoles,FactMap),
    NDirectMap = maps:put(Zone,NFactMap,DirectMap),
    init_director_map(T,NDirectMap).

sync_all_figure([])->
    ok;
sync_all_figure([{_Zone,FactMap}|T])->
    Facts = maps:to_list(FactMap),
    sync_all_fact_figure(Facts),
    sync_all_figure(T).

sync_all_fact_figure([])->
    ok;
sync_all_fact_figure([{_,Roles}|T])->
    [begin
        Node = clusters_center:get_node_by_role_id(RoleID),
        MFA = {lib_role_legion,upload_figure,[RoleID]},
        clusters_center:apply_cast(Node,MFA)
    end || #director_role{rid=RoleID}<-Roles],
    sync_all_fact_figure(T).

%%指挥官存储
save_director(DirRole)->
    #director_role{
        pos = Pos,
        rid = Rid,
        zone = Zone,
        fact = Fact,
        figure = Figure
    }=DirRole,
    #figure{
        name = Name,
        sex = Sex,
        career = Career
    }=Figure,
    Sql = io_lib:format(?SQL_LEGION_DIRECTOR_INS,[Zone,Fact,Pos,Rid,Name,Sex,Career]),
    db:execute(Sql).


batch_del_director(Zone,Fact)->
    Sql =  io_lib:format(?SQL_LEGION_DIRECTOR_DELS,[Zone,Fact]),
    db:execute(Sql).
