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

using CommonAI.Zone.Helper;
using CommonAI.Zone.ZoneEditor.EventTrigger;
using CommonAI.ZoneEditor;
using CommonLang.Property;
using CommonAI.Zone.Attributes;
using CommonAI.ZoneClient;
using CommonLang.Log;
using CommonAI.Zone.EventTrigger;
using CommonAI.Data;

namespace CommonAI.Zone.ZoneEditor
{
    public partial class EditorScene : InstanceZone
    {
        private readonly Logger log = LoggerFactory.GetLogger("EditorScene");
        private SceneData mSceneData;
		private GSCreateAreaData mCreateData;
		private ZoneEventTriggerCollection mZoneEvents;
        private HashMap<int, ZoneRegion> mStartRegions = new HashMap<int, ZoneRegion>();

        public SceneData Data { get { return mSceneData; } }
		//游戏服传过来的数据
		public GSCreateAreaData data { get { return mCreateData; } }

		public EditorScene(
            TemplateManager templates,
            InstanceZoneListener listener,
            SceneData data, GSCreateAreaData createData,
			int spaceDiv, int randomSeed = 1)
            : base(templates, listener, data, createData, spaceDiv, data.MaxUnit, randomSeed)
        {
            this.mSceneData = SyncSceneLevel(data);

            this.mZoneEvents = new ZoneEventTriggerCollection(this);
            base.mSceneType = data.sceneType;
			this.mCreateData = createData;

            // 初始化属性 //
            BindAttributes(data.Attributes, this);

            // 初始化单位 //
            {
                foreach (RegionData rdata in data.Regions)
                {
                    AddEditRegion(rdata);
                }
                foreach (PointData rdata in data.Points)
                {
                    AddEditPoint(rdata);
                }
                foreach (DecorationData rdata in data.Decorations)
                {
                    AddEditDecoration(rdata);
                }
                foreach (AreaData adata in data.Areas)
                {
                    AddEditArea(adata);
                }
                foreach (ItemData rdata in data.Items)
                {
                    AddEditItem(rdata);
                }
                foreach (UnitData rdata in data.Units)
                {
                    AddEditUnit(rdata);
                }
            }

            // 完成初始化单位 //
            {
                foreach (RegionData rdata in data.Regions)
                {
                    BindEditAbility(rdata);
                }
                foreach (PointData rdata in data.Points)
                {
                    BindEditAbility(rdata);
                }
                foreach (DecorationData rdata in data.Decorations)
                {
                    BindEditAbility(rdata);
                }
                foreach (AreaData adata in data.Areas)
                {
                    BindEditAbility(adata);
                }
                foreach (ItemData rdata in data.Items)
                {
                    BindEditAbility(rdata);
                }
                foreach (UnitData rdata in data.Units)
                {
                    BindEditAbility(rdata);
                }
            }

            // 绑定变量 //
            BindValuesAdapter var_api = new BindValuesAdapter(this, mZoneEvents);
            foreach (ZoneVar v in data.EnvironmentVars)
            {
                BindZoneVar(v, var_api);
            }

            // 绑定触发器类型 //
            mZoneEvents.Bind(data.Events);

            mSceneData.Properties.OnInit(this);

            // 绑定脚本适配器 //
            //if (mScriptAdapter != null) mScriptAdapter.BindZone(this);

        }

		public override int GetSceneID()
		{
			return this.mSceneData == null ? -1 : this.mSceneData.ID;
		}

		protected override void Disposing()
        {
            base.Disposing();
            mSceneData = null;
            mZoneEvents.Dispose();
            mZoneEvents = null;
            mStartRegions.Clear();
            //mScriptAdapter = null;
        }
        
        //---------------------------------------------------------------------------------------------------------
        #region InitScene

        // 根据场景DefaultUnitLevel配置每个单独单位等级
        private SceneData SyncSceneLevel(SceneData scene)
        {
            if (scene.DefaultUnitLevel > 0)
            {
                List<FieldAttributeValue> attlevels = new List<FieldAttributeValue>();
                PropertyUtil.CollectFieldAttributeValues(scene, typeof(TemplateLevelAttribute), attlevels);
                foreach (FieldAttributeValue fv in attlevels)
                {
                    int f_value = (int)fv.FieldValue;
                    if (f_value == 0)
                    {
                        log.Info(string.Format("配平单位等级: 场景{0},filed:{1}-{2} -> {3}", scene.TemplateID, fv.FieldOwner, fv.Field.Name, scene.DefaultUnitLevel));
                        fv.Field.SetValue(fv.FieldOwner, scene.DefaultUnitLevel);
                    }
                }
            }
            return scene;
        }

