using CommonAI.Zone.Helper;
using CommonAI.Zone.Instance;
using CommonAI.Zone.Formula;
using CommonAI.Zone.ZoneEditor;
using CommonAI.Zone.ZoneEditor.EventTrigger;
using CommonLang;
using CommonLang.Log;
using CommonLang.Property;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using CommonAI.Data;
using CommonAI.ZoneServer.JSGModule;

namespace CommonAI.Zone.EventTrigger
{
	//---------------------------------------------------------------------------------

	public class EventArguments
	{
		public InstanceUnit TriggingUnit { get; set; }
		public InstanceUnit AttackUnit { get; set; }
		public InstanceFlag TriggingFlag { get; set; }
		public InstanceItem TriggingItem { get; set; }
		public InstanceSpell TriggingSpell { get; set; }
		public ItemTemplate TriggingItemTemplate { get; set; }
		public BuffTemplate TriggingBuffTemplate { get; set; }
		public SkillTemplate TriggingSkillTemplate { get; set; }
		public SpellTemplate TriggingSpellTemplate { get; set; }
		public string TriggingQuestID { get; set; }
		public string TriggingQuestStatusValue { get; set; }
		public string TriggingQuestStatusKey { get; set; }
		//----------------------------------------------------------------
		public ZoneRegion TriggingRegion { get { return TriggingFlag as ZoneRegion; } }
		public ZoneWayPoint TriggingPoint { get { return TriggingFlag as ZoneWayPoint; } }
		public ZoneDecoration TriggingDecoration { get { return TriggingFlag as ZoneDecoration; } }
		public ZoneArea TriggingArea { get { return TriggingFlag as ZoneArea; } }
		//----------------------------------------------------------------
		public InstanceUnit IteratingUnit { get; set; }
		public InstanceItem IteratingItem { get; set; }
		public int IteratingInt32 { get; set; }
		//----------------------------------------------------------------
		public void Set(EventArguments trigger)
		{
			this.TriggingUnit = trigger.TriggingUnit;
			this.TriggingFlag = trigger.TriggingFlag;
			this.TriggingItem = trigger.TriggingItem;
			this.TriggingSpell = trigger.TriggingSpell;

			this.TriggingItemTemplate = trigger.TriggingItemTemplate;
			this.TriggingBuffTemplate = trigger.TriggingBuffTemplate;
			this.TriggingSkillTemplate = trigger.TriggingSkillTemplate;
			this.TriggingSpellTemplate = trigger.TriggingSpellTemplate;

			this.TriggingQuestID = trigger.TriggingQuestID;
			this.TriggingQuestStatusValue = trigger.TriggingQuestStatusValue;
			this.TriggingQuestStatusKey = trigger.TriggingQuestStatusKey;

			this.IteratingUnit = trigger.IteratingUnit;
			this.IteratingItem = trigger.IteratingItem;
			this.IteratingInt32 = trigger.IteratingInt32;
		}
		public EventArguments Clone()
		{
			var ret = new EventArguments();
			ret.Set(this);
			return ret;
		}
	}

	//---------------------------------------------------------------------------------
	/// <summary>
	/// 抽象值数据接口
	/// </summary>
	public abstract class IEditorValueAdapter : IDisposable
	{
		//----------------------------------------------------------------
		protected HashMap<string, object> mAttributes = new HashMap<string, object>();
		protected HashMap<string, object> mLocalVarMap = new HashMap<string, object>();
		//----------------------------------------------------------------
		public abstract TemplateManager Templates { get; }
		/// <summary>
		/// 场景触发器
		/// </summary>
		public abstract InstanceZone ZoneAPI { get; }
		/// <summary>
		/// 单位触发器
		/// </summary>
		public abstract InstanceUnit UnitAPI { get; }
		public abstract IEventTriggerCollection Group { get; }
		//----------------------------------------------------------------
		public abstract bool IsActive { get; set; }

		//----------------------------------------------------------------
		public void SetLocalVar(string key, object value)
		{
			if (!string.IsNullOrEmpty(key))
			{
				mLocalVarMap.Put(key, value);
			}
		}
		public T GetLocalVarAs<T>(string key)
		{
			if (!string.IsNullOrEmpty(key))
			{
				try
				{
					T ret = (T)mLocalVarMap[key];
					return ret;
				}
				catch (Exception er)
				{
					Console.WriteLine("IEditorValueAdapter : " + key + ", catch: " + er);
				}
			}
			return default(T);
		}

		public bool IsAttribute(string key)
		{
			return mAttributes.ContainsKey(key);
		}
		public void SetAttribute(string key, object value)
		{
			mAttributes.Put(key, value);
		}
		public object GetAttribute(string key)
		{
			return mAttributes.Get(key);
		}

		public virtual void Dispose()
		{
			this.mAttributes.Clear();
			this.mAttributes = null;
			this.mLocalVarMap.Clear();
			this.mLocalVarMap = null;
		}
	}


	public interface IEventTriggerCollection : IDisposable
	{
		void Bind<T>(ICollection<T> events) where T : IEventDataNode;
		EventTriggerAdapter GetEditEvent(string name);
		void EventActive(string name, EventArguments args);
		void EventDeactive(string name, EventArguments args);
	}

