%%% -------------------------------------------------------
%%% @author huangyongxing@yeah.net
%%% @doc
%%% 技能快捷栏
%%% @end
%%% @since 2019-04-26
%%% -------------------------------------------------------
-module(quickbar_api).
%% 数据更新接口
-export([
        save_quickbar/2
        ,db_save_quickbar/2
        ,delete_quickbar/2
        ,delete_from_all_quickbar/2
        ,replace_quickbar/4
        ,switch_quickbar/2
        ,after_auto_learn_skill/4
    ]).
%% 数据查询接口
-export([
        quickbar_skills/1
        ,notice_quickbar/2
        ,check_equal/2
    ]).
%% 数据检验及校正
-export([
        load_check_quickbar/3
        ,check_qnum_in_range/1
        ,adjustment_quick_bar/2
        ,check_quickbar_rebirth/2
        ,check_fill_quickbar/1
        ,fix_quickbar_seq/2
    ]).
%% 快捷栏槽位解锁及自动填充
-export([
        fill_quickbar_with_skills/3
    ]).

-export([
        role_replace_quickbar/4                 %% 玩家替换快捷栏 
        ,change_scene_callback/4                %% 进入场景，改变选择的技能快捷Id 
]).
-include("common.hrl").
-include("server.hrl").
-include("quickbar.hrl").
-include("skill.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("scene.hrl").

%% ---------------------------------------------------------------------
%% 上线的数据版本转换处理及普攻初始设置
%% ---------------------------------------------------------------------
%% 上线加载的QuickbarBin数据进行格式转换和初始检测
-spec load_check_quickbar(QuickbarBin :: binary(), Career, Sex) -> #quickbar{} when
    Career :: non_neg_integer(), Sex :: non_neg_integer().
load_check_quickbar(QuickbarBin, _Career, _Sex) ->
    bin_to_quickbar(QuickbarBin).

bin_to_quickbar(QuickbarBin) ->
    case util:bitstring_to_term(QuickbarBin) of
        Quickbar = #quickbar{ver = ?VER_CURRENT} ->
            Quickbar;
        Quickbar = #quickbar{} ->
            upgrade_ver(Quickbar);
        %% 这个分支不要删除，是对产品线上旧版数据的兼容修正
        _OldQuickbar = [{_, _, _, _} | _] ->
            %% 改版前数据 [{Loc, BtnType, Id, AutoUse}, ...]
            BtnList = [to_btn(Loc, Type, SkillId, AutoUse) || {Loc, Type, SkillId, AutoUse} <- _OldQuickbar],
            QuickbarNum = ?DEFAULT_QUICKBAR,
            QuickbarList = [{QuickbarNum, BtnList}],
            #quickbar{
                ver             = ?VER_CURRENT
                ,selected       = QuickbarNum
                ,quickbar_list  = QuickbarList
            };
        _ ->
            #quickbar{}
    end.

to_btn(Loc, BtnType, Id, AutoUse) ->
    #btn{loc = Loc, id = Id, btn_type = BtnType, auto_use = AutoUse}.

%% 暂时无数据版本升级变化
upgrade_ver(_Quickbar) -> _Quickbar.

%% ---------------------------------------------------------------------
%% 快捷栏数据增、删、改操作
%% ---------------------------------------------------------------------

%% 保存快捷栏到数据库
db_save_quickbar(RoleId, Quickbar) ->
    SQL = io_lib:format(?SQL_UPDATE_QUICKBAR, [util:term_to_bitstring(Quickbar), RoleId]),
    db:execute(SQL).

%% 更新快捷栏（不保存数据库）
save_quickbar([Local, Type, Scheme, Id, AutoTag], Quickbar) ->
    #quickbar{quickbar_list = QuickbarList} = Quickbar,
    BtnList = get_btn_list(Scheme, QuickbarList),
    %% 过滤时，保留不在该位置且非同类同id的按钮
    TmpBtnList = [
        BtnX ||
        BtnX = #btn{loc = LocX, btn_type = _BtnTypeX, id = IdX} <- BtnList,
        LocX =/= Local andalso IdX =/= Id
    ],
    Btn = to_btn(Local, Type, Id, AutoTag),
    NewBtnList  = [Btn | TmpBtnList],
    NewQuickbarList = store_btn_list(Scheme, QuickbarList, NewBtnList),
    Quickbar#quickbar{quickbar_list = NewQuickbarList}.