        class StartPointTrigger
        {
            private readonly IGuardUnit guard;
            private readonly InstanceFlag start;
            public StartPointTrigger(IGuardUnit guard, InstanceFlag start)
            {
                this.guard = guard;
                this.start = start;
                (this.guard as InstanceUnit).OnActivated += this.onUnitStartPoint;
            }
            private void onUnitStartPoint(InstanceUnit unit)
            {
                guard.AttackTo(start as ZoneWayPoint);
            }
        }

        private void BindAttributes(string[] attributes, GameEntity unit)
        {
            if (attributes != null)
            {
                foreach (string e in attributes)
                {
                    string[] kv = e.Split('=');
                    if (kv.Length >= 2)
                    {
                        unit.SetAttribute(kv[0].Trim(), kv[1].Trim());
                    }
                }
            }
        }

        virtual protected void AddEditUnit(UnitData data)
        {
            UnitInfo info = Templates.getUnit(data.UnitTemplateID);
            if (info != null)
            {
                AddUnitEvent add;
                InstanceUnit unit = this.AddUnit(info, data.Name, data.Force, data.UnitLevel, data.X, data.Y, data.Direction, out add);
                if (unit != null)
                {
                    BindAttributes(data.Attributes, unit);
                    unit.SetAttribute("UnitData", data);
                    unit.Alias = data.Alias;
                    unit.UnitTag = data.UnitTag;
                    unit.Pause(!data.Enable);
                    add.Sync.Alias = unit.Alias;
                    if (unit is IGuardUnit && !string.IsNullOrEmpty(data.StartPointName))
                    {
                        IGuardUnit guard = unit as IGuardUnit;
                        InstanceFlag start = getFlag(data.StartPointName);
                        if (start != null)
                        {
                            new StartPointTrigger(guard, start);
                        }
                    }
                    // 绑定脚本适配器
                    //if (mScriptAdapter != null) mScriptAdapter.BindUnit(unit);
                }
            }
        }

        virtual protected void AddEditItem(ItemData data)
        {
            ItemTemplate info = Templates.getItem(data.ItemTemplateID);
            if (info != null)
            {
                AddItemEvent add;
                InstanceItem item = this.AddItem(info, data.Name, data.X, data.Y, data.Direction, data.Force, null, out add, null,0);
                if (item != null)
                {
                    item.Alias = data.Alias;
                    add.Sync.Alias = item.Alias;
                    BindAttributes(data.Attributes, item);
                }
            }
        }

        virtual protected void AddEditRegion(RegionData data)
        {
            ZoneRegion flag = new ZoneRegion(this, data);
            if (addFlag(flag))
            {
                BindAttributes(data.Attributes, flag);
                flag.Enable = data.Enable;
                // 绑定脚本适配器
                //if (mScriptAdapter != null) mScriptAdapter.BindRegion(flag);
            }
            else
            {
                throw new Exception("Already Have Flag : " + data.Name);
            }
        }

        virtual protected void AddEditPoint(PointData data)
        {
            ZoneWayPoint flag = new ZoneWayPoint(this, data);
            if (addFlag(flag))
            {
                BindAttributes(data.Attributes, flag);
                flag.Enable = data.Enable;
                // 绑定脚本适配器
                //if (mScriptAdapter != null) mScriptAdapter.BindFlag(flag);
            }
            else
            {
                throw new Exception("Already Have Flag : " + data.Name);
            }
        }

        virtual protected void AddEditDecoration(DecorationData data)
        {
            ZoneDecoration flag = new ZoneDecoration(this, data);
            if (addFlag(flag))
            {
                BindAttributes(data.Attributes, flag);
                flag.Enable = data.Enable;
                // 绑定脚本适配器
                //if (mScriptAdapter != null) mScriptAdapter.BindFlag(flag);
            }
            else
            {
                throw new Exception("Already Have Flag : " + data.Name);
            }
        }

        virtual protected void AddEditArea(AreaData data)
        {
            ZoneArea area = new ZoneArea(this, data);
            if (addFlag(area))
            {
                BindAttributes(data.Attributes, area);
                area.Enable = data.Enable;
                // 绑定脚本适配器
                //if (mScriptAdapter != null) mScriptAdapter.BindFlag(flag);
            }
            else
            {
                throw new Exception("Already Have Flag : " + data.Name);
            }
        }

        virtual protected void BindEditAbility(SceneObjectData data)
        {
            if (data is PointData)
            {
                InitEditPoint(data as PointData);
            }
            else if (data is RegionData)
            {
                InitEditRegion(data as RegionData);
            }
            else if (data is AreaData)
            {
                InitEditArea(data as AreaData);
            }
        }

