using System;
using System.Collections.Generic;
using System.Text;
using CommonLang.IO;
using CommonAI.Zone;
using CommonLang.IO.Attribute;
using CommonAI.Zone.Helper;
using CommonLang;
using CommonAI.Data;
using CommonAI.data;

namespace CommonAI.ZoneClient
{
    public static class ClientStruct
    {
        public struct UnitBuffStatus : IExternalizable
        {
            public int BuffTemplateID;
            public uint SenderID;
            public bool IsEquip;
            public int TotalTime;
            public int PassTime;
            public byte OverlayLevel;
            public int ext;                 //扩展字段,目前非网络流字段

            public void WriteExternal(IOutputStream output)
            {
                output.PutS32(BuffTemplateID);
                output.PutVU32(SenderID);
                output.PutBool(IsEquip);
                output.PutVS32(TotalTime);
                output.PutVS32(PassTime);
                output.PutU8(OverlayLevel);
            }
            public void ReadExternal(IInputStream input)
            {
                this.BuffTemplateID = input.GetS32();
                this.SenderID = input.GetVU32();
                this.IsEquip = input.GetBool();
                this.TotalTime = input.GetVS32();
                this.PassTime = input.GetVS32();
                this.OverlayLevel = input.GetU8();
            }

            public override string ToString()
            {
                return "[" + BuffTemplateID + ", " + TotalTime + ", " + PassTime + ", " + OverlayLevel + ", " + ext + "]";
            }
        }
        public struct UnitSkillStatus : IExternalizable
        {
            public int SkillTemplateID;
            public int PassTime;
			public int useTimes;
			public void WriteExternal(IOutputStream output)
            {
                output.PutS32(SkillTemplateID);
                output.PutVS32(PassTime);
				output.PutS32(useTimes);
            }
            public void ReadExternal(IInputStream input)
            {
                this.SkillTemplateID = input.GetS32();
                this.PassTime = input.GetVS32();
				this.useTimes = input.GetS32();
            }
        }
        public struct UnitItemStatus : IExternalizable
        {
            public int ItemTemplateID;
            public int Count;
            public void WriteExternal(IOutputStream output)
            {
                output.PutS32(ItemTemplateID);
                output.PutVS32(Count);
            }
            public void ReadExternal(IInputStream input)
            {
                this.ItemTemplateID = input.GetS32();
                this.Count = input.GetVS32();
            }
        }
        public class ZoneEnvironmentVar : IExternalizable
        {
            public string Key;
            public bool SyncToClient;
            public object Value;

            public void WriteExternal(IOutputStream output)
            {
                output.PutUTF(Key);
                output.PutBool(SyncToClient);
                output.PutData(Value);
            }
            public void ReadExternal(IInputStream input)
            {
                DataType dt;
                this.Key = input.GetUTF();
                this.SyncToClient = input.GetBool();
                this.Value = input.GetData(out dt);
            }
        }

    }


    /// <summary>
    /// 单位的客户端显示数据,通常存储横向功能,比如Avatar
    /// </summary>
    public interface IUnitVisibleData : IExternalizable
    {
        void setVisibleName(String name);
		void setVisibleCardData(ICardData datas);
    }

    abstract public class SyncObjectInfo : IExternalizable
    {
        public uint ObjectID;
        public int TemplateID;

        public float x;
        public float y;
        public float direction;

        /// <summary>
        /// 用于扩展属性
        /// </summary>
        public IExternalizable ExtData;

        public abstract bool IsHalf { get; protected set; }
        public abstract bool HasExtData { get; protected set; }

        public virtual void ReadExternal(IInputStream input)
        {
            this.ObjectID = input.GetVU32();
            this.TemplateID = input.GetS32();
            MoveHelper.ReadPosAndDirection(IsHalf, out x, out y, out direction, input);
            if (HasExtData)
            {
                this.ExtData = input.GetExtAny();
            }
        }
        public virtual void WriteExternal(IOutputStream output)
        {
            output.PutVU32(ObjectID);
            output.PutS32(TemplateID);
            MoveHelper.WritePosAndDirection(IsHalf, x, y, direction, output);
            if (HasExtData)
            {
                output.PutExt(this.ExtData);
            }
        }
    }

