using System;
using System.Collections.Generic;
using CommonAI.Zone;
using CommonLang;


namespace CommonAI.ZoneClient
{
    partial class ZoneLayer
    {
        private LayerObjectMap mObjectes = new LayerObjectMap();
        private HashMap<string, ZoneFlag> mFlags = new HashMap<string, ZoneFlag>();

        private ZoneActor mActor;

        /// <summary>
        /// 获取所有单位状态
        /// </summary>
        public ICollection<ZoneObject> Objects { get { return mObjectes.Objects; } }
        public int ObjectsCount { get { return mObjectes.ObjectsCount; } }

        public ICollection<ZoneUnit> Units { get { return mObjectes.Units; } }
        public int UnitsCount { get { return mObjectes.UnitsCount; } }

        public ICollection<ZoneSpell> Spells { get { return mObjectes.Spells; } }
        public int SpellsCount { get { return mObjectes.SpellsCount; } }

        public ICollection<ZoneItem> Items { get { return mObjectes.Items; } }
        public int ItemsCount { get { return mObjectes.ItemsCount; } }

        /// <summary>
        /// 获取所有装饰物状态
        /// </summary>
        public ICollection<ZoneFlag> Flags { get { return mFlags.Values; } }

        /// <summary>
        /// 主角
        /// </summary>
        public ZoneActor Actor { get { return mActor; } }

        /// <summary>
        /// 主角ID
        /// </summary>
        public uint ActorID { get { return mActor != null ? mActor.ObjectID : 0; } }


        /// <summary>
        /// 获取一个可显示对象
        /// </summary>
        /// <typeparam name="T">ZoneObject的子类</typeparam>
        /// <param name="objID"></param>
        /// <returns></returns>
        public T GetObject<T>(uint objID) where T : ZoneObject
        {
            return mObjectes.GetObject<T>(objID);
        }
        /// <summary>
        /// 获取一个可显示对象
        /// </summary>
        /// <param name="objID"></param>
        /// <returns></returns>
        public ZoneObject GetObject(uint objID)
        {
            return mObjectes.GetObject<ZoneObject>(objID);
        }
        /// <summary>
        /// 获取一个单位
        /// </summary>
        /// <param name="objID"></param>
        /// <returns></returns>
        public ZoneUnit GetUnit(uint objID)
        {
            return mObjectes.GetObject<ZoneUnit>(objID);
        }
        /// <summary>
        /// 根据模板找单位
        /// </summary>
        /// <param name="templateID"></param>
        /// <returns></returns>
        public ZoneUnit GetUnitByTemplateID(int templateID)
        {
            foreach (var u in mObjectes.Units)
            {
                if (u.TemplateID == templateID)
                {
                    return u;
                }
            }
            return null;
        }
        /// <summary>
        /// 获取一个玩家单位
        /// </summary>
        /// <param name="uuid"></param>
        /// <returns></returns>
        public ZoneUnit GetPlayerUnit(string uuid)
        {
            if (mObjectes == null)
            {
                return null;
            }
            return mObjectes.GetPlayer(uuid);
        }

        public virtual bool IsAttackable(ZoneUnit src, ZoneUnit target, SkillTemplate.CastTarget expectTarget)
        {
            if (target.IsActive)
            {
                switch (expectTarget)
                {
                    case SkillTemplate.CastTarget.Enemy:
                        return src.Force != target.Force;
                    case SkillTemplate.CastTarget.PetForMaster:
                        if (src.Info.UType == UnitInfo.UnitType.TYPE_PET)
                        {
                            return (src != target) && (src.Force == target.Force);
                        }
                        return false;
                    case SkillTemplate.CastTarget.Alias:
                        return (src != target) && (src.Force == target.Force);


                    case SkillTemplate.CastTarget.AlliesIncludeSelf:
                        return (src.Force == target.Force);
                    case SkillTemplate.CastTarget.AlliesExcludeSelf:
                        return (src != target) && (src.Force == target.Force);

                    case SkillTemplate.CastTarget.EveryOne:
                        return true;
                    case SkillTemplate.CastTarget.EveryOneExcludeSelf:
                        return (src != target);

                    case SkillTemplate.CastTarget.Self:
                        return src == target;
					case SkillTemplate.CastTarget.EnemyAndSelf:
						return src.Force != target.Force || src == target;
					case SkillTemplate.CastTarget.NA:
                    default:
                        return false;
                }
            }
            return false;
        }

