using System;
using System.Collections.Generic;

namespace CommonLang
{
    public delegate void TickHandler(TimeTaskMS task);

    public class TimeInterval<T>
    {
        public T Tag;
        private int mIntervalTimeMS;
        private int mPassTimeMS = 0;
        private int mTickCount = 0;
        private bool mFirstTimeEnable = true;
        /// <summary>
        /// 间隔时间
        /// </summary>
        public int IntervalTimeMS { get { return mIntervalTimeMS; } }
        /// <summary>
        /// 触发过多少次
        /// </summary>
        public int TotalTickCount { get { return mTickCount; } }
        /// <summary>
        /// 总共经过时间
        /// </summary>
        public int TotalPassTimeMS { get { return mPassTimeMS; } }

        public bool FirstTimeEnable
        {
            set
            {
                mFirstTimeEnable = value;
            }

            private get
            {
                return mFirstTimeEnable;
            }
        }
        public TimeInterval(int intervalMS)
        {
            this.mIntervalTimeMS = intervalMS;
        }
        public TimeInterval(T tag, int intervalMS)
        {
            this.mIntervalTimeMS = intervalMS;
            this.Tag = tag;
        }
        public void SetPassTime(int passtimeMS)
        {
            mPassTimeMS = passtimeMS;
        }

        /// <summary>
        /// 记录归零
        /// </summary>
        public void Reset()
        {
            mPassTimeMS = 0;
            mTickCount = 0;
        }
        public void Reset(int intervalMS)
        {
            mIntervalTimeMS = intervalMS;
            mPassTimeMS = 0;
            mTickCount = 0;
        }


		/// <summary>
		/// 更新
		/// </summary>
		/// <param name="intervalMS">间隔时间</param>
		/// <returns>是否应该触发</returns>
		//public bool Update(int intervalMS)
		//{
		//    if (mIntervalTimeMS > 0)
		//    {
		//        if (mIntervalTimeMS <= mPassTimeMS)
		//        {
		//            this.mPassTimeMS += intervalMS;
		//            this.mPassTimeMS -= mIntervalTimeMS;
		//            this.mTickCount++;
		//            return true;
		//        }
		//        else if (mPassTimeMS == 0 && FirstTimeEnable)
		//        {
		//            this.mPassTimeMS += intervalMS;
		//            return true;
		//        }
		//        else
		//        {
		//            this.mPassTimeMS += intervalMS;
		//        }
		//    }
		//    return false;
		//}
		public bool Update(int intervalMS)
		{
			bool isTrigger = false;
			if (mIntervalTimeMS > 0)
			{
				this.mPassTimeMS += intervalMS;
				if (FirstTimeEnable && this.mTickCount == 0)
				{
					this.mTickCount++;
					isTrigger = true;
				}
				else if(mIntervalTimeMS <= mPassTimeMS)
				{
					this.mPassTimeMS -= mIntervalTimeMS;
					this.mTickCount++;
					isTrigger = true;
				}
			}

			return isTrigger;
		}

		public TimeInterval<T> ChangeTiming(int intervalMs)
        {
            TimeInterval<T> rlt = new TimeInterval<T>(intervalMs);
            rlt.mPassTimeMS = this.mPassTimeMS;
            rlt.mTickCount = this.mTickCount;
            rlt.Tag = this.Tag;
            return rlt;
        }
    }

    public class TimeExpire<T>
    {
        public T Tag { get; set; }
        public int TotalTimeMS { get { return mTotalTimeMS; } }
        public int PassTimeMS { get { return mPassTimeMS; } }
        public int ExpireTimeMS { get { return mTotalTimeMS - mPassTimeMS; } }

        private int mTotalTimeMS;
        private int mPassTimeMS;

        public TimeExpire(int totalMS)
        {
            this.mTotalTimeMS = totalMS;
            this.mPassTimeMS = 0;
        }

        public TimeExpire(T tag, int totalMS)
            : this(totalMS)
        {
            this.Tag = tag;
        }

        /// <summary>
        /// 记录归零
        /// </summary>
        public void Reset()
        {
            this.mPassTimeMS = 0;
        }
        public void Reset(int totalTimeMS)
        {
            this.mPassTimeMS = 0;
            this.mTotalTimeMS = totalTimeMS;
        }

        public void End()
        {
            this.mPassTimeMS = mTotalTimeMS;
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="intervalMS">间隔时间</param>
        /// <returns>是否到期</returns>
        public bool Update(int intervalMS)
        {
            if (mPassTimeMS >= mTotalTimeMS)
            {
                return true;
            }
            this.mPassTimeMS += intervalMS;
            return false;
        }

        /// <summary>
        /// 是否结束
        /// </summary>
        public bool IsEnd { get { return mPassTimeMS >= mTotalTimeMS; } }

        /// <summary>
        /// 剩余百分比
        /// </summary>
        public float Percent
        {
            get
            {
                return Math.Min((float)mPassTimeMS / (float)mTotalTimeMS, 1);
            }
        }
    }