        virtual protected void InitEditPoint(PointData data)
        {
            ZoneWayPoint flag = getFlag(data.Name) as ZoneWayPoint;
            if (flag != null && data.NextNames != null)
            {
                foreach (string nextname in data.NextNames)
                {
                    ZoneWayPoint nextpoint = getFlag(nextname) as ZoneWayPoint;
                    if (nextpoint != null)
                    {
                        flag.AddNext(nextpoint);
                    }
                    else
                    {
                        log.Error("can not find next point : " + data.Name + " -> " + nextname);
                    }
                }
            }
        }

        virtual protected void InitEditRegion(RegionData rdata)
        {
            ZoneRegion flag = getFlag(rdata.Name) as ZoneRegion;
            if (flag != null && rdata.Abilities != null)
            {
                foreach (AbilityData td in rdata.Abilities)
                {
                    if (td is SpawnUnitAbilityData)
                    {
                        SpawnUnitAbilityData tgd = td as SpawnUnitAbilityData;
                        SpawnUnitTrigger tg = tgd.CreateTrigger(this);
                        tg.bindToRegion(flag);

                        // 绑定脚本适配器
                        //if (mScriptAdapter != null) mScriptAdapter.BindRegionSpawner(flag, tg);
                    }
                    else if (td is SpawnItemAbilityData)
                    {
                        SpawnItemAbilityData tgd = td as SpawnItemAbilityData;
                        SpawnItemTrigger tg = tgd.CreateTrigger(this);
                        tg.bindToRegion(flag);
                        // 绑定脚本适配器
                        //if (mScriptAdapter != null) mScriptAdapter.BindRegionSpawner(flag, tg);
                    }
                    else if (td is PlayerStartAbilityData)
                    {
                        PlayerStartAbilityData tgd = td as PlayerStartAbilityData;
                        mStartRegions.Put(tgd.START_Force, flag);
                    }
                    else if (td is UnitTransportAbilityData)
                    {
                        UnitTransportAbilityData tp = td as UnitTransportAbilityData;
                        TransportUnitTrigger tg = tp.CreateTrigger(this);
                        tg.bindToRegion(flag);
                    }
					else if(td is RegionDamageAbilityData)
					{
						RegionDamageAbilityData trd = td as RegionDamageAbilityData;
						RegionDamageTrigger trigger = trd.CreateTrigger(this);
						trigger.bindToRegion(flag);
					}
                }
            }
        }

        virtual protected void InitEditArea(AreaData data)
        {
            ZoneArea area = getFlag(data.Name) as ZoneArea;
            if (area != null)
            {
                area.BindMapBlock(data);
            }
        }


        #endregion
        //---------------------------------------------------------------------------------------------------------
        public override void Update(int intervalMS, bool slowRefresh)
        {
            base.Update(intervalMS, slowRefresh);
        }
        
        public ZoneRegion GetEditStartRegion(int force)
        {
            return mStartRegions.Get(force);
        }

        [Obsolete]
        public List<KeyValuePair<int, ZoneRegion>> GetEditStartRegions()
        {
            return new List<KeyValuePair<int, ZoneRegion>>(mStartRegions);
        }
        public void GetEditStartRegions(List<KeyValuePair<int, ZoneRegion>> list)
        {
            list.AddRange(mStartRegions);
        }
        public void ForEachEditStartRegions(Action<int, ZoneRegion> action)
        {
            foreach (var kv in mStartRegions)
            {
                action(kv.Key, kv.Value);
            }
        }


        public RegionData TryGetTestRegion(out PlayerStartAbilityData start, Random random = null)
        {
            var list = Data.GetStartRegionsList();
            if (list.Count > 0)
            {
                if (random != null)
                {
                    CUtils.RandomList<RegionData>(random, list);
                }
                var ret = list[0];
                start = ret.GetAbilityOf<PlayerStartAbilityData>();
                return ret;
            }
            start = null;
            return null;
        }
        public bool TryGetTestTemplate(out UnitInfo info, out PlayerStartAbilityData start, Random random = null)
        {
            var list = Data.GetStartRegionsList();
            if (list.Count > 0)
            {
                if (random != null)
                {
                    CUtils.RandomList<RegionData>(random, list);
                }
                foreach (CommonAI.Zone.ZoneEditor.RegionData rg in list)
                {
                    if (TryGetTestTemplate(rg, out info, out start))
                    {
                        return true;
                    }
                }
            }
            info = null;
            start = null;
            return false;
        }
        private bool TryGetTestTemplate(RegionData startRegion, out UnitInfo info, out PlayerStartAbilityData start)
        {
            PlayerStartAbilityData tgd = startRegion.GetAbilityOf<PlayerStartAbilityData>();
            int actorTemplateID = tgd.TestActorTemplateID;
            start = tgd;
            info = Templates.getUnit(actorTemplateID);
            if (info != null)
            {
                info = info.Clone() as UnitInfo;
                info.UType = UnitInfo.UnitType.TYPE_PLAYER;
                return true;
            }
            return false;
        }

    }


}