using System;
using System.Collections.Generic;
using System.Threading;

namespace NetWorkHelper.ICollections
{
    /// <summary>
    /// 有序的数组，SortedArray 中的元素是不允许重复的。如果添加数组中已经存在的元素，将会被忽略。
    /// 该实现是线程安全的。
    /// </summary>
    [Serializable]
    public class SortedArray<T> : SortedArray2<T>, IComparer<T> where T : IComparable
    {
        public SortedArray()
        {
            base.comparer4Key = this;
        }

        public SortedArray(ICollection<T> collection)
        {
            base.comparer4Key = this;
            base.Rebuild(collection);
        }

        #region IComparer<TKey> 成员

        public int Compare(T x, T y)
        {
            return x.CompareTo(y);
        }

        #endregion
    }

    /// <summary>
    /// 有序的数组，SortedArray 中的元素是不允许重复的。如果添加数组中已经存在的元素，将会被忽略。
    /// 该实现是线程安全的。
    /// </summary>
    [Serializable]
    public class SortedArray2<T>
    {
        private List<T> lazyCopy = null;
        private int minCapacityForShrink = 32;
        private T[] array = new T[32];
        private int validCount = 0;
        protected IComparer<T> comparer4Key = null;

        #region SmartRWLocker

        [NonSerialized] private SmartRWLocker smartRWLocker = new SmartRWLocker();

        private SmartRWLocker SmartRWLocker
        {
            get
            {
                if (smartRWLocker == null)
                {
                    smartRWLocker = new SmartRWLocker();
                }

                return smartRWLocker;
            }
        }

        #endregion

        #region Ctor

        protected SortedArray2()
        {
        }

        public SortedArray2(IComparer<T> comparer)
        {
            this.comparer4Key = comparer;
        }

        public SortedArray2(IComparer<T> comparer, ICollection<T> collection)
        {
            this.comparer4Key = comparer;
            Rebuild(collection);
        }

        protected void Rebuild(ICollection<T> collection)
        {
            if (collection == null || collection.Count == 0)
            {
                return;
            }
            this.array = new T[collection.Count];
            collection.CopyTo(this.array, 0);
            Array.Sort(this.array, this.comparer4Key);
            this.validCount = collection.Count;
        }

        #endregion

        #region Property

        #region Count

        public int Count
        {
            get { return this.validCount; }
        }

        #endregion

        #region Capacity

        private int Capacity
        {
            get { return this.array.Length; }
        }

        #endregion

        #region LastReadTime

        public DateTime LastReadTime
        {
            get { return this.SmartRWLocker.LastRequireReadTime; }
        }

        #endregion

        #region LastWriteTime

        public DateTime LastWriteTime
        {
            get { return this.SmartRWLocker.LastRequireWriteTime; }
        }

        #endregion

        #endregion

        #region Contains

        public bool Contains(T t)
        {
            return this.IndexOf(t) >= 0;
        }

        #endregion

        #region Index

        public T this[int index]
        {
            get
            {
                using (this.SmartRWLocker.Lock(AccessMode.Read))
                {
                    if (index < 0 || (index >= this.validCount))
                    {
                        throw new Exception("Index out of the range !");
                    }

                    return this.array[index];
                }
            }
        }

        #endregion

        #region IndexOf

        public int IndexOf(T t)
        {
            using (this.SmartRWLocker.Lock(AccessMode.Read))
            {
                if (this.validCount == 0)
                {
                    return -1;
                }

                int index = Array.BinarySearch<T>(this.array, 0, this.validCount, t, this.comparer4Key);

                return (index < 0) ? -1 : index;
            }
        }

        #endregion

        #region Add

        public void Add(T t)
        {
            int posIndex = 0;
            this.Add(t, out posIndex);
        }

        /// <summary>
        /// Add 将一个元素添加到数组中。如果数组中已存在目标元素，则忽略。无论哪种情况，posIndex都会被赋予正确的值。
        /// </summary>        
        public void Add(T t, out int posIndex)
        {
            if (t == null)
            {
                throw new Exception("Target can't be null !");
            }

            using (this.SmartRWLocker.Lock(AccessMode.Write))
            {
                int index = Array.BinarySearch<T>(this.array, 0, this.validCount, t, this.comparer4Key);
                if (index >= 0)
                {
                    posIndex = index;
                    return;
                }

                this.AdjustCapacity(1);
                posIndex = ~index;
                Array.Copy(this.array, posIndex, this.array, posIndex + 1, this.validCount - posIndex);
                this.array[posIndex] = t;

                ++this.validCount;
            }

            this.lazyCopy = null;
        }

        public void Add(ICollection<T> collection)
        {
            this.Add(collection, true);
        }