    public class TimeTaskMS
    {
        readonly private TickHandler Handler;
        readonly private int IntervalTimeMS;
        readonly private int DelayTimeMS;
        readonly private int RepeatCount;

        public object UserData;

        private bool mRunning = false;
        private bool mExit = false;
        private int PassTimeMS = 0;
        private int DelayTimer = 0;
        private int RepeatTick = 0;
        private bool mInvoking = false;

        public TimeTaskMS(int intervalMS, int delayMS, int repeat, TickHandler handler)
        {
            this.Handler = handler;
            this.IntervalTimeMS = intervalMS;
            this.DelayTimeMS = delayMS;
            this.RepeatCount = repeat;

            Reset();
        }

        internal void Start()
        {
            this.PassTimeMS = 0;
            this.mRunning = true;
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="intervalMS">间隔时间</param>
        internal void Update(int intervalMS)
        {
            if (!mExit && mRunning)
            {
                this.PassTimeMS += intervalMS;
                if (DelayTimer > 0)
                {
                    if (DelayTimer <= PassTimeMS)
                    {
                        mInvoking = true;
                        PassTimeMS -= DelayTimer;
                        DelayTimer = 0;
                    }
                    else
                    {
                        return;
                    }
                }
                if (IntervalTimeMS <= PassTimeMS)
                {
                    mInvoking = true;
                    PassTimeMS -= IntervalTimeMS;
                    if (RepeatCount > 0)
                    {
                        RepeatTick++;
                        if (RepeatTick >= RepeatCount)
                        {
                            mExit = true;
                        }
                    }
                }
            }
        }
        internal void TryInvoke()
        {
            if (mInvoking)
            {
                mInvoking = false;
                Handler.Invoke(this);
            }
        }

        public void Reset()
        {
            this.mRunning = true;
            this.mExit = false;
            this.PassTimeMS = 0;
            this.RepeatTick = 0;
            this.DelayTimer = DelayTimeMS;
        }

        public void Stop()
        {
            mExit = true;
        }

        public void Pause()
        {
            mRunning = false;
        }
        public void Resume()
        {
            mRunning = true;
        }

        public bool IsRunning
        {
            get { return mRunning; }
        }

        public bool IsExit
        {
            get { return mExit; }
        }
        internal bool IsInvoking
        {
            get { return mInvoking; }
        }
    }

    public class TimeTaskQueue : IDisposable
    {
        private LinkedList<TimeTaskMS> mTimeTasks = new LinkedList<TimeTaskMS>();

        private List<LinkedListNode<TimeTaskMS>> removed = new List<LinkedListNode<TimeTaskMS>>(2);
        private List<TimeTaskMS> invoking = new List<TimeTaskMS>(2);


        public void Dispose()
        {
            mTimeTasks.Clear();
            removed.Clear();
            invoking.Clear();
        }


        public void Update(int intervalMS)
        {
            removed.Clear();
            invoking.Clear();
            lock (mTimeTasks)
            {
                for (LinkedListNode<TimeTaskMS> it = mTimeTasks.Last; it != null; it = it.Previous)
                {
                    TimeTaskMS t = it.Value;
                    t.Update(intervalMS);
                    if (t.IsInvoking)
                    {
                        invoking.Add(t);
                    }
                    if (t.IsExit)
                    {
                        removed.Add(it);
                    }
                }
                if (removed.Count > 0)
                {
                    for (int i = removed.Count - 1; i >= 0; --i)
                    {
                        mTimeTasks.Remove(removed[i]);
                    }
                }
            }
            if (invoking.Count > 0)
            {
                for (int i = invoking.Count - 1; i >= 0; --i)
                {
                    TimeTaskMS task = invoking[i];
                    task.TryInvoke();
                }
            }
        }

        /// <summary>
        /// 增加时间任务
        /// </summary>
        /// <param name="intervalMS"></param>
        /// <param name="delayMS"></param>
        /// <param name="repeat"></param>
        /// <param name="handler"></param>
        public TimeTaskMS AddTimeTask(int intervalMS, int delayMS, int repeat, TickHandler handler)
        {
            TimeTaskMS time = new TimeTaskMS(intervalMS, delayMS, repeat, handler);
            lock (mTimeTasks)
            {
                mTimeTasks.AddLast(time);
            }
            time.Start();
            return time;
        }
        /// <summary>
        /// 增加延时回调方法
        /// </summary>
        /// <param name="delayMS"></param>
        /// <param name="handler"></param>
        public TimeTaskMS AddTimeDelayMS(int delayMS, TickHandler handler)
        {
            TimeTaskMS time = new TimeTaskMS(0, delayMS, 1, handler);
            lock (mTimeTasks)
            {
                mTimeTasks.AddLast(time);
            }
            time.Start();
            return time;
        }
        /// <summary>
        /// 增加定时回调方法
        /// </summary>
        /// <param name="intervalMS"></param>
        /// <param name="handler"></param>
        public TimeTaskMS AddTimePeriodicMS(int intervalMS, TickHandler handler)
        {
            TimeTaskMS time = new TimeTaskMS(intervalMS, 0, 0, handler);
            lock (mTimeTasks)
            {
                mTimeTasks.AddLast(time);
            }
            time.Start();
            return time;
        }
    }