    /// <summary>
    /// 场景中同步单位数据
    /// </summary>
    [MessageType(0x9010)]
    public class SyncUnitInfo : SyncObjectInfo
    {
        public string Name;
        public string Alias;
        public int Force;

        public int Level;
        public string PlayerUUID;
        public byte status;
        public byte sub_status;
		public short sub_flag;          //sub_status>0才会有

		// 天命属性
		public byte fateType;

        public UnitFieldChangedEvent fields = new UnitFieldChangedEvent();
        public ClientStruct.UnitBuffStatus[] CurrentBuffStatus;
        public IUnitVisibleData VisibleInfo;

        //---------------------------------------------------
        private BitSet8 mask = new BitSet8(0);
        public override bool IsHalf
        {
            get { return mask.Get(0); }
            protected set { mask.Set(0, value); }
        }
        public override bool HasExtData
        {
            get { return mask.Get(1); }
            protected set { mask.Set(1, value); }
        }
        public bool HasName
        {
            get { return mask.Get(2); }
            private set { mask.Set(2, value); }
        }
        public bool HasPlayerUUID
        {
            get { return mask.Get(3); }
            private set { mask.Set(3, value); }
        }
        public bool HasAlias
        {
            get { return mask.Get(4); }
            private set { mask.Set(4, value); }
        }
        public bool IsTouchObj
        {
            get { return mask.Get(5); }
            set { mask.Set(5, value); }
        }
        public bool IsTouchMap
        {
            get { return mask.Get(6); }
            set { mask.Set(6, value); }
        }
        public bool IsStaticBlockable
        {
            get { return mask.Get(7); }
            set { mask.Set(7, value); }
        }
        //---------------------------------------------------
        public SyncUnitInfo(bool is_half) { this.IsHalf = is_half; }
        public SyncUnitInfo() { }

        public override void ReadExternal(IInputStream input)
        {
            this.mask.Mask = input.GetU8();
            base.ReadExternal(input);
            this.Force = input.GetS32();
            this.Level = input.GetVS32();
            if (HasName) this.Name = input.GetUTF();
            if (HasPlayerUUID) this.PlayerUUID = input.GetUTF();
            if (HasAlias) this.Alias = input.GetUTF();
            this.VisibleInfo = input.GetExtAny() as IUnitVisibleData;
            this.CurrentBuffStatus = input.GetStructArray<ClientStruct.UnitBuffStatus>();
            this.status = input.GetU8();
            this.sub_status = input.GetU8();

			this.fateType = input.GetU8();

			this.fields.ReadExternal(input);		
			
			if(this.sub_status > 0)
			{
				this.sub_flag = input.GetS16();
			}	
        }
        public override void WriteExternal(IOutputStream output)
        {
            this.HasName = !string.IsNullOrEmpty(Name);
            this.HasPlayerUUID = !string.IsNullOrEmpty(PlayerUUID);
            this.HasAlias = !string.IsNullOrEmpty(Alias);
            this.HasExtData = ExtData != null;

            output.PutU8(mask.Mask);
            base.WriteExternal(output);
            output.PutS32(Force);
            output.PutVS32(Level);
            if (HasName) output.PutUTF(Name);
            if (HasPlayerUUID) output.PutUTF(PlayerUUID);
            if (HasAlias) output.PutUTF(Alias);
            output.PutExt(VisibleInfo);
            output.PutStructArray(this.CurrentBuffStatus);
            output.PutU8(status);
            output.PutU8(sub_status);

			output.PutU8(fateType);

            fields.WriteExternal(output);

			if(this.sub_status > 0)
			{
				output.PutS16(this.sub_flag);
			}
        }
    }
    /// <summary>
    /// 场景中同步物品数据
    /// </summary>
    [MessageType(0x9011)]
    public class SyncItemInfo : SyncObjectInfo
    {
        public bool bDrop;
        public string Name;
        public string Alias;
        public int Force;
        public int ItemTotalTimeMS;
        public int ItemExpireTimeMS;

        public bool showItemLeftTimes;
		public bool isCanPick;			//是否还能够拾取

