%%% -------------------------------------------------------
%%% @author huangyongxing@yeah.net
%%% @doc
%%% @end
%%% -------------------------------------------------------
-module(cli_pt_120).
-export([
        encode/2
        , decode/2
    ]).

-include("cli_simu.hrl").

%% 数据封包

%% 走路请求
encode(12001, [SceneId, TargetX, TargetY, MotionType, Param1, Param2, Param3, Param4]) ->
    {ok, <<SceneId:32, TargetX:16, TargetY:16, MotionType:8,
        Param1:16, Param2:16, Param3:16, Param4:16>>};

%% 加载场景
encode(12002, _) ->
    {ok, <<>>};

encode(_Cmd, _Data) ->
    {error, unknown_data}.

%% 数据解包

%% 走路协议（长度分两种，这里只取前面的公共部分数据）
decode(12001, <<TargetX:16, TargetY:16, Id:64, _MotionType:8, _Rest/binary>>) ->
    case get(id) of
        Id ->
            %% 收包进程保存了角色id到进程字典，这里取出对比检测这条数据是否处理
            {ok, [Id, TargetX, TargetY]};
        _  ->
            ignore
    end;

%% 角色列表、场景元素列表信息
decode(12002, Bin) ->
    {RoleList, RestBin1} = read_role_list(Bin),
    {MonList, _NormalObjList, DummyList, RestBin2} = read_scene_object(RestBin1),
    FunReadMark = fun(<<AreaId:8, ClientType:8, RestBinX/binary>>) -> {{AreaId, ClientType}, RestBinX} end,
    {_Mark, _RestBin3} = pt:read_array(FunReadMark, RestBin2),
    {ok, [RoleList, MonList, DummyList]};

%% 有某角色进入场景
decode(12003, Bin) ->
    {EnterRole, _RestBin1} = read_12003_role(Bin),
    {ok, EnterRole};

decode(12004, <<LeaveRoleId:64>>) ->
    {ok, LeaveRoleId};

decode(12006, <<LeaveId:32>>) ->
    {ok, LeaveId};

decode(12007, Bin) ->
    {EnterMon, _RestBin1} = read_12007_mon(Bin),
    {ok, EnterMon};

decode(12008, <<X:16, Y:16, Id:32>>) ->
    {ok, [X, Y, Id]};

decode(_Cmd, _BinData) ->
    ignore.

%% -------------------------------------------------------------------
%% 协议打包和解包辅助函数（针对一些较复杂结构的封装等）
%% -------------------------------------------------------------------

read_role_list(Bin) ->
    pt:read_array(fun(BinX) -> read_12003_role(BinX) end, Bin).

read_mon_list(Bin) ->
    pt:read_array(fun(BinX) -> read_12007_mon(BinX) end, Bin).

% read_partner_list(Bin) ->
%     pt:read_array(fun(BinX) ->
%                 % read_12013_partner(BinX)
%                 {undefined, BinX}
%         end, Bin).

read_object_list(Bin) ->
    pt:read_array(fun(BinX) -> read_12014_object(BinX) end, Bin).

read_dummy_list(Bin) ->
    pt:read_array(fun(BinX) -> read_12015_dummy(BinX) end, Bin).

%% 这个特殊，对应12002协议，实指怪物、伙伴、其他一般场景对象、假人所有内容构成的综合体
read_scene_object(Bin) ->
    {MonList, RestBin1} = read_mon_list(Bin),
    {NormalObjList, RestBin2} = read_object_list(RestBin1),
    {DummyList, RestBin3} = read_dummy_list(RestBin2),
    {MonList, NormalObjList, DummyList, RestBin3}.

%% 读取12003协议角色信息
read_12003_role(Bin) ->
    FunActLabel = fun(<<Key:8, Val:64, RestBinX/binary>>) -> {{Key, Val}, RestBinX} end,

    <<Id:64, RestBin1/binary>> = Bin,
    {Platform, RestBin2} = pt:read_string(RestBin1),
    <<ServerId:16, RestBin3/binary>> = RestBin2,
    <<_ServerNum:16, RestBin4/binary>> = RestBin3,
    {Figure, RestBin5} = cli_simu_proto:read_figure(RestBin4),
    <<X:16, Y:16, Hp:64, HpLim:64, Speed:16, Hide:8, Ghost:8, Group:64,
    _BossWho:8, TeamId:64, _Position:8, PkStatus:8, Power:32,
    IsRide:8, MountFigure:32, PkValue:16, PetFigure:32, PetHideStatus:8,
    PkProtectTime:32, _MateRoleId:64, RestBin6/binary>> = RestBin5,

    {_ActLabel, RestBin7} = pt:read_array(FunActLabel, RestBin6),
    {_MateName, RestBin8} = pt:read_string(RestBin7),
    {_MateTitle, RestBin9} = pt:read_string(RestBin8),
    <<_RoleDance:8, _MateLv:8, _GodId:16, _GodHp:64, _GodHpLim:64,
    RestBin10/binary>> = RestBin9,
    OtherRole = #scene_role{
        id = Id, platform = Platform, server_id = ServerId,
        figure = Figure, x = X, y = Y, hp = Hp, hp_lim = HpLim,
        speed = Speed, hide = Hide, ghost = Ghost, group = Group,
        team_id = TeamId, pk_status = PkStatus,
        power = Power, is_ride = IsRide, mount_figure = MountFigure,
        pk_value = PkValue, pet_figure = PetFigure,
        pet_hide_status = PetHideStatus, pk_protect_time = PkProtectTime
    },
    {OtherRole, RestBin10}.

