using System;
using System.Collections.Generic;
using System.Text;
using CommonAI.ZoneClient;

using CommonAI.Zone.Helper;
using CommonLang;

namespace CommonAI.Zone.Instance
{
    /// <summary>
    /// 可拾取的道具
    /// </summary>
    public class InstanceItem : InstanceZoneObject, ViewTrigger.ViewTriggerListener
    {
		//拾取信息
		public HashMap<String, short> unitPickInfo = null;
		public int TotalPickTimes = 0;

		public string Name { get; private set; }
		public string DisPlayName { get; private set; }
		public string Alias { get { return mSyncInfo.Alias; } set { mSyncInfo.Alias = value; } }
        public override float Weight { get { return 0; } }
        

        protected ItemTemplate mData;
        protected SyncItemInfo mSyncInfo;
        protected ViewTrigger mViewTrigger;
        protected bool mClientVisible;
        protected bool mSyncPos;
        protected InstanceUnit mItemCreater;
        protected TimeExpire<int> mViewTriggerTimer;
        protected TimeExpire<int> mRemovedExpire;
        public int mFrom; //0:场景,1:游戏服

		public bool mPosValid = true;

        public InstanceItem(InstanceZone zone, ItemTemplate item, string name, int force, InstanceUnit creater, string disPlayName,int from)
            : base(zone, false)
        {
            this.Name = (name == null) ? "" : name;
			this.DisPlayName = (disPlayName == null) ? "" : disPlayName;
			this.mData = item;
            if(mData.LifeTimeMS > 0)
            {
                this.mRemovedExpire = new TimeExpire<int>(mData.LifeTimeMS);
            }
            else
            {
                this.mRemovedExpire = null;
            }
            //this.mRemovedExpire = new TimeExpire<int>(mData.LifeTimeMS);
            this.mViewTrigger = new ViewTriggerRoundBody(zone, item.BodySize);
            this.mViewTrigger.setListener(this);
            this.mViewTrigger.Enable = false;
            if (!mData.Pickable)
            {
                this.mViewTriggerTimer = new TimeExpire<int>(item.GotCoolDownTimeMS);
            }
            this.mSyncInfo = new SyncItemInfo(zone.IsHalfSync);
            this.mSyncInfo.TemplateID = mData.ID;
            this.mSyncInfo.Force = force;            
			this.mSyncInfo.showItemLeftTimes = mData.showLifeTime;

            if(mData.showLifeTime)
            {
                this.mSyncInfo.ItemTotalTimeMS = mData.LifeEndTime;
            }
            else
            {
                this.mSyncInfo.ItemTotalTimeMS = mData.LifeTimeMS;
            }

            this.Force = force;
            this.mClientVisible = item.ClientVisible;
            this.mSyncPos = false;// zone.SyncPos;
            this.mItemCreater = creater;
            this.mFrom = from;

			if(this.Info.maxPickPlayers > 0 || this.Info.maxPickTimes > 0)
			{
				unitPickInfo = new HashMap<String, short>(Math.Max(1, this.Info.maxPickPlayers/2));
            }
        }

        public ItemTemplate Info { get { return mData; } }
        public int Force { get; private set; }
        public override bool IntersectMap { get { return false; } }
        public override bool IntersectObj { get { return false; } }
        public override bool Moveable { get { return false; } }
        public override float BodyBlockSize { get { return mData.BodySize; } }
        override public float BodyHitSize { get { return mData.BodySize; } }
        public override float BodyHeight { get { return mData.BodySize; } }
        public override bool ClientVisible { get { return mClientVisible; } }
        public override bool SyncPos { get { return mSyncPos; } }
        public InstanceUnit ItemCreater { get { return mItemCreater; } }
        public int ExpireTimeMS {
            get {
                if(mRemovedExpire != null)
                {
                    return mRemovedExpire.TotalTimeMS - mRemovedExpire.PassTimeMS;
                }
                return int.MaxValue;
            }
        }

		public bool IsPosValid()
		{
			return this.mPosValid;
		}

		public void setPosNotValid()
		{
			this.mPosValid = false;
		}

