%% ---------------------------------------------------------
%% Doc: 玩家record操作相关
%% Author:  hek
%% Email:   1472524632@qq.com
%% Created: 2016-8-25
%% Description: 获取、更新指定玩家record字段
%% --------------------------------------------------------

-module(lib_player_record).
-include("attr.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("predefine.hrl").

-export([
         get_field_auto/2,
         update_field_auto/2,
         get_field/2,
         update_field/2,
         %% 修正玩家的pk值
         pk_login/6,
         use_red_name_goods/3,
         %% 功能存在超时的检查
         role_func_check_insert/3,
         role_func_check_update/3,
         role_func_check_delete/2,
         role_func_check_exist/3,
         role_func_check_delete_sub_id/3,
         role_func_check/0
        ]).

get_field_auto(FieldList, PS) ->
    get_field_auto(FieldList, PS, []).

get_field_auto([], _PS, Res) -> lists:reverse(Res);
get_field_auto([FieldId|T], PS, Res) ->
    Value = element(FieldId+1, PS),
    get_field_auto(T, PS, [Value|Res]).

update_field_auto([], PS) -> PS;
update_field_auto([{FieldId, Value}|T], PS) ->
    NewPS = setelement(FieldId+1, PS, Value),
    update_field_auto(T, NewPS).

get_field(KeyList, PS) ->
    get_field(KeyList, PS, []).

get_field([], _PS, Res) -> lists:reverse(Res);
get_field([Key|T], PS, Res) ->
    Value = case Key of
                career -> PS#player_status.figure#figure.career;
                _ -> 0
            end,
    get_field(T, PS, [Value|Res]).

update_field(_KeyValueList, PS) -> PS.

%% ================================= 玩家pk状态 =================================
%% 玩家pk状态
pk_login(NowTime, PkStatus, PkSChgTime, PkValue, PkVChgTime, LastLogoutTime)->
    {NPkValue, NPkVChgTime, NewPkValueRef} = if
        PkValue =< 0  ->
            {0, 0, undefined};
        PkVChgTime =:= 0 -> %% 一次都没有清理过。
            NPkValueRef = erlang:send_after(?RemovePkValue*1000, self(), {'change_pk_value', pk_value, -1}),
            {PkValue, NowTime, NPkValueRef};
        true -> %% 根据最近的一次清理时间，计算下一次要清理的时间
            DelPkValue = (LastLogoutTime - PkVChgTime) div ?RemovePkValue,
            case max(0, PkValue - DelPkValue) of
                0 ->
                    {0, 0, undefined};
                NewPkValue ->
                    NextPkVChgTime = NowTime + (
                        ?RemovePkValue - ((LastLogoutTime - PkVChgTime) rem ?RemovePkValue)
                    ),
                    %% 多延长几秒
                    SpanTime = NextPkVChgTime - NowTime + 2,
                    NPkValueRef = erlang:send_after(SpanTime*1000, self(), {'change_pk_value', pk_value, -1}),
                    {NewPkValue, NextPkVChgTime-?RemovePkValue, NPkValueRef}
            end
    end,
    #pk{
        pk_status = PkStatus, pk_change_time = PkSChgTime, pk_value = NPkValue,
        pk_value_change_time = NPkVChgTime, pk_value_ref = NewPkValueRef
    }.