	//---------------------------------------------------------------------------------
	/// <summary>
	/// 执行事件触发器的数据接口
	/// </summary>
	public abstract class EventTriggerAdapter : IEditorValueAdapter, IDisposable
	{
		public static int EXPECT_TEST_AND_DO_ACTION_TIME_MS = 10;
		private Logger log = LoggerFactory.GetLogger("ET");
		private IEventDataNode mData;
		private IEventTriggerCollection mGroup;
		private List<TimeTaskMS> mTimes = new List<TimeTaskMS>();
		private bool mActive = true;
		//-------------------------------------------------------------------------
		public string Name { get { return mData.EventName; } }
		public override IEventTriggerCollection Group { get { return mGroup; } }
		public override TemplateManager Templates { get { return ZoneAPI.Templates; } }
		//-------------------------------------------------------------------------
		public override bool IsActive
		{
			get { return mActive; }
			set
			{
				if (mActive != value)
				{
					mActive = value;
					if (mActive)
					{
						foreach (TimeTaskMS task in mTimes)
						{
							task.Resume();
						}
					}
					else
					{
						foreach (TimeTaskMS task in mTimes)
						{
							task.Pause();
						}
					}
				}
			}
		}

		//-------------------------------------------------------------------------
		public EventTriggerAdapter(IEventDataNode evt, IEventTriggerCollection group)
		{
			this.mData = evt;
			this.mGroup = group;
			this.mActive = evt.EventIsActive;
		}

		public override void Dispose()
		{
			foreach (var t in mData.EventTriggers) { if (t != null) t.Dispose(); }
			foreach (var t in mData.EventConditions) { if (t != null) t.Dispose(); }
			foreach (var t in mData.EventActions) { if (t != null) t.Dispose(); }
			foreach (TimeTaskMS task in mTimes)
			{
				task.Dispose();
			}
			mTimes.Clear();
			mTimes = null;

            if (mOnDisposed != null)
			{
				mOnDisposed.Invoke(this);
			}
			mOnDisposed = null;
			mOnActionBegin = null;
			mOnActionEnd = null;

			mData = null;
			mGroup = null;
			base.Dispose();
		}

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


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

		internal void Start()
		{
			this.Listen();
			if (!mActive)
			{
				foreach (TimeTaskMS task in mTimes)
				{
					task.Pause();
				}
			}
		}


		private void Listen()
		{
			var args = new EventArguments();
			foreach (AbstractTrigger t in mData.EventTriggers)
			{
				if (t != null)
				{
					t.Listen(this, args);
				}
			}
		}

		/// <summary>
		/// 测试并执行一次触发器
		/// </summary>
		/// <returns></returns>
		public bool TestAndDoAction(EventArguments args)
		{
			if (!IsActive)
			{
				return false;
			}

			int timeUse = 0;
#if JSGProfile
			int startTick = System.Environment.TickCount;
			bool isTrigger = true;
#endif
			Stopwatch stopwatch = Stopwatch.StartNew();
			try
			{
				InitLocalVars(args);
				foreach (AbstractCondition c in mData.EventConditions)
				{
					if (c != null && !c.Test(this, args))
					{
#if JSGProfile
						isTrigger = false;
#endif
						return false;
					}
				}
			}
			finally
			{
				stopwatch.Stop();
				PrintStopwatch(stopwatch, "Test");

#if JSGProfile
				if (!isTrigger)
				{
					timeUse = System.Environment.TickCount - startTick;
					JSGServerProfile.RecordTrigger(this.ZoneAPI, this.Name, timeUse, false);
				}
#endif
			}

			if (mData.EventDelayTimeMS == 0)
			{
				RunInternal(args, timeUse);
			}
			else
			{
				var argst = args.Clone();
				ZoneAPI.AddTimeDelayMS(mData.EventDelayTimeMS, (TimeTaskMS) =>
				{
					RunInternal(argst, timeUse);
				});
			}
			return true;
		}

		/// <summary>
		/// 重置TaskTimer().
		/// </summary>
		public void ResetTimeTask()
		{
			foreach (TimeTaskMS task in mTimes)
			{
				task.Reset();
			}
		}


		private void RunInternal(EventArguments args, int checkTimeUse)
		{
#if JSGProfile
			int startTick = System.Environment.TickCount;
#endif

            //if(this.Name.Equals("事件重置列表1") || this.Name.Equals("玉重置"))
            //{
            //	int i = 0;
            //}
            Stopwatch stopwatch = Stopwatch.StartNew();
			try
			{
				if (mOnActionBegin != null)
				{
					mOnActionBegin.Invoke(this, args);
				}
				foreach (AbstractAction a in mData.EventActions)
				{
					if (a != null)
					{
						a.DoAction(this, args);
					}
				}
				if (mOnActionEnd != null)
				{
					mOnActionEnd.Invoke(this, args);
				}
			}
			finally
			{
				stopwatch.Stop();
				PrintStopwatch(stopwatch, "RunInternal");
#if JSGProfile
				int timeUse = System.Environment.TickCount - startTick + checkTimeUse;
				bool needNotice = JSGServerProfile.RecordTrigger(this.ZoneAPI, this.Name, timeUse, true);

				if (!"单位受到伤害,发送战报".Equals(this.Name) || GlobalData.BattleReportEventLogCnt == 0)
				{
					if (GlobalData.GAME_BS_TEST) //内部测试标记开放了
					{
						log.Warn("--事件: " + this.ZoneAPI.UUID + ", " + this.ZoneAPI.GetSceneID() + ", act:" + this.Name);
					}
					else if(needNotice)
					{
						log.Debug("--事件: " + this.ZoneAPI.UUID + ", " + this.ZoneAPI.GetSceneID() + ", act:" + this.Name);
					}
				}
				
				if ("单位受到伤害,发送战报".Equals(this.Name))
				{
					GlobalData.BattleReportEventLogCnt += 1;
				}
#endif
			}
		}