        public override SyncObjectInfo GenSyncInfo(bool net)
        {
            return GenSyncItemInfo(net, null);
        }
        public SyncItemInfo GenSyncItemInfo(bool net, string playerId)
        {
            mSyncInfo.ItemExpireTimeMS = this.ExpireTimeMS;
			mSyncInfo.isCanPick = IsCanPick(playerId);

            return mSyncInfo;
        }

		//针对拾取人数上限控制是否移除
		public bool IsPickAll()
		{
			if(this.Info.maxPickPlayers > 0 && this.Info.maxPickTimes > 0)
			{
				return this.TotalPickTimes >= (this.Info.maxPickPlayers * this.Info.maxPickTimes);
			}

			return false;
		}


		public bool IsCanPick(String playerId)
		{
			if (this.unitPickInfo == null)
			{
				return true;
			}

			if (this.Info.maxPickTimes > 0)
			{
				if (playerId != null && this.unitPickInfo.ContainsKey(playerId))
				{
					return this.unitPickInfo.Get(playerId) < this.Info.maxPickTimes;
				}
				else
				{
					return this.Info.maxPickPlayers == 0 || this.unitPickInfo.Count < this.Info.maxPickPlayers;
				}
			}

			return this.unitPickInfo.Count < this.Info.maxPickPlayers || (playerId != null && this.unitPickInfo.ContainsKey(playerId));
		}

        protected override void onAdded(bool pointLv)
        {
            this.mSyncInfo.x = X;
            this.mSyncInfo.y = Y;
            this.mSyncInfo.ObjectID = base.ID;
            this.mSyncInfo.direction = Direction;
            this.mSyncInfo.Alias = this.Alias;
            this.mSyncInfo.Name = this.DisPlayName;
        }
        protected override void Disposing()
        {
            base.Disposing();
            mViewTrigger.Dispose();
        }
        protected override void onRemoved()
        {

        }

        protected override void onUpdate(bool slowRefresh)
        {
            if (IsPaused) { return; }
            if (mRemovedExpire != null && mRemovedExpire.Update(Parent.UpdateIntervalMS))
            {
                Parent.RemoveObject(this);
            }
            if (mViewTriggerTimer != null && mViewTriggerTimer.Update(Parent.UpdateIntervalMS))
            {
                mViewTrigger.Enable = true;
                mViewTrigger.onLookUpdate(X, Y);
            }
        }

        public virtual bool IsPickable(InstanceUnit u)
        {
			if (this.Info.OnlyForShow)
			{
				return false;
			}

			if (!this.mPosValid)
			{
				return false;
			}

            if(u.IsDead())
            {
                return false;
            }
            /*if (!mData.Pickable)//此参数为是否可手动拾取,而非是否能拾取
            {
                return false;
            }*/
            if (mData.PlayerOnly && (!u.IsPlayer))
            {
                return false;
            }
            if (!this.Enable)
            {
                return false;
            }
            if (mData.DropForAll || Force == u.Force)
            {
                if (tryPickItem(u) && Parent.cb_unitTryPickItem(u, this))
                {
                    return true;
                }
            }
            return false;
        }

        public bool DirectPickItem(InstanceUnit u,System.Action action = null)
        {
            if (IsPickable(u))
            {
                Parent.cb_unitFinishPickItem(u, this);
                bool remove;
				int pickTimes;
                if (u.doGotInstanceItem(this, out remove, out pickTimes))
                {
                    if (Info.GotEffectSelf != null)
                    {
                        Parent.queueEvent(new AddEffectEvent(this.ID, X, Y, Direction, Info.GotEffectSelf));
                    }
                    u.queueEvent(new UnitGotInstanceItemEvent(u.ID, this.ID));
                    if (remove)
                    {
                        if(action != null)
                        {
                            action.Invoke();
                        }
                        mViewTrigger.Enable = false;
                        Parent.RemoveObject(this);
                    }
                }
                return true;
            }
            return false;
        }

