#region COPYRIGHT
//
//     THIS IS GENERATED BY TEMPLATE
//     
//     AUTHOR  :     ROYE
//     DATE       :     2011
//
//     COPYRIGHT (C) 2011, TIANXIAHOTEL TECHNOLOGIES CO., LTD. ALL RIGHTS RESERVED.
//
#endregion

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System.Caching
{
    /// <summary>
    /// 提供一个最近最少使用算法的服务端缓存类
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    public class LruCache<TKey, TValue> : ICache<TKey, TValue>
    {
        private readonly long capacity;
        private readonly TopDeque<TKey, KeyValuePair<TKey, TValue>> deque;

        /// <summary>
        /// 提供一个默认容量为5000，线程安全的LRU缓存。
        /// </summary>
        public static readonly ICache<TKey, TValue> Default = new ThreadSafeCache<TKey, TValue>(new LruCache<TKey, TValue>(5000), new object());

        /// <summary>
        /// 初始化指定容量的缓存实例。
        /// </summary>
        /// <param name="maxSize"></param>
        public LruCache(long capacity)
        {
            this.capacity = capacity;
            this.deque = new TopDeque<TKey, KeyValuePair<TKey, TValue>>();
        }

        /// <summary>
        /// 把键值对添加到缓存中。如果已存在相同键值对，则用新值替换。
        /// </summary>
        /// <param name="key"></param>
        /// <param name="item"></param>
        public void Add(TKey key, TValue item)
        {
            this.Add(key, item, true);
        }

        /// <summary>
        /// 把键值对添加到缓存中，并指定如果已存在相同键值对是否用新值替换。
        /// </summary>
        /// <param name="key"></param>
        /// <param name="item"></param>
        /// <param name="replaceIfExists"></param>
        /// <returns></returns>
        public TValue Add(TKey key, TValue item, bool replaceIfExists)
        {
            var cached = new KeyValuePair<TKey, TValue>(key, item);
            KeyValuePair<TKey, TValue> oldCached;
            if (this.deque.TryChangeValue(key, cached, true, replaceIfExists, out oldCached))
            {
                if (!replaceIfExists)
                {
                    return oldCached.Value;
                }
            }
            while (this.deque.Count > this.capacity && this.deque.Count > 0)
            {
                oldCached = this.deque.PopBottom();
            }
            return item;
        }

        /// <summary>
        /// 移除掉所有的键值。
        /// </summary>
        public void Clear()
        {
            while (this.deque.Count > 0)
            {
                this.deque.PopBottom();
            }
        }

        /// <summary>
        /// 确定是否包含指定的键。
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsKey(TKey key)
        {
            if (this.deque.Contains(key))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 从<see cref="System.Caching.LruCache<TKey, TItem>"/>移除掉指定键值。
        /// </summary>
        /// <param name="key"></param>
        public void RemoveKey(TKey key)
        {
            KeyValuePair<TKey, TValue> pair;
            if (this.deque.TryGetValue(key, out pair))
            {
                this.deque.Remove(key);
            }
        }

        /// <summary>
        /// 查找指定键对应的值，并标记为命中。
        /// </summary>
        /// <param name="key"></param>
        /// <param name="generator"></param>
        /// <returns></returns>
        public TValue Get(TKey key, Func<TValue> generator)
        {
            return Get(key, true, generator);
        }

        /// <summary>
        /// 查找指定键对应的值。
        /// </summary>
        /// <param name="key"></param>
        /// <param name="markAsHit"></param>
        /// <param name="generator"></param>
        /// <returns></returns>
        public TValue Get(TKey key, bool markAsHit, Func<TValue> generator)
        {
            if (!this.ContainsKey(key))
            {
                if (generator != null)
                {
                    this.Add(key, generator());
                }
            }

            KeyValuePair<TKey, TValue> pair;
            if (this.deque.TryGetValue(key, markAsHit, out pair))
            {
                return pair.Value;
            }
            return default(TValue);
        }

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

        public IEnumerator<TValue> GetEnumerator()
        {
            foreach (KeyValuePair<TKey, TValue> cachedItem in deque)
            {
                yield return cachedItem.Value;
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }

    /// <summary>
    /// 提供一个默认键类型为String类型的LRUCache类。
    /// </summary>
    /// <typeparam name="TItem"></typeparam>
    public class LruCache<TItem> : LruCache<string, TItem>
    {
        public LruCache(long capacity)
            : base(capacity)
        {
        }
    }
}