%% 读取12007怪物信息
read_12007_mon(Bin) ->
    FunActLabel = fun(<<ActType:8, Label:32, RestBinX/binary>>) ->
            {{ActType, Label}, RestBinX}
    end,
    FunReadBuff = fun(<<K:16, EffectId:16, SkillId:32, SkillLv:8, Stack:8,
            Int:32/signed, Float:32/signed, T:64, RestBinX/binary>>) ->
            {{K, EffectId, SkillId, SkillLv, Stack, Int, Float, T}, RestBinX}
    end,
    <<X:16, Y:16, Id:32, Mid:32, Hp:64, HpLim:64, Lv:16, RestBin1/binary>> = Bin,
    {Name, RestBin2} = pt:read_string(RestBin1),
    <<Speed:16, Body:32, RestBin3/binary>> = RestBin2,
    {IconEff, RestBin4} = pt:read_string(RestBin3),
    <<IconTexture:32, WeaponId:32, AttType:8, Kind:8, Color:8, Out:8, Boss:8,
    CollectTime:32, IsBeClicked:8, IsBeAtted:8, Hide:8, Ghost:8, Group:64,
    GuildId:64, _RoleId:64, Angle:16, AttrType:8, _Title:32, _PkProtectTime:32,
    RestBin5/binary>> = RestBin4,
    {_ActLabel, RestBin6} = pt:read_array(FunActLabel, RestBin5),
    {_BuffList, RestBin7} = pt:read_array(FunReadBuff, RestBin6),
    CliMon = #cli_mon{
        id = Id
        ,x = X
        ,y = Y
        ,mid = Mid
        ,hp = Hp
        ,hp_lim = HpLim
        ,level = Lv
        ,name = Name
        ,speed = Speed
        ,body = Body
        ,icon_eff = IconEff
        ,icon_texture = IconTexture
        ,weapon_id = WeaponId
        ,att_type = AttType
        ,kind = Kind
        ,color = Color
        ,out = Out
        ,boss = Boss
        ,collect_time = CollectTime
        ,is_be_clicked = IsBeClicked
        ,is_be_atted = IsBeAtted
        ,hide = Hide
        ,ghost = Ghost
        ,group = Group
        ,guild_id = GuildId
        ,angle = Angle
        ,attr_type = AttrType
    },
    {CliMon, RestBin7}.

% read_12013_partner(Bin) ->
%     FunReadLvModel = fun(<<Part:8, ModelId:32, RestBinX/binary>>) -> {{Part, ModelId}, RestBinX} end,
%     <<X:16, Y:16, Id:32, Hp:64, HpLim:64, RestBin1/binary>> = Bin,
%     {Name, RestBin2} = pt:read_string(RestBin1),
%     <<Lv:16, Speed:16, Career:8, Hide:8, Group:16, RestBin3/binary>> = RestBin2,
%     {LvModel, RestBin4} = pt:read_array(FunReadLvModel, RestBin3),
%     <<IconTexture:32, OwnerId:64, RestBin5/binary>> = RestBin4,
%     %% 伙伴暂时没用
%     _Partner = {X, Y, Id, Hp, HpLim, Name, Lv, Speed, Career, Hide, Group, LvModel, IconTexture, OwnerId},
%     {_Partner, RestBin5}.

read_12014_object(Bin) ->
    <<X:16, Y:16, Id:32, RestBin1/binary>> = Bin,
    {Name, RestBin2} = pt:read_string(RestBin1),
    <<Body:32, RestBin3/binary>> = RestBin2,
    {IconEff, RestBin4} = pt:read_string(RestBin3),
    <<Speed:16, IsBeClicked:8, TeamId:64, PlayerId:64, RestBin5/binary>> = RestBin4,
    _Object = {X, Y, Id, Name, Body, IconEff, Speed, IsBeClicked, TeamId, PlayerId},
    {_Object, RestBin5}.

read_12015_dummy(Bin) ->
    <<Id:32, _:16, _:16, RestBin1/binary>> = Bin,
    {Figure, RestBin2} = cli_simu_proto:read_figure(RestBin1),
    <<X:16, Y:16, Hp:64, HpLim:64, Speed:16, Hide:8, Ghost:8, Group:64,
    CombatPower:32, IsDance:8, SvrNum:16, RestBin3/binary>> = RestBin2,
    _Dummy = {Id, Figure, X, Y, Hp, HpLim, Speed, Hide, Ghost, Group, CombatPower, IsDance, SvrNum},
    {_Dummy, RestBin3}.