        //---------------------------------------------------
        private BitSet8 mask = new BitSet8(0);
        public override bool IsHalf
        {
            get { return mask.Get(0); }
            protected set { mask.Set(0, value); }
        }
        public override bool HasExtData
        {
            get { return mask.Get(4); }
            protected set { mask.Set(4, value); }
        }
        public bool HasName
        {
            get { return mask.Get(1); }
            private set { mask.Set(1, value); }
        }
        public bool HasAlias
        {
            get { return mask.Get(3); }
            private set { mask.Set(3, value); }
        }
        //---------------------------------------------------
        public SyncItemInfo(bool is_half) { this.IsHalf = is_half; bDrop = false; }
        public SyncItemInfo() { bDrop = false; }

        public override void ReadExternal(IInputStream input)
        {
            this.mask.Mask = input.GetU8();
            base.ReadExternal(input);
            this.Force = input.GetVS32();
            this.ItemExpireTimeMS = input.GetVS32();
            this.ItemTotalTimeMS = input.GetVS32();
            if (HasName) this.Name = input.GetUTF();
            if (HasAlias) this.Alias = input.GetUTF();

            this.showItemLeftTimes = input.GetBool();
			this.isCanPick = input.GetBool();
		}
        public override void WriteExternal(IOutputStream output)
        {
            this.HasName = !string.IsNullOrEmpty(Name);
            this.HasAlias = !string.IsNullOrEmpty(Alias);
            this.HasExtData = ExtData != null;
            output.PutU8(mask.Mask);
            base.WriteExternal(output);
            output.PutVS32(Force);
            output.PutVS32(ItemExpireTimeMS);
            output.PutVS32(ItemTotalTimeMS);
            if (HasName) output.PutUTF(Name);
            if (HasAlias) output.PutUTF(Alias);

            output.PutBool(this.showItemLeftTimes);
			output.PutBool(this.isCanPick);
        }
    }
    /// <summary>
    /// 场景中同步法术数据
    /// </summary>
    [MessageType(0x9012)]
    public class SyncSpellInfo : SyncObjectInfo
    {
        public int Force;
        public float CurSpeed;
        //---------------------------------------------------
        private BitSet8 mask = new BitSet8(0);
        public override bool IsHalf
        {
            get { return mask.Get(0); }
            protected set { mask.Set(0, value); }
        }
        public override bool HasExtData
        {
            get { return mask.Get(4); }
            protected set { mask.Set(4, value); }
        }
        public bool HasSpeed
        {
            get { return mask.Get(4); }
            set { mask.Set(4, value); }
        }
        //---------------------------------------------------
        public SyncSpellInfo(bool is_half) { this.IsHalf = is_half; }
        public SyncSpellInfo() { }

        public override void ReadExternal(IInputStream input)
        {
            this.mask.Mask = input.GetU8();
            base.ReadExternal(input);
            this.Force = input.GetVS32();
            if (HasSpeed)
            {
                this.CurSpeed = input.GetF32();
            }
        }
        public override void WriteExternal(IOutputStream output)
        {
            this.HasExtData = ExtData != null;
            output.PutU8(mask.Mask);
            base.WriteExternal(output);
            output.PutVS32(Force);
            if (HasSpeed)
            {
                output.PutF32(CurSpeed);
            }
        }
    }