        /// <summary>
        /// Add 如果能保证collection中的元素不会与现有的元素重复，则checkRepeat可以传入false。
        /// </summary>       
        public void Add(ICollection<T> collection, bool checkRepeat)
        {
            if (collection == null || collection.Count == 0)
            {
                return;
            }

            using (this.SmartRWLocker.Lock(AccessMode.Write))
            {
                ICollection<T> resultCollection = collection;

                #region checkRepeat

                if (checkRepeat)
                {
                    Dictionary<T, T> dic = new Dictionary<T, T>();
                    foreach (T t in collection)
                    {
                        if (dic.ContainsKey(t) || this.Contains(t))
                        {
                            continue;
                        }

                        dic.Add(t, t);
                    }

                    resultCollection = dic.Keys;
                }

                #endregion

                if (resultCollection.Count == 0)
                {
                    return;
                }

                this.AdjustCapacity(resultCollection.Count);

                foreach (T t in resultCollection)
                {
                    this.array[this.validCount] = t;
                    ++this.validCount;
                }

                Array.Sort<T>(this.array, 0, this.validCount, this.comparer4Key);
            }

            this.lazyCopy = null;
        }

        #endregion

        #region Remove

        #region Remove

        /// <summary>
        /// Remove 删除数组中所有值为t的元素。
        /// </summary>      
        public void Remove(T t)
        {
            if (t == null)
            {
                return;
            }

            int index = -1;
            do
            {
                index = this.IndexOf(t);
                if (index >= 0)
                {
                    this.RemoveAt(index);
                }

            } while (index >= 0);

            this.lazyCopy = null;
        }

        #endregion

        #region RemoveAt

        public void RemoveAt(int index)
        {
            using (this.SmartRWLocker.Lock(AccessMode.Write))
            {
                if (index < 0 || (index >= this.validCount))
                {
                    return;
                }

                if (index == this.validCount - 1)
                {
                    this.array[index] = default(T);
                }
                else
                {
                    Array.Copy(this.array, index + 1, this.array, index, this.validCount - index - 1);
                }
                --this.validCount;
            }

            this.lazyCopy = null;
        }

        #endregion

        #region RemoveBetween

        public void RemoveBetween(int minIndex, int maxIndex)
        {
            using (this.SmartRWLocker.Lock(AccessMode.Write))
            {
                minIndex = minIndex < 0 ? 0 : minIndex;
                maxIndex = maxIndex >= this.validCount ? this.validCount - 1 : maxIndex;

                if (maxIndex < minIndex)
                {
                    return;
                }

                Array.Copy(this.array, maxIndex + 1, this.array, minIndex, this.validCount - maxIndex - 1);

                this.validCount -= (maxIndex - minIndex + 1);
            }

            this.lazyCopy = null;
        }

        #endregion

        #endregion

        #region GetBetween

        public T[] GetBetween(int minIndex, int maxIndex)
        {
            using (this.SmartRWLocker.Lock(AccessMode.Read))
            {
                minIndex = minIndex < 0 ? 0 : minIndex;
                maxIndex = maxIndex >= this.validCount ? this.validCount - 1 : maxIndex;

                if (maxIndex < minIndex)
                {
                    return new T[0];
                }

                int count = maxIndex - minIndex - 1;
                T[] result = new T[count];

                Array.Copy(this.array, minIndex, result, 0, count);
                return result;
            }
        }

        #endregion

        #region Shrink

        /// <summary>
        /// Shrink 将内部数组收缩到最小，释放内存。
        /// </summary>
        public void Shrink()
        {
            using (this.SmartRWLocker.Lock(AccessMode.Write))
            {
                if (this.array.Length == this.validCount)
                {
                    return;
                }


                int len = this.validCount >= this.minCapacityForShrink ? this.validCount : this.minCapacityForShrink;

                T[] newAry = new T[len];

                Array.Copy(this.array, 0, newAry, 0, this.validCount);
                this.array = newAry;
            }
        }

        #endregion

        #region AdjustCapacity

        private void AdjustCapacity(int newCount)
        {
            using (this.SmartRWLocker.Lock(AccessMode.Write))
            {
                int totalCount = this.validCount + newCount;
                if (this.array.Length >= totalCount)
                {
                    return;
                }

                int newCapacity = this.array.Length;
                while (newCapacity < totalCount)
                {
                    newCapacity *= 2;
                }

                T[] newAry = new T[newCapacity];
                Array.Copy(this.array, 0, newAry, 0, this.validCount);
                this.array = newAry;
            }
        }

        #endregion

        #region GetMax

        public T GetMax()
        {
            using (this.SmartRWLocker.Lock(AccessMode.Read))
            {
                if (this.validCount == 0)
                {
                    throw new Exception("SortedArray is Empty !");
                }

                return this.array[this.validCount - 1];
            }
        }

        #endregion

        #region GetMin

