namespace Thousandto.Update.Download
{
    using Thousandto.Update.Delegate;
    using Thousandto.Update.Log;
    using System;
    using System.Collections.Generic;
    using System.Threading;

    public class ThreadPool<T> where T: new()
    {
        private ThreadPoolAction<T> _action;
        private DataPool<T> _dataPool;
        private MyThread _highPriorityThread;
        protected object _lockObj;
        private bool _pause;
        private bool _stop;
        private ManualResetEvent _threadManger;
        private List<MyThread> _threadQueue;

        public ThreadPool(int maxThreadCount, ThreadPoolAction<T> action)
        {
            _threadQueue = new List<MyThread>();
            _dataPool = new DataPool<T>();
            _lockObj = new object();
            _stop = false;
            _action = action;
            _threadManger = new ManualResetEvent(false);
            for (int i = 0; i < maxThreadCount; i++)
            {
                MyThread item = new MyThread(i);
                item.Name = "download thread: " + i;
                if (_highPriorityThread == null)
                {
                    _highPriorityThread = item;
                    _highPriorityThread.Start(new ThreadStart(HighPriorityThreadFunc), ThreadPriority.Normal);
                }
                else
                {
                    item.Start(new ThreadStart(ThreadFunc), ThreadPriority.BelowNormal);
                }
                _threadQueue.Add(item);
            }
            UpdateLog.WARN_LOG("Init ThreadPool");
        }

        internal void AddData(T data, DataLevel level, bool fail = false)
        {
            _dataPool.AddData(data, level, fail);
            if (!_pause)
            {
                _threadManger.Set();
            }
            if (level == DataLevel.High)
            {
                _highPriorityThread.Resume();
            }
        }

        internal void AddFailData(T data)
        {
            _dataPool.AddFailData(data);
        }

        internal void ClearData(DataLevel level)
        {
            _dataPool.ClearQueue(level);
        }

        private void Dowork(T fileData)
        {
            if (_action != null)
            {
                _action(fileData);
            }
        }

        private T GetTask()
        {
            return PopData();
        }

        private void Join()
        {
            for (int i = 0; i < _threadQueue.Count; i++)
            {
            }
            _dataPool.Clear();
            _threadQueue.Clear();
        }

        /// <summary>
        /// 暂停普通下载队列,除了高优先级队列,其他队列都暂停
        /// </summary>
        public void Pause()
        {
            _pause = true;
            _threadManger.Reset();
        }

        /// <summary>
        /// 暂停指定下载队列
        /// </summary>
        /// <param name="level"></param>
        internal void PauseLevel(DataLevel level)
        {
            _dataPool.PauseLevel(level);
        }

        /// <summary>
        /// 恢复指定下载队列
        /// </summary>
        /// <param name="level"></param>
        internal void ResumeLevel(DataLevel level)
        {
            _dataPool.ResumeLevel(level);
        }

        public virtual T PopData()
        {
            return _dataPool.PopData();
        }

        /// <summary>
        /// 恢复所有下载队列
        /// </summary>
        public void Resume()
        {
            _pause = false;
            _threadManger.Set();
            _highPriorityThread.Resume();
        }

        /// <summary>
        /// 是否暂停中,除了高优先级队列,其他队列都暂停
        /// </summary>
        /// <returns></returns>
        public bool IsPaused()
        {
            return _pause;
        }

        /// <summary>
        /// 是否静默更新暂停中
        /// </summary>
        /// <returns></returns>
        internal bool IsBaseResPaused()
        {
            return _dataPool.IsBaseResPaused();
        }

        /// <summary>
        /// 是否当前场景暂停中
        /// </summary>
        /// <returns></returns>
        internal bool IsCurScenePaused()
        {
            return _dataPool.IsCurScenePaused();
        }

        /// <summary>
        /// 获取对应下载队列中数据个数
        /// </summary>
        /// <param name="level"></param>
        /// <returns></returns>
        internal int GetDataCount(DataLevel level)
        {
            return _dataPool.GetDataCount(level);
        }

        private void Stop()
        {
            _stop = true;
            Resume();
        }

        /// <summary>
        /// 高优先级下载
        /// </summary>
        private void HighPriorityThreadFunc()
        {
            while (!_stop)
            {
                if (_dataPool.GetHighPriorityQueueCount() == 0)
                {
                    UpdateLog.DEBUG_LOG("High Thread pause : " + Thread.CurrentThread.Name);
                    _highPriorityThread.Pause();
                }
                T task = GetTask();
                if (task == null)
                {
                    if (!_stop)
                    {
                        UpdateLog.DEBUG_LOG("High Thread pause1 : " + Thread.CurrentThread.Name);
                        _highPriorityThread.Pause();
                    }
                }
                else
                {
                    Dowork(task);
                }
            }
            UpdateLog.DEBUG_LOG("High Thread abort: " + Thread.CurrentThread.Name);
        }

        /// <summary>
        /// 普通资源下载
        /// </summary>
        private void ThreadFunc()
        {
            while (!_stop)
            {
                if (_pause)
                {
                    UpdateLog.DEBUG_LOG("Normal Thread pause : " + Thread.CurrentThread.Name);
                    _threadManger.Reset();
                    _threadManger.WaitOne();
                }
                T task = GetTask();
                if (task == null)
                {
                    UpdateLog.DEBUG_LOG("Normal Thread pause1 : " + Thread.CurrentThread.Name);
                    if (!_stop)
                    {
                        _threadManger.Reset();
                        _threadManger.WaitOne();
                    }
                }
                else
                {
                    Dowork(task);
                }
            }
            UpdateLog.DEBUG_LOG("Normal Thread abort: " + Thread.CurrentThread.Name);
        }

        public void WaitForFinish()
        {
            Stop();
            Join();
        }

        public object Locker
        {
            get
            {
                return _lockObj;
            }
        }
    }
}