        /// <summary>
        /// 获取一个编辑器标记
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public T GetFlag<T>(string name) where T : ZoneFlag
        {
            return mFlags.Get(name) as T;
        }
        public ZoneFlag GetFlag(string name)
        {
            return mFlags.Get(name);
        }

        public ZoneEditorUnit GetUnitFlagByTemplateID(int templateID)
        {
            foreach (var flag in mFlags.Values)
            {
                if (flag is ZoneEditorUnit)
                {
                    var u = flag as ZoneEditorUnit;
                    if (u.Data.UnitTemplateID == templateID)
                    {
                        return u;
                    }
                }
            }
            return null;
        }

        //-------------------------------------------------------------------------------------------------------//
        //
        //-------------------------------------------------------------------------------------------------------//

        private class LayerObjectMap
        {
            private HashMap<uint, ZoneObject> mObjects = new HashMap<uint, ZoneObject>();
            private List<ZoneObject> mObjectsList = new List<ZoneObject>();


            private HashMap<uint, ZoneUnit> mObjects_MirrorUnits = new HashMap<uint, ZoneUnit>();
            private HashMap<uint, ZoneSpell> mObjects_MirrorSpells = new HashMap<uint, ZoneSpell>();
            private HashMap<uint, ZoneItem> mObjects_MirrorItems = new HashMap<uint, ZoneItem>();
            private HashMap<string, ZoneUnit> mObjects_MirrorPlayers = new HashMap<string, ZoneUnit>();

            public T GetObject<T>(uint id) where T : ZoneObject
            {
                Type type = typeof(T);
                ZoneObject obj;
                if (type.IsSubclassOf(typeof(ZoneUnit)))
                {
                    return mObjects_MirrorUnits.Get(id) as T;
                }
                else if (type.IsSubclassOf(typeof(ZoneSpell)))
                {
                    if (mObjects_MirrorSpells.ContainsKey(id))
                    {
                        return mObjects_MirrorSpells.Get(id) as T;
                    }
                }
                else if (type.IsSubclassOf(typeof(ZoneItem)))
                {
                    return mObjects_MirrorItems.Get(id) as T;
                }
                else if (mObjects.TryGetValue(id, out obj))
                {
                    return obj as T;
                }
                return null;
            }
            public ZoneUnit GetPlayer(string uuid)
            {
                return mObjects_MirrorPlayers.Get(uuid);
            }

            public void Add(ZoneObject obj)
            {
                mObjects.Add(obj.ObjectID, obj);
                mObjectsList.Add(obj);
                if (obj is ZoneUnit)
                {
                    var u = obj as ZoneUnit;
                    mObjects_MirrorUnits.Add(obj.ObjectID, u);
                    if (!string.IsNullOrEmpty(u.PlayerUUID))
                    {
                        mObjects_MirrorPlayers.Put(u.PlayerUUID, u);
                    }
                }
                else if (obj is ZoneItem)
                {
                    mObjects_MirrorItems.Add(obj.ObjectID, obj as ZoneItem);
                }
                else if (obj is ZoneSpell)
                {
                    mObjects_MirrorSpells.Add(obj.ObjectID, obj as ZoneSpell);
                }
            }
            public ZoneObject RemoveObjectByKey(uint id)
            {
                ZoneObject obj = mObjects.RemoveByKey(id);
                if (obj != null)
                {
                    mObjectsList.Remove(obj);
                    if (obj is ZoneUnit)
                    {
                        var u = obj as ZoneUnit;
                        mObjects_MirrorUnits.Remove(id);
                        if (!string.IsNullOrEmpty(u.PlayerUUID))
                        {
                            mObjects_MirrorPlayers.Remove(u.PlayerUUID);
                        }
                    }
                    else if (obj is ZoneItem)
                    {
                        mObjects_MirrorItems.Remove(id);
                    }
                    else if (obj is ZoneSpell)
                    {
                        mObjects_MirrorSpells.Remove(id);
                    }
                }
                return obj;
            }
            public void Clear()
            {
                mObjects.Clear();
                mObjectsList.Clear();
                mObjects_MirrorItems.Clear();
                mObjects_MirrorSpells.Clear();
                mObjects_MirrorUnits.Clear();
                mObjects_MirrorPlayers.Clear();
            }
            public bool ContainsObjectByKey(uint id)
            {
                return mObjects.ContainsKey(id);
            }