    /*
    /// <summary>
    /// 场景中同步单位数据
    /// </summary>
    [MessageType(0x9000)]
    public class SyncUnitInfo : IExternalizable
    {
        public uint ObjectID;
        public SyncUnitType ObjectType = SyncUnitType.Unit;
        public int TemplateID;

        public string Name;
        public string Alias;
        public byte Force;

        public float x;
        public float y;
        public float direction;
        /// <summary>
        /// 用于扩展属性
        /// </summary>
        public IExternalizable ExtData;
        //---------------------------------------------------
        #region units
        public int Level;
        public string PlayerUUID;
        public byte status;
        public byte sub_status;
        public UnitFieldChangedEvent fields = new UnitFieldChangedEvent();
        public ClientStruct.UnitBuffStatus[] CurrentBuffStatus;
        /// <summary>
        /// 战斗服玩家属性,通常存储横向功能,比如Avatar
        /// </summary>
        public CreateUnitInfoR2B PlayerInfo;
        #endregion
        //---------------------------------------------------
        #region items
        public int ItemTotalTimeMS;
        public int ItemExpireTimeMS;
        #endregion
        //---------------------------------------------------
        private BitSet8 mask = new BitSet8(0);
        public bool IsHalf
        {
            get { return mask.Get(0); }
            private set { mask.Set(0, value); }
        }
        public bool HasName
        {
            get { return mask.Get(1); }
            private set { mask.Set(1, value); }
        }
        public bool HasPlayerUUID
        {
            get { return mask.Get(2); }
            private set { mask.Set(2, value); }
        }
        public bool HasAlias
        {
            get { return mask.Get(3); }
            private set { mask.Set(3, value); }
        }
        public bool HasExtData
        {
            get { return mask.Get(4); }
            private set { mask.Set(4, value); }
        }
        //---------------------------------------------------
        public SyncUnitInfo(bool is_half) { }
        public SyncUnitInfo() { }

        public void ReadExternal(IInputStream input)
        {
            this.mask.Mask = input.GetU8();
            this.ObjectType = (SyncUnitType)input.GetU8();
            this.ObjectID = input.GetVU32();
            this.TemplateID = input.GetS32();
            if (HasName)
            {
                this.Name = input.GetUTF();
            }

            MoveHelper.ReadPosAndDirection(IsHalf, out x, out y, out direction, input);

            if (ObjectType == SyncUnitType.Item)
            {
                this.Force = input.GetU8();
                this.ItemExpireTimeMS = input.GetVS32();
                this.ItemTotalTimeMS = input.GetVS32();
                if (HasAlias)
                {
                    this.Alias = input.GetUTF();
                }
            }
            else if (ObjectType == SyncUnitType.Unit)
            {
                this.Force = input.GetU8();
                this.Level = input.GetVS32();
                if (HasPlayerUUID)
                {
                    this.PlayerUUID = input.GetUTF();
                }
                if (HasAlias)
                {
                    this.Alias = input.GetUTF();
                }
                this.PlayerInfo = input.GetExt<CreateUnitInfoR2B>();
                this.CurrentBuffStatus = input.GetStructArray<ClientStruct.UnitBuffStatus>();
                this.status = input.GetU8();
                this.sub_status = input.GetU8();
                this.fields.ReadExternal(input);
            }
            if (HasExtData)
            {
                this.ExtData = input.GetExtAny();
            }
        }
        public void WriteExternal(IOutputStream output)
        {
            this.HasName = !string.IsNullOrEmpty(Name);
            this.HasPlayerUUID = !string.IsNullOrEmpty(PlayerUUID);
            this.HasAlias = !string.IsNullOrEmpty(Alias);
            this.HasExtData = ExtData != null;

            output.PutU8(mask.Mask);
            output.PutU8((byte)ObjectType);
            output.PutVU32(ObjectID);
            output.PutS32(TemplateID);
            if (HasName)
            {
                output.PutUTF(Name);
            }

            MoveHelper.WritePosAndDirection(IsHalf, x, y, direction, output);

            if (ObjectType == SyncUnitType.Item)
            {
                output.PutU8(Force);
                output.PutVS32(ItemExpireTimeMS);
                output.PutVS32(ItemTotalTimeMS);
                if (HasAlias)
                {
                    output.PutUTF(Alias);
                }
            }
            else if (ObjectType == SyncUnitType.Unit)
            {
                output.PutU8(Force);
                output.PutVS32(Level);
                if (HasPlayerUUID)
                {
                    output.PutUTF(PlayerUUID);
                }
                if (HasAlias)
                {
                    output.PutUTF(Alias);
                }
                output.PutExt(PlayerInfo);
                output.PutStructArray(this.CurrentBuffStatus);
                output.PutU8(status);
                output.PutU8(sub_status);
                fields.WriteExternal(output);
            }
            if (HasExtData)
            {
                output.PutExt(ExtData);
            }
        }
    }
    */

    /// <summary>
    /// 同步场景中所有单位
    /// </summary>
    [MessageType(0x9001)]
    public class SyncObjectsEvent : ZoneEvent
    {
        public List<SyncObjectInfo> Objects;
        public SyncObjectsEvent() { }
        public SyncObjectsEvent(int count)
        {
            this.Objects = new List<SyncObjectInfo>(count);
        }

