using CommonAI.RTS;
using CommonAI.Zone;
using CommonAI.Zone.Helper;
using CommonAI.Zone.Instance;
using CommonAI.Zone.ZoneEditor;
using CommonAI.ZoneClient;
using CommonLang;
using CommonLang.ByteOrder;
using CommonLang.IO;
using CommonLang.IO.Attribute;
using CommonLang.Log;
using CommonLang.Property;
using CommonLang.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CommonAI.ZoneServer;
using System.Threading;
using CommonLang.Concurrent;
using System.Diagnostics;
using CommonAIServer.Node.Interface;
using CommonLang.Vector;
using CommonAI.Data;

namespace CommonAIServer.Node
{
    public class BaseZoneNode : InstanceZoneListener
    {
        protected readonly static Logger log = LoggerFactory.GetLogger("ZoneNode");
        protected readonly object locker = new object();

        private readonly EditorTemplates mDataRoot;
        private readonly TemplateManager mTemplates;
        private readonly ZoneNodeConfig mConfig;
        private readonly int mUpdateInterval;
        private readonly int mUpdateIntervalLimit;
        //private readonly TimeInterval<ServerStatusB2C> mSyncServerStatus;

        protected SceneData mSceneData;
        private EditorScene mZone;
        private System.Threading.Timer mTimer;

        private long mLastUpdateTime;
		private long mProfileItemsTime;
        private bool mStarted = false;
        private bool mShutDown = false;
        private bool mIsDisposed = false;
        private bool mIsRunning = false;

		//更新次数,用于非重要数据慢刷新逻辑
		private int mTotalUpdateTimes = 0;

		//------------------------------------------------------------------------------------------------------------
		// 当前帧发送的消息队列 //
		private Queue<Event> mPostZoneEvents = new Queue<Event>();
        // 内部主线程命令 //
        private SyncMessageQueue<Task> mTasks = new SyncMessageQueue<Task>();

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

        public BaseZoneNode(EditorTemplates data_root, ZoneNodeConfig cfg)
        {
            this.mDataRoot = data_root;
            this.mTemplates = data_root.Templates;
            this.mConfig = cfg.Clone();
            this.mUpdateInterval = mConfig.GAME_UPDATE_INTERVAL_MS;
            this.mUpdateIntervalLimit = mUpdateInterval * 2;
            //this.mSyncServerStatus = new TimeInterval<ServerStatusB2C>(new ServerStatusB2C(), cfg.TEST_POST_SERVER_INFO_INTERVAL_MS);
            this.EnableTimer = true;
        }

        public string Name { get { return (mSceneData != null) ? mSceneData.ToString() : "null"; } }
        public SceneData SceneData { get { return mSceneData; } }
        public EditorTemplates DataRoot { get { return mDataRoot; } }
        public TemplateManager Templates { get { return mTemplates; } }
        public int SceneID { get { return mSceneData.ID; } }
        public EditorScene Zone { get { return mZone; } }
        public bool IsStarted { get { return mStarted; } }
        public bool IsRunning { get { return mIsRunning; } }
        public bool IsDisposed { get { lock (this) { return mIsDisposed; } } }

        public bool EnableTimer { get; set; }

        protected ZoneNodeConfig Config { get { return mConfig; } }
        protected int UpdateInterval { get { return mUpdateInterval; } }
        protected IEnumerable<Event> PostZoneEvents { get { return mPostZoneEvents; } }
        //------------------------------------------------------------------------------------------------------------

        public override string ToString()
        {
            if (mSceneData != null)
            {
                return mSceneData.Name + "(" + mSceneData.ID + ")";
            }
            return "Unable to load scene";
        }

		public virtual bool CheckDropItem()
		{
			return false;
		}