%% 删除指定位置的快捷栏
delete_quickbar(Loc, Quickbar) ->
    #quickbar{selected = Selected, quickbar_list = QuickbarList} = Quickbar,
    NewQuickbarList = del_btn_from_quickbar_list(Selected, QuickbarList, Loc),
    Quickbar#quickbar{quickbar_list = NewQuickbarList}.

%% 从所有快捷栏删除指定位置
delete_from_all_quickbar(Loc, Quickbar) ->
    #quickbar{quickbar_list = QuickbarList} = Quickbar,
    NewQuickbarList = lists:foldl(
        fun ({QuickbarNum, _BtnList}, Acc) ->
                del_btn_from_quickbar_list(QuickbarNum, Acc, Loc);
            (_, Acc) -> Acc
        end, QuickbarList, QuickbarList),
    Quickbar#quickbar{quickbar_list = NewQuickbarList}.


%% ---------------------------------------------------------------------------
%% @doc 玩家替换快捷栏
-spec role_replace_quickbar(Role, Loc1, Loc2, Scheme) -> 
    {false, Reason} | {ok, NewRole} when
    Role        :: #player_status{},
    Loc1        :: integer(),
    Loc2        :: integer(),
    Scheme      :: integer(),
    Reason      :: integer(),
    NewRole     :: #player_status{}.