        override public void WriteExternal(IOutputStream output)
        {
            int len = Objects.Count;
            output.PutVS32(len);
            for (int i = 0; i < len; i++)
            {
                output.PutExt(Objects[i]);
            }
        }
        override public void ReadExternal(IInputStream input)
        {
            int len = input.GetVS32();
            this.Objects = new List<SyncObjectInfo>(len);
            for (int i = 0; i < len; i++)
            {
                SyncObjectInfo add = input.GetExtAny() as SyncObjectInfo;
                Objects.Add(add);
            }
        }
    }

    /// <summary>
    /// 玩家登陆到服务器后,服务器分配对应的单位ID
    /// </summary>
    [MessageType(0x9002)]
    public class LockActorEvent : ZoneEvent
    {
        /// <summary>
        /// 当前房间单位信息
        /// </summary>
        public SyncUnitInfo UnitData;

        /// <summary>
        /// 服务端传过来的单位信息
        /// </summary>
        public IUnitProperties GameServerProp;

        /// <summary>
        /// 服务端更新速度/秒
        /// </summary>
        public int ServerUpdateInterval;
        /// <summary>
        /// 客户端同步范围
        /// </summary>
        public float ClientSyncObjectRange;
        /// <summary>
        /// 客户端同步范围
        /// </summary>
        public float ClientSyncObjectOutRange;

        public PlayerSkillChangedEvent Skills;
        public ClientStruct.UnitSkillStatus[] CurrentSkillStatus;
        public ClientStruct.UnitItemStatus[] CurrentItemStatus;
        public ClientStruct.ZoneEnvironmentVar[] CurrentZoneVars;
        public ClientStruct.ZoneEnvironmentVar[] CurrentPlayerVars;

        override public void WriteExternal(IOutputStream output)
        {
            output.PutExt(this.UnitData);
            output.PutExt(this.GameServerProp);
            output.PutVS32(this.ServerUpdateInterval);
            output.PutF32(this.ClientSyncObjectRange);
            output.PutF32(this.ClientSyncObjectOutRange);

            output.PutExt(this.Skills);
            output.PutStructArray(this.CurrentSkillStatus);
            output.PutStructArray(this.CurrentItemStatus);
            output.PutExtArray(this.CurrentZoneVars);
            output.PutExtArray(this.CurrentPlayerVars);

        }
        override public void ReadExternal(IInputStream input)
        {
            this.UnitData = input.GetExt<SyncUnitInfo>();
            this.GameServerProp = input.GetExtAny() as IUnitProperties;
            this.ServerUpdateInterval = input.GetVS32();
            this.ClientSyncObjectRange = input.GetF32();
            this.ClientSyncObjectOutRange = input.GetF32();

            this.Skills = input.GetExt<PlayerSkillChangedEvent>();
            this.CurrentSkillStatus = input.GetStructArray<ClientStruct.UnitSkillStatus>();
            this.CurrentItemStatus = input.GetStructArray<ClientStruct.UnitItemStatus>();
            this.CurrentZoneVars = input.GetExtArray<ClientStruct.ZoneEnvironmentVar>();
            this.CurrentPlayerVars = input.GetExtArray<ClientStruct.ZoneEnvironmentVar>();
        }
    }

    /// <summary>
    /// 连接到代理服务器
    /// </summary>
    [MessageType(0x9003)]
    public class ConnectToProxy : ZoneEvent
    {
        public string ConnectString;
        public ConnectToProxy() { }
        public ConnectToProxy(string connect_string)
        {
            this.ConnectString = connect_string;
        }
        override public void WriteExternal(IOutputStream output)
        {
            output.PutUTF(ConnectString);
        }
        override public void ReadExternal(IInputStream input)
        {
            this.ConnectString = input.GetUTF();
        }
    }
    /// <summary>
    /// 从代理服务器断开
    /// </summary>
    [MessageType(0x9004)]
    public class DisconnectFromProxy : ZoneEvent
    {
        override public void WriteExternal(IOutputStream output)
        {
        }
        override public void ReadExternal(IInputStream input)
        {
        }
    }