		public void ProcessActionActive(EventArguments args)
		{
			if (mOnActionActive != null)
			{
				mOnActionActive.Invoke(this, args);
			}
		}

		private void PrintStopwatch(Stopwatch stopwatch, string function)
		{
			if (stopwatch.ElapsedMilliseconds > EXPECT_TEST_AND_DO_ACTION_TIME_MS)
			{
				log.WarnFormat("[{0}] at scene[{1}] -> event[{2}] : usetime {3} > {4}ms, data{5}",
					function,
					(ZoneAPI as EditorScene).Data.ToString() + "-" + ZoneAPI.UUID,
					mData.EventName,
					stopwatch.ElapsedMilliseconds,
					EXPECT_TEST_AND_DO_ACTION_TIME_MS,
					ZoneAPI.GetInfo());
			}
		}

		//-----------------------------------------------------------------------------------------------
		#region _局部变量_

		private void InitLocalVars(EventArguments args)
		{
			mLocalVarMap.Clear();
			foreach (LocalVar klv in mData.EventLocalVars)
			{
				object obj = klv.GetValue(this, args);
				mLocalVarMap.Put(klv.Key, obj);
			}
		}

		#endregion
		public delegate bool TryPickItemHandler(EventArguments args, InstanceUnit unit, InstanceItem item);
		public delegate void TimeTask(EventArguments args);
		//-----------------------------------------------------------------------------------------------
		#region _时间任务_

		internal void listen_TimeDelaySEC(EventArguments args, float TimeSEC)
		{
			args = args.Clone();
			TimeTaskMS task = ZoneAPI.AddTimeDelayMS((int)(TimeSEC * 1000), (time) =>
			{
				TestAndDoAction(args);
			});
			this.mTimes.Add(task);
		}
		internal void listen_TimePeriodicSEC(EventArguments args, float EveryTimeSEC)
		{
			args = args.Clone();
			TimeTaskMS task = ZoneAPI.AddTimePeriodicMS((int)(EveryTimeSEC * 1000), (time) =>
			{
				TestAndDoAction(args);
			});
			if (task != null)
			{
				this.mTimes.Add(task);
			}
		}
		internal void listen_TimeTaskSEC(EventArguments args, float EveryTimeSEC, float DelayTimeSEC, int repeat)
		{
			args = args.Clone();
			TimeTaskMS task = ZoneAPI.AddTimeTask((int)(EveryTimeSEC * 1000), (int)(DelayTimeSEC * 1000), repeat, (time) =>
			{
				TestAndDoAction(args);
			});
			this.mTimes.Add(task);
		}
		internal void listen_TimeTask(EventArguments args, int intervalMS, int delayMS, int repeat, TimeTask handler)
		{
			args = args.Clone();
			TimeTaskMS task = ZoneAPI.AddTimeTask(intervalMS, delayMS, repeat, (t) =>
			{
				handler(args);
			});
			this.mTimes.Add(task);
		}

		#endregion

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


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

		//-----------------------------------------------------------------------------------------------
		#region __监听_场景事件__

		public void listen_SceneInit(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.InitHandler handler = new InstanceZone.InitHandler((z) =>
			{
				TestAndDoAction(args);
			});
			zone.OnInit += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnInit -= handler;
			};
		}