%% ---------------------------------------------------------------------------
role_replace_quickbar(Role, Loc1, Loc2, Scheme) ->
    #player_status{quickbar = QuickBar, id = RoleId} = Role,
    #quickbar{quickbar_list = QuickbarList} = QuickBar,
    BtnList = get_btn_list(Scheme, QuickbarList),
    BtnLoc1 = lists:keyfind(Loc1, #btn.loc, BtnList),
    BtnLoc2 = lists:keyfind(Loc2, #btn.loc, BtnList),
    if
        not is_record(BtnLoc1, btn) ->
            {false, ?FAIL};
        not is_record(BtnLoc2, btn) ->
            {false, ?FAIL};
        true ->
            NewQuickbar = replace_quickbar(Loc1, Loc2, Scheme, QuickBar),
            Role2 = Role#player_status{quickbar= NewQuickbar},
            db_save_quickbar(RoleId, NewQuickbar),
            mod_scene_agent:update(Role2, [{quickbar_skills, NewQuickbar}]),
            {ok, Role2}
    end.


%% 替换快捷栏
replace_quickbar(Loc1, Loc2, Scheme, Quickbar) ->
    #quickbar{quickbar_list = QuickbarList} = Quickbar,
    BtnList = get_btn_list(Scheme, QuickbarList),
    BtnLoc1 = lists:keyfind(Loc1, #btn.loc, BtnList),
    BtnLoc2 = lists:keyfind(Loc2, #btn.loc, BtnList),
    %% 删除原数据
    BtnListDelAll = [
        BtnX || BtnX = #btn{loc = LocX} <- BtnList, not lists:member(LocX, [Loc1, Loc2])
    ],
    %% 将有效按钮数据写入到删除后的数据中
    NeedCheckAdd = [{Loc1, BtnLoc2}, {Loc2, BtnLoc1}],
    NewBtnList = lists:foldl(
        fun ({NewLocX, BtnX}, Acc) ->
                case BtnX of
                    #btn{} ->
                        NewBtnX = BtnX#btn{loc = NewLocX},
                        [NewBtnX | Acc];
                    _ ->
                        Acc
                end
        end, BtnListDelAll, NeedCheckAdd),
    NewQuickbarList = store_btn_list(Scheme, QuickbarList, NewBtnList),
    Quickbar#quickbar{quickbar_list = NewQuickbarList}.

%% 技能栏切换
-spec switch_quickbar(Player, OptionNum) -> NewPlayer when
    Player :: #player_status{}, NewPlayer :: #player_status{},
    OptionNum :: non_neg_integer().
switch_quickbar(Player, OptionNum) ->
    #player_status{id = RoleId, quickbar = Quickbar, sid = Sid} = Player,
    #quickbar{selected = OldSelected} = Quickbar,
    SetNum =
    case check_qnum_in_range(OptionNum) of
        true  -> OptionNum;
        false -> ?DEFAULT_QUICKBAR
    end,
    case OldSelected =:= SetNum of
        true  ->
            Player;
        false ->
            NewQuickbar = Quickbar#quickbar{selected = SetNum},
            db_save_quickbar(RoleId, NewQuickbar),
            notice_quickbar(Sid, NewQuickbar),
            Player#player_status{quickbar = NewQuickbar}
    end.

%% -> BtnList
get_btn_list(QuickbarNum, QuickbarList) ->
    case lists:keyfind(QuickbarNum, 1, QuickbarList) of
        {_, BtnList} -> BtnList;
        _ -> []
    end.

%% -> NewQuickbarList
store_btn_list(QuickbarNum, OldQuickbarList, NewBtnList) ->
    lists:keystore(QuickbarNum, 1, OldQuickbarList, {QuickbarNum, NewBtnList}).

%% -> NewQuickbarList
del_btn_from_quickbar_list(QuickbarNum, QuickbarList, DelLoc) ->
    BtnList = get_btn_list(QuickbarNum, QuickbarList),
    NewBtnList = lists:keydelete(DelLoc, #btn.loc, BtnList),
    store_btn_list(QuickbarNum, QuickbarList, NewBtnList).

%% 检查快捷栏位置是否在范围内
check_qnum_in_range(QuickbarNum) ->
    [Min, Max] = ?QUICKBAR_NUM_RANGE,
    QuickbarNum >= Min andalso QuickbarNum =< Max.

%% ---------------------------------------------------------------------
%% 技能数据管理与查询
%% ---------------------------------------------------------------------

%% ---------------------------------------------------------------------------
%% @doc 通知前端快捷栏信息
-spec notice_quickbar(Sid, Quickbar) -> ok when
    Sid         :: pid(),
    Quickbar    :: #quickbar{}.
%% ---------------------------------------------------------------------------
notice_quickbar(Sid, #quickbar{quickbar_list = QuickbarList}) ->
    Fun = fun({Scheme, BtnList}) ->
        BtnInfoList = [
            {Loc, BtnType, Id, AutoTag} ||
            #btn{loc = Loc, btn_type = BtnType, id = Id, auto_use = AutoTag} <- BtnList
        ],
        {Scheme, BtnInfoList}
    end,
    QuickbarInfoList = lists:map(Fun, QuickbarList),
    {ok, BinData} = pt_130:write(13007, [QuickbarInfoList]),
    lib_server_send:send_to_sid(Sid, BinData),
    ok.

%% 检测两个快捷栏数据是否等价
check_equal(
    #quickbar{ver = Ver, selected = Selected, quickbar_list = QuickbarListA},
    #quickbar{ver = Ver, selected = Selected, quickbar_list = QuickbarListB}) ->
    sub_check_equal(QuickbarListA, QuickbarListB);
check_equal(_, _) ->
    false.

sub_check_equal([], []) ->
    true;
sub_check_equal([{QuickbarNumA, BtnListA} | QListA], QuickbarListB) ->
    case lists:keytake(QuickbarNumA, 1, QuickbarListB) of
        {value, {_, BtnListB}, RemainQuickbarListB} ->
            case ulists:list_equal(BtnListA, BtnListB) of
                true  ->
                    sub_check_equal(QListA, RemainQuickbarListB);
                false ->
                    false
            end;
        _ ->
            false
    end;
sub_check_equal(_, _) ->
    false.

%% 设定战斗使用的技能列表
%% 此处使用等级1，是沿用原来的处理，如有需要再变更
-spec quickbar_skills(PSOrQuickbar :: #player_status{} | #quickbar{}) -> Skills when
    Skills ::  [{SkillId, SkillLevel}],
    SkillId :: non_neg_integer(), SkillLevel :: non_neg_integer().
quickbar_skills(#player_status{quickbar = QuickBar} = Player) ->
    lib_skill:get_normal_skill(Player) ++ quickbar_skills(QuickBar);
quickbar_skills(#quickbar{selected = Selected, quickbar_list = QuickbarList}) ->
    BtnList = get_btn_list(Selected, QuickbarList),
    [{SkillId, 1} || #btn{id = SkillId, btn_type = ?BTN_SKILL} <- BtnList];
quickbar_skills(_) ->
    [].

%% 自动学习技能后，检测解锁及更新快捷栏槽位
after_auto_learn_skill(Player, _Turn, AddSkills, _Event) ->
    #player_status{id = RoleId, quickbar = Quickbar} = Player,
    LastAddSkillIds = lists:sort([Id || {Id, ?SKILL_TYPE_ACTIVE, 0} <- AddSkills]),
    NewQuickbar = fill_quickbar_with_skills(Quickbar, LastAddSkillIds, ?BASE_BTN_LOCS),
    case check_equal(NewQuickbar, Quickbar) of
        true  -> ignore;
        false -> db_save_quickbar(RoleId, NewQuickbar)
    end,
    Player#player_status{quickbar = NewQuickbar}.

%% 检测填补技能快捷栏
%% （有足够技能但是技能栏空置时，前端竟然不能选择技能，需要服务端先填充数据，即表现为需要服务端解锁）
check_fill_quickbar(Player = #player_status{
        skill = SkillStatus,
        quickbar = Quickbar,
        figure = #figure{career = Career, sex = Sex, turn = Turn}
    }) ->
    #status_skill{
        skill_list = SkillList
    } = SkillStatus,
    RebirthReplaceSkills = get_rebirth_replace_skills(Career, Sex, Turn),
    QuickbarRebirth = check_quickbar_rebirth(Quickbar, RebirthReplaceSkills),
    {CheckActiveSkills, AngerSkillIds, _MyNormalSkill} = lists:foldl(
        fun({SkillId, SkillLevel}, {Acc, AngerSkillList, NormalSkill}) ->
                case data_skill:get(SkillId, SkillLevel) of
                    #skill{type = ?SKILL_TYPE_ACTIVE, is_anger = 1} ->
                        {Acc, [SkillId | AngerSkillList], NormalSkill};
                    #skill{type = ?SKILL_TYPE_ACTIVE, is_normal = 0} ->
                        %% 主动技能、非怒气、非普攻、非转生替换掉的旧技能
                        NewAcc =
                        case lists:keymember(SkillId, 1, RebirthReplaceSkills) of
                            true  -> Acc;
                            false -> [SkillId | Acc]
                        end,
                        {NewAcc, AngerSkillList, NormalSkill};
                    #skill{type = ?SKILL_TYPE_ACTIVE, is_normal = 1, skill_link = [SkillId | _]} ->
                        NewNormalSkill =
                        case NormalSkill > 0 of
                            true  ->
                                case lists:keymember(SkillId, 2, RebirthReplaceSkills) of
                                    true  -> SkillId;
                                    false -> NormalSkill
                                end;
                            false ->
                                SkillId
                        end,
                        {Acc, AngerSkillList, NewNormalSkill};
                    _ ->
                        {Acc, AngerSkillList, NormalSkill}
                end
        end, {[], [], 0}, SkillList),
    %% 第一个位置不需要固定为普攻
    % QuickbarSetFirst = check_set_first_loc(QuickbarRebirth, MyNormalSkill, Career, Sex),
    % ?INFO_TTY("set first:~nbefore:~p,~nafter:~p", [QuickbarRebirth, QuickbarSetFirst]),
    %% FIXME 转生旧技能移除、怒气旧技能移除、排重修复、次序重排等几个操作，在后续版本可以考虑移除，
    %%       目前保留的目的是修复旧号曾经的数据重复错误
    %% 转生旧技能、怒气技能移除
    QuickbarAfterValid = valid_quickbar_list(QuickbarRebirth, RebirthReplaceSkills, AngerSkillIds),
    %% 排重修复
    QuickbarAfterRemoveDuplic = remove_duplicate_quickbar(QuickbarAfterValid),
    %% 次序重排
    QuickbarSorted = fix_quickbar_seq(QuickbarAfterRemoveDuplic, Turn),
    %% 填充检测
    NewQuickbar = fill_quickbar_with_skills(QuickbarSorted, CheckActiveSkills, ?BASE_BTN_LOCS),
    % ?INFO_TTY("CheckActiveSkills:~n~p,~nbefore fill:~n~p,~nafter fill:~n~p", [CheckActiveSkills, QuickbarSorted, NewQuickbar]),
    Player#player_status{quickbar = NewQuickbar}.

%% 排重检查
remove_duplicate_quickbar(Quickbar) ->
    #quickbar{quickbar_list = QuickbarList} = Quickbar,
    NewQuickbarList = [
        begin
                NewBtnList = remove_duplicate_btn(BtnList, [], []),
                {QuickbarNum, NewBtnList}
        end ||
        {QuickbarNum, BtnList} <- QuickbarList
    ],
    Quickbar#quickbar{quickbar_list = NewQuickbarList}.

remove_duplicate_btn([Btn = #btn{loc = Loc, btn_type = ?BTN_SKILL, id = SkillId} | Others],
    BtnSkills, Acc) ->
    case lists:keyfind(SkillId, 1, BtnSkills) of
        {_, OldLoc} when OldLoc > Loc  ->   % 已经有记录了，并且旧记录在后面位置
            BtnSkillInfo = {SkillId, Loc},
            NewAcc = [Btn | lists:keydelete(OldLoc, #btn.loc, Acc)],
            NewBtnSkills = [BtnSkillInfo | lists:keydelete(SkillId, 1, BtnSkills)],
            remove_duplicate_btn(Others, NewBtnSkills, NewAcc);
        {_, _OldLoc} ->     % 有记录，但是旧记录在前面位置
            remove_duplicate_btn(Others, BtnSkills, Acc);
        _ ->                % 无记录
            BtnSkillInfo = {SkillId, Loc},
            remove_duplicate_btn(Others, [BtnSkillInfo | BtnSkills], [Btn | Acc])
    end;
remove_duplicate_btn([Btn = #btn{} | Others], BtnSkills, Acc) ->
    remove_duplicate_btn(Others, BtnSkills, [Btn | Acc]);
remove_duplicate_btn([_ | Others], BtnSkills, Acc) ->
    remove_duplicate_btn(Others, BtnSkills, Acc);
remove_duplicate_btn(_, _BtnSkills, Acc) ->
    lists:reverse(Acc).

%% 检测快捷栏列表数据（修复数据用）
valid_quickbar_list(Quickbar, RebirthReplaceSkills, AngerSkillIds) ->
    #quickbar{quickbar_list = QuickbarList} = Quickbar,
    NewQuickbarList = [
        begin
                NewBtnList = [
                    Btn ||
                    Btn = #btn{id = SkillId, btn_type = ?BTN_SKILL} <- BtnList,
                    valid_btn_skill(SkillId, RebirthReplaceSkills, AngerSkillIds)
                ],
                {QuickbarNum, NewBtnList}
        end ||
        {QuickbarNum, BtnList} <- QuickbarList
    ],
    Quickbar#quickbar{quickbar_list = NewQuickbarList}.

%% 检查是否有效的快捷栏技能ID（转生后的旧技能和怒气技能都不能放在快捷栏）
valid_btn_skill(SkillId, RebirthReplaceSkills, AngerSkillIds) ->
    not (
        lists:keymember(SkillId, 1, RebirthReplaceSkills) orelse
        lists:member(SkillId, AngerSkillIds)
    ).

%% 获取转生技能映射（不包含转生解锁的独立新技能，仅指替换转生前的部分技能的映射关系）
%% -> [{OldSkillId, NewSkillId}, ...]
get_rebirth_replace_skills(_Career, _Sex, Turn) ->
    lists:foldl(fun(_TurnX, Acc) ->
                [] ++ Acc
        end, [], lists:seq(0, Turn)).

%% 有空的快捷栏要替换上新学的技能
%% Quickbar: #quickbar{}
fill_quickbar_with_skills(Quickbar, [], _) ->
    Quickbar;
fill_quickbar_with_skills(Quickbar, _, []) ->
    Quickbar;
fill_quickbar_with_skills(Quickbar, AddSkills, RemainLocList) ->
    #quickbar{quickbar_list = QuickbarList} = Quickbar,
    [Min, Max] = ?QUICKBAR_NUM_RANGE,
    Fun = fun(QuickbarNum, Acc) ->
        OldBtnList = get_btn_list(QuickbarNum, Acc),
        NewBtnList = fill_btn_list(OldBtnList, AddSkills, RemainLocList),
        store_btn_list(QuickbarNum, Acc, NewBtnList)
    end,
    NewQuickbarList = lists:foldl(Fun, QuickbarList, lists:seq(Min, Max)),
    Quickbar#quickbar{quickbar_list = NewQuickbarList}.

fill_btn_list(BtnList, [], _) ->
    BtnList;
fill_btn_list(BtnList, _, []) ->
    BtnList;
fill_btn_list(BtnList, AddSkills = [SkillId | OtherSkills], OldRemainLocList = [Loc | BtnLocList]) ->
    case lists:keyfind(Loc, #btn.loc, BtnList) of
        false ->
            case lists:keymember(SkillId, #btn.id, BtnList) of
                false ->
                    Btn = to_btn(Loc, ?BTN_SKILL, SkillId, 0),
                    NewBtnList = [Btn | BtnList],
                    fill_btn_list(NewBtnList, OtherSkills, BtnLocList);
                true ->
                    fill_btn_list(BtnList, OtherSkills, OldRemainLocList)
            end;
        #btn{id = Id} ->
            case data_skill:get(Id, 1) of
                #skill{type = ?SKILL_TYPE_ACTIVE, is_normal = 0} ->
                    fill_btn_list(BtnList, AddSkills, BtnLocList);
                _ ->
                    %% 如果技能不正常，那就删掉这个技能
                    NewBtnList = lists:keydelete(Loc, #btn.loc, BtnList),
                    fill_btn_list(NewBtnList, AddSkills, BtnLocList)
            end
    end.

fix_quickbar_seq(Quickbar, Turn) ->
    #quickbar{quickbar_list = QuickbarList} = Quickbar,
    %% 这里应排除普攻技能位（BASE_BTN_LOCS已经排除了）
    {LocMax, LocList} =
    case Turn >= 3 of
        true  ->
            {lists:max(?BASE_BTN_LOCS), ?BASE_BTN_LOCS};
        false ->    % 转生3次解锁剩余的技能槽，在此之前只开放到第5个槽位
            BtnLocMax = 5,
            {BtnLocMax, [BtnLoc || BtnLoc <- ?BASE_BTN_LOCS, BtnLoc =< BtnLocMax]}
    end,
    AllLocList = lists:sort(LocList),
    NewQuickbarList = [
        begin
                NewBtnList = fix_btn_list_seq(BtnList, AllLocList, LocMax),
                {QuickbarNum, NewBtnList}
        end ||
        {QuickbarNum, BtnList} <- QuickbarList
    ],
    Quickbar#quickbar{quickbar_list = NewQuickbarList}.

%% 修复快捷栏技能顺序（以免前面位置空出来，后面位置有技能）
fix_btn_list_seq(BtnList, AllLocList, LocMax) ->
    ReminLocList = [BtnLoc || BtnLoc <- AllLocList, not lists:keymember(BtnLoc, #btn.loc, BtnList)],
    fix_btn_list_seq(BtnList, ReminLocList, [], LocMax).

%% fix_btn_list_seq(Quickbar, LocList, Acc, LocMax) -> NewQuickbar.
fix_btn_list_seq([Btn = #btn{loc = Loc} | BtnList],
    [HdLoc | RemainLocList], Acc, LocMax) when Loc > LocMax ->
    %% 存在空位，并且这是一个后面才开放位置的按钮，则调节到前面的空位
    NewBtn = Btn#btn{loc = HdLoc},
    fix_btn_list_seq(BtnList, RemainLocList, [NewBtn | Acc], LocMax);
fix_btn_list_seq([Btn | BtnList], LocList = [_ | _], Acc, LocMax) ->
    %% 还存在空位，但这是前置开放的按钮
    fix_btn_list_seq(BtnList, LocList, [Btn | Acc], LocMax);
fix_btn_list_seq(BtnList, [], Acc, _LocMax) ->
    %% 没有前置无条件开放的空位了
    lists:reverse(Acc) ++ BtnList;
fix_btn_list_seq([], _, Acc, _LocMax) ->
    %% 全部按钮检测处理完，还原顺序
    lists:reverse(Acc).

%% 删除失效的挂机技能
adjustment_quick_bar(Quickbar, DelSkills) ->
    #quickbar{quickbar_list = QuickbarList} = Quickbar,
    FunDelInvalidSkill = fun({SkillId, _Lev}, BtnListAcc) ->
            lists:keydelete(SkillId, #btn.id, BtnListAcc)
    end,
    NewQuickbarList = [
        begin
                NewBtnList = lists:foldl(FunDelInvalidSkill, BtnList, DelSkills),
                {QuickbarNum, NewBtnList}
        end ||
        {QuickbarNum, BtnList} <- QuickbarList
    ],
    Quickbar#quickbar{quickbar_list = NewQuickbarList}.

%% 转生技能快捷栏数据检测
%% （同时去除非技能类型的非法数据，如果后续需要支持其他按钮类型，则应进行调整）
%% 转生技能分两类：
%% 1、将普攻技能映射为另一个技能（原普攻就不能使用了）
%% 2、以转生为学习条件，独立开放的新技能
check_quickbar_rebirth(Quickbar, RebirthReplaceSkills) ->
    #quickbar{quickbar_list = QuickbarList} = Quickbar,
    NewQuickbarList = [
        begin
                NewBtnList = check_btn_reincarnation(BtnList, RebirthReplaceSkills),
                {QuickbarNum, NewBtnList}
        end || {QuickbarNum, BtnList} <- QuickbarList
    ],
    Quickbar#quickbar{quickbar_list = NewQuickbarList}.

check_btn_reincarnation(BtnList, RebirthReplaceSkills) ->
    [
        conv_quickbar_button(Btn, RebirthReplaceSkills) ||
        Btn = #btn{btn_type = ?BTN_SKILL} <- BtnList
    ].

conv_quickbar_button(Btn = #btn{btn_type = ?BTN_SKILL, id = OldSkillId}, RebirthReplaceSkills) ->
    %% 这里只支持整个列表为BTN_SKILL类型的数据；
    %% 后续如果改为有其他类型，不能直接lists:keyfind/3
    case lists:keyfind(OldSkillId, 1, RebirthReplaceSkills) of
        {_, MapSkillId} ->
            Btn#btn{id = MapSkillId};
        _ ->
            Btn
    end;
conv_quickbar_button(Btn, _RebirthReplaceSkills) ->
    Btn.


%% ---------------------------------------------------------------------------
%% @doc 进入场景，改变选择的技能快捷Id
%% 玩家场景切换回调(只做一些场景更新后的状态变更)
-spec change_scene_callback(Role, OldSceneInfo, OldSceneData, NewSceneData) -> 
    NewRole when
    Role            :: #player_status{},
    OldSceneInfo    :: tuple(),
    OldSceneData    :: #ets_scene{},
    NewSceneData    :: #ets_scene{},
    NewRole         :: #player_status{}.
%% ---------------------------------------------------------------------------
change_scene_callback(Role, _OldSceneInfo, _OldSceneData, _NewSceneData) ->
    #player_status{scene = SceneId, quickbar = QuickBar} = Role,
    case data_scene:get(SceneId) of
        #ets_scene{type = SceneType} ->
            Selected = case data_skill_scene_setting:get_skill_scene_scheme(SceneType) of
                Scheme when is_integer(Scheme) andalso Scheme > 0 ->
                    Scheme;
                _ ->
                    1
            end,
            QuickBar2 = QuickBar#quickbar{selected = Selected},
            Role#player_status{quickbar = QuickBar2};
        _ ->
            Role
    end.