        public bool PickItem(InstanceUnit u)
        {
            if (IsPickable(u))
            {
                if (Parent.TouchObject2(u, this))
                {
                    if (tryPickItem(u) && Parent.cb_unitTryPickItem(u, this))
                    {
                        u.startPickProgressObject(this, mData.PickTimeMS, (unit, pickable) =>
                        {
                            if (this.Enable)
                            {
                                Parent.cb_unitFinishPickItem(u, this);
                                bool remove;
								int pickTimes;
								if (u.doGotInstanceItem(this, out remove, out pickTimes))
                                {
                                    if (Info.GotEffectSelf != null)
                                    {
                                        Parent.queueEvent(new AddEffectEvent(this.ID , X, Y, Direction, Info.GotEffectSelf));
                                    }

									InstancePlayer player = (u as InstancePlayer);
									int flag = this.IsCanPick(player == null ? null : player.PlayerUUID) ? 0 : 1;
                                    u.queueEvent(new UnitGotInstanceItemEvent(u.ID, this.ID, (byte)flag));

									//如果标记移除,或者拾取人数达上限
									if (remove || this.IsPickAll())
                                    {
                                        mViewTrigger.Enable = false;
                                        Parent.RemoveObject(this);
                                    }
                                }
                            }
                        });
                        return true;
                    }
                }
            }
            return false;
        }

        private bool tryPickItem(InstanceUnit unit)
        {
            if (!Parent.IsVisibleAOI(unit, this))
            {
                return false;
            }
            bool ret = true;
            if (mTryPickItem != null)
            {
                foreach (TryPickItem trypick in mTryPickItem.GetInvocationList())
                {
                    if (!trypick.Invoke(this, unit))
                    {
                        ret = false;
                    }
                }
            }
            return ret;
        }

        #region _Collides_

        void ViewTrigger.ViewTriggerListener.onObjectEnterView(ViewTrigger src, InstanceZoneObject obj)
        {
            if (!mData.Pickable && !mData.OnlyForShow)
            {
                InstanceUnit u = obj as InstanceUnit;
                if (mData.PlayerOnly && (!u.IsPlayer))
                {
                    return;
                }
                if ((mData.DropForAll || Force == u.Force) && this.IsPickable(u))
                {
                    bool remove;
					int pickTimes;
					if (u.doGotInstanceItem(this, out remove, out pickTimes))
                    {
						u.NotifyRemoveDropItemB2C(this);

						if (Info.GotEffectSelf != null)
                        {
                            Parent.queueEvent(new AddEffectEvent(this.ID, X, Y, Direction, Info.GotEffectSelf));
                        }
                        u.queueEvent(new UnitGotInstanceItemEvent(u.ID, this.ID));
                        if (remove)
                        {
                            mViewTrigger.Enable = false;
                            Parent.RemoveObject(this);
                        }
                    }
                } 
            }
        }
        void ViewTrigger.ViewTriggerListener.onObjectLeaveView(ViewTrigger src, InstanceZoneObject obj)
        {

        }
        bool ViewTrigger.ViewTriggerListener.select(ViewTrigger src, InstanceZoneObject obj)
        {
            if (obj == this)
            {
                return false;
            }
            else if (obj is InstanceUnit)
            {
                return true;
            }
            return false;
        }

		public override String GetTemplateData()
		{
			return "Item:" + this.Info.ID;
		}

		#endregion

		#region _API_

		public ItemTemplate get_template()
        {
            return mData;
        }
        public bool is_attribute(string key)
        {
            return IsAttribute(key);
        }
        public void set_attribute(string key, object value)
        {
            SetAttribute(key, value);
        }
        public object get_attribute(string key)
        {
            return GetAttribute(key);
        }

        #endregion

        #region _Delegate_

        /// <summary>
        /// 单位尝试检取道具监听,
        /// 返回False禁止检取
        /// </summary>
        /// <returns></returns>
        public delegate bool TryPickItem(InstanceItem item, InstanceUnit unit);
        private TryPickItem mTryPickItem;
        public event TryPickItem OnTryPickItem { add { mTryPickItem += value; } remove { mTryPickItem -= value; } }

        protected override void clearEvents()
        {
            base.clearEvents();
            this.mTryPickItem = null;
        }

        #endregion

    }
}