		public void listen_TryPickItem(EventArguments args, InstanceZone zone, TryPickItemHandler action)
		{
			args = args.Clone();
			InstanceZone.TryPickItemHandler handler = new InstanceZone.TryPickItemHandler((z, u, i) =>
			{
				args.TriggingUnit = u;
				args.TriggingItem = i;
				args.TriggingItemTemplate = i.Info;
				TestAndDoAction(args);
				return action.Invoke(args, u, i);
			});
			zone.OnTryPickItem += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnTryPickItem -= handler;
			};
		}

        private List<InstanceUnit> _tmpList = new List<InstanceUnit>();
        public void listen_RecvMessageFromGS(EventArguments args, InstanceZone zone, string msg, string triggerUnits)
		{
			args = args.Clone();
			InstanceZone.RecvMessageR2BHandler handler = new InstanceZone.RecvMessageR2BHandler((z, m) =>
			{
				if (m.Message == msg)
				{
                    if (!string.IsNullOrEmpty(triggerUnits) || !string.IsNullOrEmpty(m.TriggerUnits))
					{
                        _tmpList.Clear();
						if (!string.IsNullOrEmpty(m.TriggerUnits))
						{
							//游戏发送过来的,要触发的单位列表:id1,id2...
							var sps = m.TriggerUnits.Split(',');
							foreach (var s in sps)
							{
								try
								{
									var id = System.Convert.ToUInt32(s);
									var unit = zone.getUnit(id);
									if (unit != null)
									{
										_tmpList.Add(unit);
									}
								}
								catch { }
							}
						}

                        if (!string.IsNullOrEmpty(triggerUnits))
                        {
                            //编辑器配置的,要触发的单位列表:类型1:数量1:阵营1;类型2:数量2:阵营2...
                            var sps = triggerUnits.Split(';');
							foreach (var s in sps)
							{
								var info = s.Split(':');
								if (info.Length != 3) continue;
								try
                                {
									int type = int.Parse(info[0]);
                                    int cnt = int.Parse(info[1]);
									int force = int.Parse(info[2]);
									if (cnt <= _tmpList.Count) break;

									switch(type)
									{
										case 1: //死亡单位
                                            zone.getDeadUnit(cnt - _tmpList.Count, force, ref _tmpList);
											break;
                                        default:
                                            log.Error($"配置的触发单位类型不能识别: {triggerUnits}");
                                            break;
									}
                                }
                                catch { }
							}
                        }

                        if (_tmpList.Count > 0)
                        {
                            foreach (var unit in _tmpList)
                            {
                                args.TriggingUnit = unit;
                                TestAndDoAction(args);
                            }
                            _tmpList.Clear();
                        }
                    }
                    else
					{
                        TestAndDoAction(args);
                    }
				}
			});
			zone.OnRecvMessageFromGS += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnRecvMessageFromGS -= handler;
			};
		}

		public void listen_ItemAdded(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.ItemAddedHandler handler = new InstanceZone.ItemAddedHandler((z, i, u) =>
			{
				args.TriggingItem = i;
				args.TriggingItemTemplate = i.Info;
				TestAndDoAction(args);
			});
			zone.OnItemAdded += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnItemAdded -= handler;
			};
		}

		#endregion
		//-----------------------------------------------------------------------------------------------
		#region __监听_FLAG事件__

		public void listen_FlagOpened(EventArguments args, InstanceFlag flag)
		{
			args = args.Clone();
			InstanceFlag.FlagEnabledHandler handler = new InstanceFlag.FlagEnabledHandler((f) =>
			{
				args.TriggingFlag = f;
				TestAndDoAction(args);
			});
			flag.OnFlagEnabled += handler;
			this.OnDisposed += (api) =>
			{
				flag.OnFlagEnabled -= handler;
			};
		}

		public void listen_FlagClosed(EventArguments args, InstanceFlag flag)
		{
			args = args.Clone();
			InstanceFlag.FlagDisabledHandler handler = new InstanceFlag.FlagDisabledHandler((f) =>
			{
				args.TriggingFlag = flag;
				TestAndDoAction(args);
			});
			flag.OnFlagDisabled += handler;
			this.OnDisposed += (api) =>
			{
				flag.OnFlagDisabled -= handler;
			};
		}

		public void listen_RegionSpawnOver(EventArguments args, ZoneRegion region)
		{
			args = args.Clone();
			ZoneRegion.SpawnOverHandler handler = new ZoneRegion.SpawnOverHandler((rg) =>
			{
				args.TriggingFlag = rg;
				TestAndDoAction(args);
			});
			region.OnSpawnOver += handler;
			this.OnDisposed += (api) =>
			{
				region.OnSpawnOver -= handler;
			};
		}
		public void listen_RegionEntered(EventArguments args, ZoneRegion region)
		{
			args = args.Clone();
			ZoneRegion.UnitEnterHandler handler = new ZoneRegion.UnitEnterHandler((rg, u) =>
			{
				args.TriggingFlag = rg;
				args.TriggingUnit = u as InstanceUnit;
				TestAndDoAction(args);
			});
			region.OnUnitEnter += handler;
			this.OnDisposed += (api) =>
			{
				region.OnUnitEnter -= handler;
			};
		}
		public void listen_RegionLeft(EventArguments args, ZoneRegion region)
		{
			args = args.Clone();
			ZoneRegion.UnitLeaveHandler handler = new ZoneRegion.UnitLeaveHandler((rg, u) =>
			{
				args.TriggingFlag = rg;
				args.TriggingUnit = u as InstanceUnit;
				TestAndDoAction(args);
			});
			region.OnUnitLeave += handler;
			this.OnDisposed += (api) =>
			{
				region.OnUnitLeave -= handler;
			};
		}

		public void listen_AreaEntered(EventArguments args, ZoneArea area)
		{
			args = args.Clone();
			ZoneArea.UnitEnterHandler handler = new ZoneArea.UnitEnterHandler((rg, u) =>
			{
				args.TriggingFlag = rg;
				args.TriggingUnit = u as InstanceUnit;
				TestAndDoAction(args);
			});
			area.OnUnitEnter += handler;
			this.OnDisposed += (api) =>
			{
				area.OnUnitEnter -= handler;
			};
		}
		public void listen_AreaLeft(EventArguments args, ZoneArea area)
		{
			args = args.Clone();
			ZoneArea.UnitLeaveHandler handler = new ZoneArea.UnitLeaveHandler((rg, u) =>
			{
				args.TriggingFlag = rg;
				args.TriggingUnit = u as InstanceUnit;
				TestAndDoAction(args);
			});
			area.OnUnitLeave += handler;
			this.OnDisposed += (api) =>
			{
				area.OnUnitLeave -= handler;
			};
		}

		#endregion
		//-----------------------------------------------------------------------------------------------
		#region __监听_单位事件__

		public void listen_GenericUnitAdded(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.UnitAddedHandler handler = new InstanceZone.UnitAddedHandler((z, u) =>
			{
				args.TriggingUnit = u;
				TestAndDoAction(args);
			});
			zone.OnUnitAdded += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitAdded -= handler;
			};
		}
		public void listen_GenericUnitRemoved(EventArguments args, InstanceZone zone)
		{
			InstanceZone.UnitRemovedHandler handler = new InstanceZone.UnitRemovedHandler((z, u) =>
			{
				args.TriggingUnit = u;
				TestAndDoAction(args);
			});
			zone.OnUnitRemoved += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitRemoved -= handler;
			};
		}
		public void listen_GenericUnitActivated(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.UnitActivatedHandler handler = new InstanceZone.UnitActivatedHandler((z, u) =>
			{
				args.TriggingUnit = u;
				TestAndDoAction(args);
			});
			zone.OnUnitActivated += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitActivated -= handler;
			};
		}
		public void listen_GenericUnitDamaged(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.UnitDamageHandler handler = new InstanceZone.UnitDamageHandler((z, u, attacker, reduceHP, attack) =>
			{
				args.TriggingUnit = u;
				args.AttackUnit = attacker;
				args.TriggingSpell = attack.FromSpellUnit;
				args.TriggingSkillTemplate = attack.FromSkill;
				args.TriggingSpellTemplate = attack.FromSpell;
				args.TriggingBuffTemplate = attack.FromBuff;
				TestAndDoAction(args);
			});
			zone.OnUnitDamage += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitDamage -= handler;
			};
		}
		public void listen_GenericUnitDead(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.UnitDeadHandler handler = new InstanceZone.UnitDeadHandler((z, u, attacker) =>
			{
				args.TriggingUnit = u;
				TestAndDoAction(args);
			});
			zone.OnUnitDead += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitDead -= handler;
			};
		}
		public void listen_GenericUnitRebirth(EventArguments args, InstanceZone zone)
		{
			InstanceZone.UnitRebirthHandler handler = new InstanceZone.UnitRebirthHandler((z, u) =>
			{
				args.TriggingUnit = u;
				TestAndDoAction(args);
			});
			zone.OnUnitRebirth += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitRebirth -= handler;
			};
		}
		public void listen_GenericUnitGotInstanceItem(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.UnitGotInstanceItemHandler handler = new InstanceZone.UnitGotInstanceItemHandler((z, u, i) =>
			{
				args.TriggingUnit = u;
				args.TriggingItem = i;
				args.TriggingItemTemplate = i.Info;
				TestAndDoAction(args);
			});
			zone.OnUnitGotInstanceItem += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitGotInstanceItem -= handler;
			};
		}
		public void listen_GenericUnitGotInventoryItem(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.UnitGotInventoryItemHandler handler = new InstanceZone.UnitGotInventoryItemHandler((z, u, i, c) =>
			{
				args.TriggingUnit = u;
				args.TriggingItemTemplate = i;
				TestAndDoAction(args);
			});
			zone.OnUnitGotInventoryItem += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitGotInventoryItem -= handler;
			};
		}
		public void listen_GenericUnitLostInventoryItem(EventArguments args, InstanceZone zone)
		{
			InstanceZone.UnitLostInventoryItemHandler handler = new InstanceZone.UnitLostInventoryItemHandler((z, u, i, c) =>
			{
				args.TriggingUnit = u;
				args.TriggingItemTemplate = i;
				TestAndDoAction(args);
			});
			zone.OnUnitLostInventoryItem += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitLostInventoryItem -= handler;
			};
		}
		public void listen_GenericUnitUseItem(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.UnitUseItemHandler handler = new InstanceZone.UnitUseItemHandler((z, u, i, c) =>
			{
				args.TriggingUnit = u;
				args.TriggingItemTemplate = i;
				TestAndDoAction(args);
			});
			zone.OnUnitUseItem += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitUseItem -= handler;
			};
		}
		public void listen_GenericUnitGotBuff(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.UnitGotBuffHandler handler = new InstanceZone.UnitGotBuffHandler((z, u, b) =>
			{
				args.TriggingUnit = u;
				args.TriggingBuffTemplate = b.Data;
				TestAndDoAction(args);
			});
			zone.OnUnitGotBuff += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitGotBuff -= handler;
			};
		}
		public void listen_GenericUnitLostBuff(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.UnitLostBuffHandler handler = new InstanceZone.UnitLostBuffHandler((z, u, b) =>
			{
				args.TriggingUnit = u;
				args.TriggingBuffTemplate = b.Data;
				TestAndDoAction(args);
			});
			zone.OnUnitLostBuff += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitLostBuff -= handler;
			};
		}
		public void listen_GenericUnitQuestAccepted(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.QuestAcceptedHandler handler = new InstanceZone.QuestAcceptedHandler((u, q) =>
			{
				args.TriggingUnit = u;
				args.TriggingQuestID = q;
				TestAndDoAction(args);
			});
			zone.OnQuestAccepted += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnQuestAccepted -= handler;
			};
		}
		public void listen_GenericUnitQuestCompleted(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.QuestCommittedHandler handler = new InstanceZone.QuestCommittedHandler((u, q) =>
			{
				args.TriggingUnit = u;
				args.TriggingQuestID = q;
				TestAndDoAction(args);
			});
			zone.OnQuestCommitted += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnQuestCommitted -= handler;
			};
		}
		public void listen_GenericUnitQuestDropped(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.QuestDroppedHandler handler = new InstanceZone.QuestDroppedHandler((u, q) =>
			{
				args.TriggingUnit = u;
				args.TriggingQuestID = q;
				TestAndDoAction(args);
			});
			zone.OnQuestDropped += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnQuestDropped -= handler;
			};
		}
		public void listen_GenericUnitQuestStatusChanged(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.QuestStatusChangedHandler handler = new InstanceZone.QuestStatusChangedHandler((u, q, k, v) =>
			{
				args.TriggingUnit = u;
				args.TriggingQuestID = q;
				TestAndDoAction(args);
			});
			zone.OnQuestStatusChanged += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnQuestStatusChanged -= handler;
			};
		}

		public void listen_GenericUnitPickUnit(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.UnitPickUnitHandler handler = new InstanceZone.UnitPickUnitHandler((z, u, p) =>
			{
				args.TriggingUnit = u;
				TestAndDoAction(args);
			});
			zone.OnUnitPickUnit += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitPickUnit -= handler;
			};
		}

		public void listen_GenericUnitLaunchSkill(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.UnitLaunchSkillHandler handler = new InstanceZone.UnitLaunchSkillHandler((z, u, s) =>
			{
				args.TriggingUnit = u;
				args.TriggingSkillTemplate = s.Data;
				TestAndDoAction(args);
			});
			zone.OnUnitLaunchSkill += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitLaunchSkill -= handler;
			};
		}

		public void listen_GenericPlayerReady(EventArguments args, InstanceZone zone)
		{
			args = args.Clone();
			InstanceZone.PlayerReadyHandler handler = new InstanceZone.PlayerReadyHandler((p) =>
			{
				args.TriggingUnit = p;
				TestAndDoAction(args);
			});
			zone.OnPlayerReady += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnPlayerReady -= handler;
			};
		}


		//////////////////////////////////////////////////////////////////////////////////////


		public void listen_PointUnitDead(EventArguments args, InstanceZone zone, string unitName, int UnitTemplateID = 0)
		{
			args = args.Clone();
			InstanceZone.UnitDeadHandler handler = new InstanceZone.UnitDeadHandler((z, u, attacker) =>
			{
				if (UnitTemplateID > 0)
				{
					if (u.Info.ID == UnitTemplateID)
					{
						args.TriggingUnit = u;
						TestAndDoAction(args);
					}
				}
				else
				{
					if (u.Name.Equals(unitName))
					{
						args.TriggingUnit = u;
						TestAndDoAction(args);
					}
				}

			});

			zone.OnUnitDead += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitDead -= handler;
			};
		}


		public void listen_PointUnitOutBattle(EventArguments args, InstanceZone zone, int unitID)
		{
			args = args.Clone();
			InstanceZone.UnitOutBattleHandler handler = new InstanceZone.UnitOutBattleHandler((z, u) =>
			{
				if (u.Info.ID == unitID)
				{
					args.TriggingUnit = u;
					TestAndDoAction(args);
				}
			});
			zone.OnUnitOutBattle += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitOutBattle -= handler;
			};
		}


		//////////////////////////////////////////////////////////////////////////////////////

		public void listen_SpecifyUnitActivated(EventArguments args, InstanceUnit unit)
		{
			args = args.Clone();
			InstanceUnit.ActivatedHandler handler = new InstanceUnit.ActivatedHandler((u) =>
			{
				args.TriggingUnit = u;
				TestAndDoAction(args);
			});
			unit.OnActivated += handler;
			this.OnDisposed += (api) =>
			{
				unit.OnActivated -= handler;
			};
		}
		public void listen_SpecifyUnitAttack(EventArguments args, InstanceUnit unit)
		{
			args = args.Clone();
			InstanceUnit.AttackHandler handler = new InstanceUnit.AttackHandler((u, t, hp, s) =>
			{
				args.TriggingUnit = u;
				args.TriggingSpell = s.FromSpellUnit;
				args.TriggingSkillTemplate = s.FromSkill;
				args.TriggingSpellTemplate = s.FromSpell;
				args.TriggingBuffTemplate = s.FromBuff;
				TestAndDoAction(args);
			});
			unit.OnAttack += handler;
			this.OnDisposed += (api) =>
			{
				unit.OnAttack -= handler;
			};
		}

		public void listen_PointUnitIDDamaged(EventArguments args, InstanceZone zone, int templateID)
		{
			args = args.Clone();
			InstanceZone.UnitDamageHandler handler = new InstanceZone.UnitDamageHandler((z, u, attacker, reduceHP, attack) =>
			{
				if (u.Info.ID == templateID)
				{
					args.TriggingUnit = u;
					args.AttackUnit = attacker;
					args.TriggingSpell = attack.FromSpellUnit;
					args.TriggingSkillTemplate = attack.FromSkill;
					args.TriggingSpellTemplate = attack.FromSpell;
					args.TriggingBuffTemplate = attack.FromBuff;
					TestAndDoAction(args);
				}
			});
			zone.OnUnitDamage += handler;
			this.OnDisposed += (api) =>
			{
				zone.OnUnitDamage -= handler;
			};
		}

		public void listen_SpecifyUnitDamaged(EventArguments args, InstanceUnit unit)
		{
			args = args.Clone();
			InstanceUnit.DamageHandler handler = new InstanceUnit.DamageHandler((u, a, hp, s) =>
			{
				args.TriggingUnit = u;
				args.TriggingSpell = s.FromSpellUnit;
				args.TriggingSkillTemplate = s.FromSkill;
				args.TriggingSpellTemplate = s.FromSpell;
				args.TriggingBuffTemplate = s.FromBuff;
				TestAndDoAction(args);
			});
			unit.OnDamage += handler;
			this.OnDisposed += (api) =>
			{
				unit.OnDamage -= handler;
			};
		}
		public void listen_SpecifyUnitDead(EventArguments args, InstanceUnit unit)
		{
			args = args.Clone();
			InstanceUnit.DeadHandler handler = new InstanceUnit.DeadHandler((u, a) =>
			{
				args.TriggingUnit = u;
				TestAndDoAction(args);
			});
			unit.OnDead += handler;
			this.OnDisposed += (api) =>
			{
				unit.OnDead -= handler;
			};
		}
		public void listen_SpecifyUnitRebirth(EventArguments args, InstanceUnit unit)
		{
			InstanceUnit.RebirthHandler handler = new InstanceUnit.RebirthHandler((u) =>
			{
				args.TriggingUnit = u;
				TestAndDoAction(args);
			});
			unit.OnRebirth += handler;
			this.OnDisposed += (api) =>
			{
				unit.OnRebirth -= handler;
			};
		}
		public void listen_SpecifyUnitGotInstanceItem(EventArguments args, InstanceUnit unit)
		{
			args = args.Clone();
			InstanceUnit.GotInstanceItemHandler handler = new InstanceUnit.GotInstanceItemHandler((u, i) =>
			{
				args.TriggingUnit = u;
				args.TriggingItem = i;
				args.TriggingItemTemplate = i.Info;
				TestAndDoAction(args);
			});
			unit.OnGotInstanceItem += handler;
			this.OnDisposed += (api) =>
			{
				unit.OnGotInstanceItem -= handler;
			};
		}
		public void listen_SpecifyUnitGotInventoryItem(EventArguments args, InstanceUnit unit)
		{
			args = args.Clone();
			InstanceUnit.GotInventoryItemHandler handler = new InstanceUnit.GotInventoryItemHandler((u, i) =>
			{
				args.TriggingUnit = u;
				args.TriggingItemTemplate = i;
				TestAndDoAction(args);
			});
			unit.OnGotInventoryItem += handler;
			this.OnDisposed += (api) =>
			{
				unit.OnGotInventoryItem -= handler;
			};
		}
		public void listen_SpecifyUnitLostInventoryItem(EventArguments args, InstanceUnit unit)
		{
			InstanceUnit.LostInventoryItemHandler handler = new InstanceUnit.LostInventoryItemHandler((u, i) =>
			{
				args.TriggingUnit = u;
				args.TriggingItemTemplate = i;
				TestAndDoAction(args);
			});
			unit.OnLostInventoryItem += handler;
			this.OnDisposed += (api) =>
			{
				unit.OnLostInventoryItem -= handler;
			};
		}
		public void listen_SpecifyUnitUseItem(EventArguments args, InstanceUnit unit)
		{
			args = args.Clone();
			InstanceUnit.UseItemHandler handler = new InstanceUnit.UseItemHandler((u, i, c) =>
			{
				args.TriggingUnit = u;
				args.TriggingItemTemplate = i;
				TestAndDoAction(args);
			});
			unit.OnUseItem += handler;
			this.OnDisposed += (api) =>
			{
				unit.OnUseItem -= handler;
			};
		}
		public void listen_SpecifyUnitGotBuff(EventArguments args, InstanceUnit unit)
		{
			args = args.Clone();
			InstanceUnit.GotBuffHandler handler = new InstanceUnit.GotBuffHandler((u, b) =>
			{
				args.TriggingUnit = u;
				args.TriggingBuffTemplate = b.Data;
				TestAndDoAction(args);
			});
			unit.OnGotBuff += handler;
			this.OnDisposed += (api) =>
			{
				unit.OnGotBuff -= handler;
			};
		}
		public void listen_SpecifyUnitLostBuff(EventArguments args, InstanceUnit unit)
		{
			args = args.Clone();
			InstanceUnit.LostBuffHandler handler = new InstanceUnit.LostBuffHandler((u, b) =>
			{
				args.TriggingUnit = u;
				args.TriggingBuffTemplate = b.Data;
				TestAndDoAction(args);
			});
			unit.OnLostBuff += handler;
			this.OnDisposed += (api) =>
			{
				unit.OnLostBuff -= handler;
			};
		}
		public void listen_SpecifyUnitLaunchSkill(EventArguments args, InstanceUnit unit)
		{
			args = args.Clone();
			InstanceUnit.OnLaunchSkillHandler handler = new InstanceUnit.OnLaunchSkillHandler((u, s) =>
			{
				args.TriggingUnit = u;
				args.TriggingSkillTemplate = s.Data;
				TestAndDoAction(args);
			});
			unit.OnLaunchSkill += handler;
			this.OnDisposed += (api) =>
			{
				unit.OnLaunchSkill -= handler;
			};
		}

		#endregion
		//-----------------------------------------------------------------------------------------------
		#region __监听_触发器事件__

		public void listen_EventActionBegin(EventArguments args, EventTriggerAdapter adapter)
		{
			args = args.Clone();
			OnActionBeginHandler handler = new OnActionBeginHandler((a, g) =>
			{
				TestAndDoAction(g);
			});
			adapter.OnActionBegin += handler;
			this.OnDisposed += (api) =>
			{
				adapter.OnActionBegin -= handler;
			};
		}
		public void listen_EventActionEnd(EventArguments args, EventTriggerAdapter adapter)
		{
			args = args.Clone();
			OnActionEndHandler handler = new OnActionEndHandler((a, g) =>
			{
				TestAndDoAction(g);
			});
			adapter.OnActionEnd += handler;
			this.OnDisposed += (api) =>
			{
				adapter.OnActionEnd -= handler;
			};
		}

		public void listen_EventActionActive(EventArguments args, EventTriggerAdapter adapter)
		{
			args = args.Clone();
			OnActionActiveHandler handler = new OnActionActiveHandler((a, g) =>
			{
				TestAndDoAction(g);
			});
			adapter.mOnActionActive += handler;
			this.OnDisposed += (api) =>
			{
				adapter.mOnActionActive -= handler;
			};
		}

		#endregion

		//-----------------------------------------------------------------------------------------------
		#region Delegates

		public delegate void OnActionBeginHandler(EventTriggerAdapter trigger, EventArguments args);
		public delegate void OnActionEndHandler(EventTriggerAdapter trigger, EventArguments args);
		public delegate void OnActionActiveHandler(EventTriggerAdapter trigger, EventArguments args);
		public delegate void OnDisposedHandler(EventTriggerAdapter trigger);

		private OnActionBeginHandler mOnActionBegin;
		private OnActionEndHandler mOnActionEnd;
		private OnActionActiveHandler mOnActionActive;
		private OnDisposedHandler mOnDisposed;

		public event OnActionBeginHandler OnActionBegin { add { mOnActionBegin += value; } remove { mOnActionBegin -= value; } }
		public event OnActionEndHandler OnActionEnd { add { mOnActionEnd += value; } remove { mOnActionEnd -= value; } }
		public event OnActionActiveHandler OnActionActive { add { mOnActionActive += value; } remove { mOnActionActive -= value; } }

		public event OnDisposedHandler OnDisposed { add { mOnDisposed += value; } remove { mOnDisposed -= value; } }

		#endregion
		//-----------------------------------------------------------------------------------------------
	}

	//---------------------------------------------------------------------------------
	/// <summary>
	/// 绑定环境变量用的数据接口
	/// </summary>
	public class BindValuesAdapter : IEditorValueAdapter
	{
		private IEventTriggerCollection mGroup;
		private InstanceZone mZoneAPI;
		private InstanceUnit mUnitAPI;

		public BindValuesAdapter(EditorScene scene, IEventTriggerCollection group)
		{
			this.IsActive = true;
			this.mGroup = group;
			this.mZoneAPI = scene;
			this.mUnitAPI = null;
		}
		public override void Dispose()
		{
			this.mGroup = null;
			this.mZoneAPI = null;
			this.mUnitAPI = null;
			base.Dispose();
		}

		public override bool IsActive { get; set; }

		public override TemplateManager Templates { get { return mZoneAPI.Templates; } }
		public override IEventTriggerCollection Group { get { return mGroup; } }
		public override InstanceZone ZoneAPI { get { return mZoneAPI; } }
		public override InstanceUnit UnitAPI { get { return mUnitAPI; } }
	}

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

	public class ZoneEventTriggerCollection : IEventTriggerCollection
	{
		private EditorScene mScene;

		private HashMap<string, EventTriggerAdapter> mEvents = new HashMap<string, EventTriggerAdapter>();

		public ZoneEventTriggerCollection(EditorScene scene)
		{
			this.mScene = scene;
		}
		public void Dispose()
		{
			foreach (EventTriggerAdapter trigger in mEvents.Values)
			{
				trigger.Dispose();
			}
			mEvents.Clear();
			mEvents = null;
			mScene = null;
		}

		public void Bind<T>(ICollection<T> events) where T : IEventDataNode
		{
			foreach (IEventDataNode e in events)
			{
				ZoneEventTrigger trigger = new ZoneEventTrigger(mScene, e, this);
				mEvents.Put(e.EventName, trigger);
			}
			foreach (EventTriggerAdapter trigger in mEvents.Values)
			{
				trigger.Start();
			}
		}

		public EventTriggerAdapter GetEditEvent(string name)
		{
			if (name == null) { return null; }
			return mEvents.Get(name);
		}
		public void EventActive(string name, EventArguments args)
		{
			EventTriggerAdapter apt = this.GetEditEvent(name);
			if (apt != null)
			{
				apt.IsActive = true;
				apt.ProcessActionActive(args);
			}
		}
		public void EventDeactive(string name, EventArguments args)
		{
			EventTriggerAdapter apt = this.GetEditEvent(name);
			if (apt != null)
			{
				apt.IsActive = false;
			}

		}

		public class ZoneEventTrigger : EventTriggerAdapter
		{
			private readonly EditorScene mScene;
			public override InstanceZone ZoneAPI { get { return mScene; } }
			public override InstanceUnit UnitAPI { get { return null; } }
			public ZoneEventTrigger(EditorScene scene, IEventDataNode evt, ZoneEventTriggerCollection group)
				: base(evt, group)
			{
				mScene = scene;
			}
		}
	}

	public class UnitEventTriggerCollection : IEventTriggerCollection
	{
		private InstanceUnit mUnit;

		private HashMap<string, EventTriggerAdapter> mEvents = new HashMap<string, EventTriggerAdapter>();

		public UnitEventTriggerCollection(InstanceUnit unit)
		{
			this.mUnit = unit;
		}
		public void Dispose()
		{
			foreach (EventTriggerAdapter trigger in mEvents.Values)
			{
				trigger.Dispose();
			}
			mEvents.Clear();
			mEvents = null;
			mUnit = null;
		}

		public void Bind<T>(ICollection<T> events) where T : IEventDataNode
		{
			foreach (IEventDataNode e in events)
			{
				UnitEventTrigger trigger = new UnitEventTrigger(mUnit, e, this);
				mEvents.Put(e.EventName, trigger);
			}
			foreach (EventTriggerAdapter trigger in mEvents.Values)
			{
				trigger.Start();
			}
		}
		public EventTriggerAdapter GetEditEvent(string name)
		{
			if (name == null) { return null; }
			return mEvents.Get(name);
		}
		public void EventActive(string name, EventArguments args)
		{
			EventTriggerAdapter apt = this.GetEditEvent(name);
			if (apt != null)
			{
				apt.IsActive = true;
			}
		}
		public void EventDeactive(string name, EventArguments args)
		{
			EventTriggerAdapter apt = this.GetEditEvent(name);
			if (apt != null)
			{
				apt.IsActive = false;
			}
		}
		public class UnitEventTrigger : EventTriggerAdapter
		{
			private readonly InstanceZone mScene;
			private readonly InstanceUnit mUnit;
			public override InstanceZone ZoneAPI { get { return mScene; } }
			public override InstanceUnit UnitAPI { get { return mUnit; } }
			public UnitEventTrigger(InstanceUnit unit, IEventDataNode evt, UnitEventTriggerCollection group)
				: base(evt, group)
			{
				mUnit = unit;
				mScene = unit.Parent;
			}
		}
	}

	//---------------------------------------------------------------------------------
}