        public T GetMin()
        {
            using (this.SmartRWLocker.Lock(AccessMode.Read))
            {
                if (this.validCount == 0)
                {
                    throw new Exception("SortedArray is Empty !");
                }

                return this.array[0];
            }
        }

        #endregion

        #region GetAll

        public List<T> GetAll()
        {
            List<T> list = new List<T>();
            using (this.SmartRWLocker.Lock(AccessMode.Read))
            {
                for (int i = 0; i < this.validCount; i++)
                {
                    list.Add(this.array[i]);
                }
            }
            return list;
        }

        #endregion

        #region GetAllReadonly

        /// <summary>
        /// 注意，内部使用了Lazy缓存，返回的集合不可被修改。
        /// </summary>        
        public List<T> GetAllReadonly()
        {
            if (this.lazyCopy != null)
            {
                return this.lazyCopy;
            }

            using (this.SmartRWLocker.Lock(AccessMode.Read))
            {
                List<T> list = new List<T>();
                for (int i = 0; i < this.validCount; i++)
                {
                    list.Add(this.array[i]);
                }

                this.lazyCopy = list;
                return this.lazyCopy;
            }
        }

        #endregion

        #region Clear

        public void Clear()
        {
            using (this.SmartRWLocker.Lock(AccessMode.Write))
            {
                this.array = new T[this.minCapacityForShrink];
                this.validCount = 0;
            }

            this.lazyCopy = null;
        }

        #endregion

        #region ToString

        public override string ToString()
        {
            return string.Format("Count:{0} ,Capacity:{1}", this.validCount, this.array.Length);
        }

        #endregion
    }

    /// <summary>
    /// SmartRWLocker 简化了ReaderWriterLock的使用。通过using来使用Lock方法返回的对象，如：using(this.smartLocker.Lock(AccessMode.Read)){...}
    /// zhuweisky 2008.11.25
    /// </summary>   
    public class SmartRWLocker
    {
        private ReaderWriterLock readerWriterLock = new ReaderWriterLock();

        #region LastRequireReadTime

        private DateTime lastRequireReadTime = DateTime.Now;

        public DateTime LastRequireReadTime
        {
            get { return lastRequireReadTime; }
        }

        #endregion

        #region LastRequireWriteTime

        private DateTime lastRequireWriteTime = DateTime.Now;

        public DateTime LastRequireWriteTime
        {
            get { return lastRequireWriteTime; }
        }

        #endregion

        #region Lock

        public LockingObject Lock(AccessMode accessMode, bool enableSynchronize)
        {
            if (!enableSynchronize)
            {
                return null;
            }

            return this.Lock(accessMode);
        }

        public LockingObject Lock(AccessMode accessMode)
        {
            if (accessMode == AccessMode.Read)
            {
                this.lastRequireReadTime = DateTime.Now;
            }
            else
            {
                this.lastRequireWriteTime = DateTime.Now;
            }

            return new LockingObject(this.readerWriterLock, accessMode);
        }

        #endregion
    }

    /// <summary>
    /// LockingObject SmartRWLocker的Lock方法返回的锁对象。仅仅通过using来使用该对象，如：using(this.smartLocker.Lock(AccessMode.Read)){...}
    /// </summary>
    public class LockingObject : IDisposable
    {
        private ReaderWriterLock readerWriterLock;
        private AccessMode accessMode = AccessMode.Read;
        private LockCookie lockCookie;

        #region Ctor

        public LockingObject(ReaderWriterLock _lock, AccessMode _lockMode)
        {
            this.readerWriterLock = _lock;
            this.accessMode = _lockMode;

            if (this.accessMode == AccessMode.Read)
            {
                this.readerWriterLock.AcquireReaderLock(-1);
            }
            else if (this.accessMode == AccessMode.Write)
            {
                this.readerWriterLock.AcquireWriterLock(-1);
            }
            else //UpAndDowngrade
            {
                this.lockCookie = this.readerWriterLock.UpgradeToWriterLock(-1);
            }
        }

        #endregion

        #region IDisposable 成员

        public void Dispose()
        {
            if (this.accessMode == AccessMode.Read)
            {
                this.readerWriterLock.ReleaseReaderLock();
            }
            else if (this.accessMode == AccessMode.Write)
            {
                this.readerWriterLock.ReleaseWriterLock();
            }
            else //UpAndDowngrade
            {
                this.readerWriterLock.DowngradeFromWriterLock(ref this.lockCookie);
            }
        }

        #endregion
    }

    /// <summary>
    /// AccessMode 访问锁定资源的方式。
    /// </summary>
    public enum AccessMode
    {
        Read = 0,
        Write,

        /// <summary>
        /// 前提条件：已经获取Read锁。
        /// 再采用此模式，可以先升级到Write，访问资源，再降级回Read。
        /// </summary>
        UpAndDowngrade4Write
    }
}