		/// <summary>
		/// 获得指定名称的路点坐标
		/// </summary>
		/// <param name="name"></param>
		/// <returns></returns>
		public PointData GetScenePointData(string name)
        {
            foreach (PointData p in mSceneData.Points)
            {
                if (p.Name == name)
                {
                    return p;
                }
            }
            return null;
        }
        //------------------------------------------------------------------------------------------------------------
        /// <summary>
        /// 房间初始化
        /// </summary>
        public void Start(SceneData data, GSCreateAreaData gsData, string bindGameSrvId)
        {
            lock (locker)
            {
                if (mStarted) { return; }
                this.mStarted = true;
                // 解析游戏服创建房间信息 //
                this.mSceneData = data;
                {
                    // 构造战斗场景 //
                    this.mZone = TemplateManager.Factory.CreateEditorScene(this.Templates, this, mSceneData, gsData, bindGameSrvId);
                    // 非全屏同步,每个Client负责维护自己需要的队列 //
                    this.mZone.SyncPos = false;
                    this.mZone.IsSyncZ = false;
                    // 半同步,场景不能大于255 //
                    this.mZone.IsHalfSync = true;
                }
                // 创建游戏主循环Timer //
                this.mLastUpdateTime = CUtils.CurrentTimeMS;
				this.mProfileItemsTime = this.mLastUpdateTime + 60000;

				this.mIsRunning = true;
                this.timer_start();
                this.QueueTask(() =>
                {
                    OnStarted();
                    if (event_OnZoneStart != null)
                    {
                        event_OnZoneStart.Invoke(this);
                    }
                });				
			}
        }

        /// <summary>
        /// 开始异步关闭房间
        /// </summary>
        public void Stop()
        {
            lock (locker)
            {
                mShutDown = true;
            }
        }

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

        protected virtual void OnStarted() { }
        protected virtual void OnStopped() { }
        protected virtual void OnZoneUpdate(bool slowRefresh) { }
        //protected virtual void OnTestUpdate(int intervalMS)
        //{
        //    if (mSyncServerStatus.Update(intervalMS))
        //    {
        //        mSyncServerStatus.Tag.Update(Process.GetCurrentProcess());
        //        mPostZoneEvents.Enqueue(mSyncServerStatus.Tag);
        //    }
        //}
        protected virtual void OnBeginUpdate() { }
        protected virtual void OnEndUpdate() { }
        protected virtual void OnError(Exception err)
        {
            if (mConfig.TEST)
            {
                mPostZoneEvents.Enqueue(new ServerExceptionB2C(err.Message + " : " + this.ToString(), err.StackTrace));
            }
        }
        protected virtual void OnDispose() { }

        /// <summary>
        /// 当收到从场景来的消息(预过滤发送给客户端)
        /// </summary>
        /// <param name="e"></param>
        /// <returns>True截断消息</returns>
        protected virtual bool OnMessageHandlerFromInstanceZone(Event e) { return false; }

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

        private void timer_start()
        {
            if (EnableTimer)
            {
                this.mTimer = new System.Threading.Timer(do_update, this, this.mUpdateInterval, this.mUpdateInterval);
            }
        }
//         private void timer_update(object obj)
//         {
//             ThreadPool.QueueUserWorkItem(do_update, this);
//         }
        private void timer_exit()
        {
            if (this.mTimer != null)
            {
                this.mTimer.Dispose();
                this.mTimer = null;
            }
        }