%% 使用道具消除罪恶值
use_red_name_goods(Ps, GoodsTypeId, Num)->
    #player_status{id = RoleId, sid = Sid, battle_attr = BA,
                   scene = SceneId, scene_pool_id = ScenePId, copy_id = CopyId, x = X, y = Y} = Ps,
    #battle_attr{pk = Pk} = BA,
    #pk{pk_value = PkValue, pk_value_ref = PkValueRef} = Pk,
    EffectValue = max(data_goods:get_effect_val(GoodsTypeId, del_pk_value), 1),
    DelNum = Num * EffectValue,
    if
        PkValue =< 0 -> 
            {fail, ?ERRCODE(err150_pk_value_0)};
        true ->
            {UseNum, NewPkValue} = if
              PkValue - DelNum >= 0 -> 
                  {Num, PkValue - DelNum};
              true -> %% 不需要消耗Num个物品
                  {util:ceil(PkValue / EffectValue), 0}
            end,
            lib_goods_api:cost_object_list(Ps, [{0, GoodsTypeId, UseNum}], goods_use, ""),
            NewPk = if
                NewPkValue == 0 ->
                    util:cancel_timer(PkValueRef),
                    {ok, BinData1} = pt_200:write(20015, [RoleId, NewPkValue]),
                    lib_server_send:send_to_area_scene(SceneId, ScenePId, CopyId, X, Y, BinData1),
                    Pk#pk{pk_value = 0, pk_value_change_time = 0, pk_value_ref = undefined};
                true ->
                    Pk#pk{pk_value = NewPkValue}
            end,
            NewPs = Ps#player_status{battle_attr = BA#battle_attr{pk = NewPk}},
            lib_player:send_attribute_change_notify(NewPs, ?NOTIFY_PK),
            mod_scene_agent:update(NewPs, [{battle_attr, NewPs#player_status.battle_attr}]),
            {ok, BinData} = pt_200:write(20014, ["", 2, NewPkValue]),
            lib_server_send:send_to_sid(Sid, BinData),
            {ok, NewPs, UseNum}
    end.


%% 新增定时器数据
role_func_check_insert(RoleId, Type, EndTimesOrEndTime)->
    E = #ets_role_func_check{key_id = {RoleId, Type}, end_times = EndTimesOrEndTime},
    ets:insert(?ETS_ROLE_FUNC_CHECK, E).

%% 更新定时器数据
role_func_check_update(RoleId, Type, EndTimesOrEndTime) ->
    case ets:lookup(?ETS_ROLE_FUNC_CHECK, {RoleId, Type}) of
        [#ets_role_func_check{end_times = EndTimes} = Object] ->
            case func_type_check(Type) of
                true ->
                    {Id, _} = EndTimesOrEndTime,
                    NewEndTimes = [EndTimesOrEndTime|lists:keydelete(Id, 1, EndTimes)],
                    NewObject = Object#ets_role_func_check{end_times = NewEndTimes},
                    ets:insert(?ETS_ROLE_FUNC_CHECK, NewObject);
                _ ->
                    skip
            end;
        _ ->
            role_func_check_insert(RoleId, Type, [EndTimesOrEndTime])
    end.

%% 删除定时检查超时
role_func_check_delete(RoleId, Type)->
    ets:delete(?ETS_ROLE_FUNC_CHECK, {RoleId, Type}).

%% 删除子类型数据
role_func_check_delete_sub_id(RoleId, Type, SubId)->
    case ets:lookup(?ETS_ROLE_FUNC_CHECK, {RoleId, Type}) of
        [] -> skip;
        [#ets_role_func_check{end_times = EndTimes} = Object] ->
              case func_type_check(Type) of
                  true ->
                    NewEndTimes = lists:keydelete(SubId, 1, EndTimes),
                    if
                        NewEndTimes == [] ->
                            ets:delete(?ETS_ROLE_FUNC_CHECK, {RoleId, Type});
                        true ->
                            NewObject = Object#ets_role_func_check{end_times = NewEndTimes},
                            ets:insert(?ETS_ROLE_FUNC_CHECK, NewObject)
                    end;
                  _ ->
                    skip
            end
    end.

%% 玩家功能定时检测过期
role_func_check()->
    NowTime = utime:unixtime(),
    RoleList = ets:tab2list(?ETS_ROLE_FUNC_CHECK),
    Fun = fun(#ets_role_func_check{key_id = {RoleId, Type}, end_times = EndTimesOrEndTime}=E) ->
              case func_type_check(Type) of
                  true ->
                      F = fun({Id, DEndTime}, {DList, LList}) ->
                              if
                                  NowTime > DEndTime -> {[Id|DList], LList};
                                  true -> {DList, [{Id, DEndTime}|LList]}
                              end
                          end,
                      {DelList, LeftList} = lists:foldl(F, {[], []}, EndTimesOrEndTime),
                      if
                          DelList == [] -> skip;
                          true -> send_msg_to_role(RoleId, {'func_timer_out', Type, DelList})
                      end,
                      if
                          LeftList == [] -> ets:delete(?ETS_ROLE_FUNC_CHECK, {RoleId, Type});
                          true  ->
                              NE = E#ets_role_func_check{end_times = LeftList},
                              ets:insert(?ETS_ROLE_FUNC_CHECK, NE)
                      end;
                  _ ->
                      ok
              end
          end,
    lists:foreach(Fun, RoleList).

%% 检测某定时项是否存在
%% true 存在|false 不存在
role_func_check_exist(RoleId, Type, SubId) ->
    NowTime = utime:unixtime(),
    case ets:lookup(?ETS_ROLE_FUNC_CHECK, {RoleId, Type}) of
      [] -> 
        false;
      [#ets_role_func_check{end_times = EndTimes}|_] ->
          case lists:keyfind(SubId, 1, EndTimes) of
            {_, SubEndTime} when SubEndTime > NowTime ->
              true;
            _ ->
              false
          end
    end.

%% 发送消息
send_msg_to_role(RoleId, Msg)->
    RolePid = misc:get_player_process(RoleId),
    case misc:is_process_alive(RolePid) of
        false -> skip;
        true -> RolePid ! Msg
    end.


config_func_type_list() ->
    [
      ?FUNC_TYPE_DESIGNATION,
      ?FUNC_TYPE_FASHION,
      ?FUNC_TYPE_SUP_VIP,
      ?FUNC_TYPE_VIP,
      ?FUNC_TYPE_MIDNIGHT_LOG
    ].

func_type_check(Type) ->
    lists:member(Type, config_func_type_list()).