	public delegate void MultiTimeLineRefresh(bool isAdd);

	/// <summary>
	/// 同时执行多个Timer
	/// </summary>
	public class MultiTimeLine
    {
        private readonly List<TimeExpire<int>> Times = new List<TimeExpire<int>>();
		private readonly MultiTimeLineRefresh mRefeshNotify;
		public MultiTimeLine(MultiTimeLineRefresh notify)
		{
			this.mRefeshNotify = notify;
		}

		public TimeExpire<int> Add(int timeMS)
        {
            TimeExpire<int> ret = new TimeExpire<int>(timeMS);
            Times.Add(ret);			
			if(this.mRefeshNotify != null)
			{
				this.mRefeshNotify.Invoke(true);
			}
			return ret;
        }
        public bool Remove(TimeExpire<int> task)
        {
            task.End();

			if (this.mRefeshNotify != null)
			{
				this.mRefeshNotify.Invoke(false);
			}

			return Times.Remove(task);
        }
        public void Clear()
        {
            for (int i = Times.Count - 1; i >= 0; --i)
            {
                TimeExpire<int> task = Times[i];
                task.End();
            }
            Times.Clear();
        }
        public bool Update(int intervalMS)
        {
			for (int i = Times.Count - 1; i >= 0; --i)
			{
				TimeExpire<int> task = Times[i];
				if (task.Update(intervalMS))
				{
					Times.RemoveAt(i);
				}
			}

			return Times.Count > 0;
		}
        public bool Enable { get { return Times.Count > 0; } }
    }

    //--------------------------------------------------------------------------------------------
    #region SystemTime


    public class SystemTimeInterval<T> : TimeInterval<T>
    {
        private long lastUpdateTime = CUtils.CurrentTimeMS;
        public SystemTimeInterval(int intervalMS) : base(intervalMS) { }
        public bool Update()
        {
            long curTime = CUtils.CurrentTimeMS;
            int interval = (int)(curTime - lastUpdateTime);
            lastUpdateTime = curTime;
            return base.Update(interval);
        }
    }

    public class SystemTimeExpire<T> : TimeExpire<T>
    {
        private long lastUpdateTime = CUtils.CurrentTimeMS;
        public SystemTimeExpire(int timeMS) : base(timeMS) { }
        public bool Update()
        {
            long curTime = CUtils.CurrentTimeMS;
            int interval = (int)(curTime - lastUpdateTime);
            lastUpdateTime = curTime;
            return base.Update(interval);
        }
    }

    public class SystemTimeTaskQueue : TimeTaskQueue
    {
        private long lastUpdateTime = CUtils.CurrentTimeMS;
        public void Update()
        {
            long curTime = CUtils.CurrentTimeMS;
            int interval = (int)(curTime - lastUpdateTime);
            lastUpdateTime = curTime;
            base.Update(interval);
        }
    }

	public class SystemMultiTimeLine : MultiTimeLine
	{
		private long lastUpdateTime = CUtils.CurrentTimeMS;
		public SystemMultiTimeLine() : base(null) { }
		public void Update()
		{
			long curTime = CUtils.CurrentTimeMS;
			int interval = (int)(curTime - lastUpdateTime);
			lastUpdateTime = curTime;
			base.Update(interval);
		}
	}

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


	public class SystemTimeRecoder
    {
        private long last_update_time;
        private int current_interval;

        public long LastUpdateTimeMS { get { return last_update_time; } }
        public int CurrentIntervalMS { get { return current_interval; } }

        public SystemTimeRecoder()
        {
            this.last_update_time = CUtils.CurrentTimeMS;
            this.current_interval = 0;
        }

        public void Reset()
        {
            this.last_update_time = CUtils.CurrentTimeMS;
            this.current_interval = 0;
        }

        public int Update()
        {
            long curtime = CUtils.CurrentTimeMS;
            current_interval =(int)(curtime - last_update_time);
            return current_interval;
        }

    }

    public class TimeUtil
    {
		//使用替代方案: CommonLang.CUtils.localTimeMS
		public static long GetTimestampMS()
        {
			TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
			return (long)ts.TotalMilliseconds;

			//return CommonLang.CUtils.CurrentTimeMS;
		}
    }  
}