    /// <summary>
    /// 同步场景中所有Flag状态
    /// </summary>
    [MessageType(0x9005)]
    public class SyncFlagsEvent : ZoneEvent
    {
        public List<string> ClosedDecorations = new List<string>();
        public HashMap<string, string> ChangedTags = new HashMap<string, string>();

        public SyncFlagsEvent()
        {
        }

        override public void WriteExternal(IOutputStream output)
        {
            output.PutList(ClosedDecorations, output.PutUTF);
            output.PutMap(ChangedTags, output.PutUTF, output.PutUTF);
        }
        override public void ReadExternal(IInputStream input)
        {
            this.ClosedDecorations = input.GetUTFList();
            this.ChangedTags = input.GetMap<string, string>(input.GetUTF, input.GetUTF);
        }
    }

    [MessageType(0x9006)]
    public class ClientEnterScene : ZoneEvent
    {
        /// <summary>
        /// 场景ID
        /// </summary>
        public int sceneID;

        /// <summary>
        /// 分割大小
        /// </summary>
        public int spaceDiv;

        /// <summary>
        /// 资源版本
        /// </summary>
        public string resVersion;

        public ClientEnterScene() { }
        public ClientEnterScene(int sceneID, int spaceDiv, string resVer)
        {
            this.sceneID = sceneID;
            this.spaceDiv = spaceDiv;
            this.resVersion = resVer;
        }
        override public void WriteExternal(IOutputStream output)
        {
            output.PutS32(sceneID);
            output.PutVS32(spaceDiv);
            output.PutUTF(resVersion);
        }
        override public void ReadExternal(IInputStream input)
        {
            this.sceneID = input.GetS32();
            this.spaceDiv = input.GetVS32();
            this.resVersion = input.GetUTF();
        }
    }

    /// <summary>
    /// 玩家离开场景.
    /// </summary>
    [MessageType(0x9007)]
    public class PlayerLeaveScene : PlayerEvent
    {
        public PlayerLeaveScene() { }
        public PlayerLeaveScene(uint oid) : base(oid)
        {
        }
        override public void WriteExternal(IOutputStream output)
        {
            base.WriteExternal(output);
        }
        override public void ReadExternal(IInputStream input)
        {
            base.ReadExternal(input);
        }
    }

    [MessageType(0x9008)]
    public class AddEffectEvent2 : ZoneEvent, PositionMessage
    {
        public enum EffectType
        {
            None,
            MoveToTarget,
            MoveToPlayer
        }

        public uint hostId = 0;

        public float x;
        public float y;
        public float direction;
        private uint effect_sn = 0;
        private EffectType et;
        private float targetX;
        private float targetY;
        private bool followActor;
        public LaunchEffect effect { get; set; }
        public AddEffectEvent2() { }
        public AddEffectEvent2(uint hostId, float x, float y, float dir, LaunchEffect effect, EffectType et, float targetX, float targetY, bool followActor = false)
        {
            this.hostId = hostId;
            this.x = x;
            this.y = y;
            this.direction = dir;
            this.effect = effect;
            this.et = et;
            this.targetX = targetX;
            this.targetY = targetY;
            this.followActor = followActor;
        }
        override public void WriteExternal(IOutputStream output)
        {
            output.PutVU32(hostId);
            output.PutF32(x);
            output.PutF32(y);
            output.PutF32(direction);
            output.PutVU32(effect_sn);
        }
        override public void ReadExternal(IInputStream input)
        {
            this.hostId = input.GetVU32();
            this.x = input.GetF32();
            this.y = input.GetF32();
            this.direction = input.GetF32();
            this.effect_sn = input.GetVU32();
        }
        public override void BeforeWrite(TemplateManager templates)
        {
            if (effect != null)
            {
                this.effect_sn = effect.SerialNumber;
            }
        }
        public override void EndRead(TemplateManager templates)
        {
            this.effect = templates.GetSnData<LaunchEffect>(effect_sn);
        }
        public float X { get { return x; } }
        public float Y { get { return y; } }

        public float TargetX
        {
            get { return targetX; }
        }

        public float TargetY
        {
            get { return targetY; }
        }

        public bool FollowActor
        {
            get { return followActor; }
        }

        public EffectType ET
        {
            get { return et; }
        }

    }
}