            public ZoneItem GetNearPickableItem(ZoneActor owner)
            {
                var zl = owner.Parent;
                ZoneItem item = null;
                for (int i = mObjectsList.Count - 1; i >= 0; --i)
                {
                    item = mObjectsList[i] as ZoneItem;
                    if (item != null && item.Info != null && !item.Info.IsPopPanel && zl.IsCanPickItem(owner, item))
                    {
                        return item;
                    }
                }
                return null;
            }

            public ZoneItem GetNearPopPanelItem(ZoneActor owner)
            {
                var zl = owner.Parent;
                ZoneItem item = null;
                for (int i = mObjectsList.Count - 1; i >= 0; --i)
                {
                    item = mObjectsList[i] as ZoneItem;
                    if (item != null && item.Info != null && item.Info.IsPopPanel)
                    {
                        if (zl.IsCanPickItem(owner, item)) return item;
                    }
                }
                return null;
            }

            public ZoneItem GetDropItem()
            {
                ZoneItem item = null;
                foreach(ZoneItem i in mObjects_MirrorItems.Values)
                {
                    if(i.SyncInfo.bDrop == true)
                    {
                        item = i;
                        break;
                    }
                }
                return item;
            }

            /// <summary>
            /// 遍历所有元素,如果返回True,则立即Break
            /// </summary>
            /// <param name="action">return true if cancel for each</param>
            /// <returns>true if cancel</returns>
            public bool ForEachObjects(Predicate<ZoneObject> action)
            {
                for (int i = mObjectsList.Count - 1; i >= 0; --i)
                {
                    if (action(mObjectsList[i]))
                    {
                        return true;
                    }
                }
                return false;
            }

 
            public void ForEachObjectsDoUpdate()
            {
                ZoneObject zo;
                for (int i = mObjectsList.Count - 1; i >= 0; --i)
                {
                    zo = mObjectsList[i];
                    zo.Update();
                    zo.UpdatePos();
                }
            }

            public void ForEachObjectsDoUpdateAI()
            {
                for (int i = mObjectsList.Count - 1; i >= 0; --i)
                {
                    mObjectsList[i].UpdateAI();
                }
            }

            public List<ZoneObject>.Enumerator GetObjectsEnumerator()
            {
                return mObjectsList.GetEnumerator();
            }

            public ICollection<ZoneObject> Objects { get { return mObjects.Values; } }
            public int ObjectsCount { get { return mObjects.Count; } }

            public ICollection<ZoneUnit> Units { get { return mObjects_MirrorUnits.Values; } }
            public int UnitsCount { get { return mObjects_MirrorUnits.Count; } }

            public ICollection<ZoneSpell> Spells { get { return mObjects_MirrorSpells.Values; } }
            public int SpellsCount { get { return mObjects_MirrorSpells.Count; } }

            public ICollection<ZoneItem> Items { get { return mObjects_MirrorItems.Values; } }
            public int ItemsCount { get { return mObjects_MirrorItems.Count; } }


        }
    }
}