        private void do_update(object obj)
        {
            lock (locker)
            {
				bool slowUpdate = true;
				if (!mIsRunning) return;
                Stopwatch stopwatch = Stopwatch.StartNew();
                try
                {
                    CommonLang.CUtils.localTimeMS = CommonLang.CUtils.CurrentTimeMS;
					CommonLang.CUtils.S_LOCAL_TIMESTAMPMS = CommonLang.TimeUtil.GetTimestampMS();

					if (mLastUpdateTime == 0)
                    {
                        mLastUpdateTime = CommonLang.CUtils.localTimeMS;
                    }
                    int intervalMS = (int)(CommonLang.CUtils.localTimeMS - mLastUpdateTime);
                    mLastUpdateTime = CommonLang.CUtils.localTimeMS;
                    intervalMS = Math.Min(intervalMS, mUpdateIntervalLimit);
					slowUpdate = this.ZoneUpdate(intervalMS);
                }
                catch (Exception err)
                {
                    log.Error(err.Message, err);
                    OnError(err);
                }
                finally
                {
                    stopwatch.Stop();
                    if (mIsRunning && stopwatch.ElapsedMilliseconds > mUpdateIntervalLimit)
                    {
                        log.WarnFormat("update overload at scene[{0}] : stopwatch time {1} units = {2} spells = {3} items = {4}, UUID = {5}, {6}",
                            mSceneData, stopwatch.ElapsedMilliseconds, mZone.AllUnitsCount, mZone.AllSpellsCount, mZone.AllItemsCount, mZone.UUID, mZone.GetInfo());
                    }
					//else if(mZone != null && slowUpdate & this.mProfileItemsTime < CommonLang.CUtils.localTimeMS && (mZone.AllUnitsCount > 200 || mZone.AllSpellsCount > 200 || mZone.AllItemsCount > 200))
					//{
					//	log.WarnFormat("场景单位数量预警[{0}] : stopwatch time {1} units = {2} spells = {3} items = {4}, UUID = {5}",
					//	   mSceneData, stopwatch.ElapsedMilliseconds, mZone.AllUnitsCount, mZone.AllSpellsCount, mZone.AllItemsCount, mZone.UUID);
					//}
                }
            }
        }
        /// <summary>
        /// 战斗场景主逻辑更新//
        /// </summary>
        /// <param name="intervalMS"></param>
        public virtual bool ZoneUpdate(int intervalMS)
        {
			bool slowUpdate = false;
			//从效率出发,Unit位置更新,及时推送到客户端,AOI进出则不需要每帧检测
			lock (locker)
            {
                if (mIsRunning)
                {
                    mTasks.ProcessMessages(do_task);
                    mPostZoneEvents.Clear();
					OnBeginUpdate();

					if (intervalMS > 0)
                    {						
                        try
                        {
							mTotalUpdateTimes++;
							if(mTotalUpdateTimes > GlobalData.ZONE_UPDATE_SLOW)
							{
								mTotalUpdateTimes = 0;
								slowUpdate = true;
							}							
							mZone.Update(intervalMS, slowUpdate);
                        }
                        catch (Exception err)
                        {
                            log.Error(err.Message, err);
                            OnError(err);
                        }
                        finally
                        {
                            this.OnZoneUpdate(slowUpdate);
                        }
                    }
                    //if (mConfig.TEST)
                    //{
                    //    OnTestUpdate(intervalMS);
                    //}
                    OnEndUpdate();
                    if (mShutDown)
                    {
                        this.mIsRunning = false;
                        try
                        {
                            timer_exit();
                            OnStopped();
                            if (event_OnZoneStop != null)
                            {
                                event_OnZoneStop.Invoke(this);
                            }
                        }
                        catch (Exception err)
                        {
                            log.Error(err.Message, err);
                            OnError(err);
                        }
                        try
                        {
                            this.OnDispose();
                            if (mZone != null)
                            {
                                this.mZone.Dispose();
                            }
                            if (event_OnZoneDisposed != null)
                            {
                                event_OnZoneDisposed.Invoke(this);
                            }
                        }
                        catch (Exception err)
                        {
                            log.Error(err.Message, err);
                            OnError(err);
                        }
                        finally
                        {
                            this.DisposeEvents();
                            this.mIsDisposed = true;
                        }
                    }
                }
            }
			return slowUpdate;
		}

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

        void InstanceZoneListener.onEventHandler(Event e)
        {
            if (!OnMessageHandlerFromInstanceZone(e))
            {
                mPostZoneEvents.Enqueue(e);
            }
        }

        protected internal delegate void Task();
        /// <summary>
        /// 保证在Task内部执行的代码线程安全
        /// </summary>
        /// <param name="task"></param>
        protected internal void QueueTask(Task task)
        {
            mTasks.Enqueue(task);
        }

        private void do_task(Task task)
        {
            if (task != null)
            {
                task.Invoke();
            }
        }

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

        protected virtual void DisposeEvents()
        {
            this.event_OnZoneStart = null;
            this.event_OnZoneStop = null;
            this.event_OnZoneDisposed = null;
        }

        private Action<BaseZoneNode> event_OnZoneStart;
        private Action<BaseZoneNode> event_OnZoneStop;
        private Action<BaseZoneNode> event_OnZoneDisposed;
        public event Action<BaseZoneNode> OnZoneStart { add { event_OnZoneStart += value; } remove { event_OnZoneStart -= value; } }
        public event Action<BaseZoneNode> OnZoneStop { add { event_OnZoneStop += value; } remove { event_OnZoneStop -= value; } }
        public event Action<BaseZoneNode> OnZoneDisposed { add { event_OnZoneDisposed += value; } remove { event_OnZoneDisposed -= value; } }

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


}