using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace nft.util {
    public class Cache<TKey, TValue> : IDictionary<TKey, TValue> where TValue : class {
        // Dictionary to contain the cache.
        static Dictionary<TKey, WeakReference> _cache;

        public Cache(int capacity) {
            _cache = new Dictionary<TKey, WeakReference>(capacity);
        }

        // Accesses a data object from the cache.
        // If the object was reclaimed for garbage collection,
        // create a new data object at that index location.
        public TValue this[TKey key] {
            get {
                if (_cache.ContainsKey(key)) {
                    WeakReference wr = _cache[key];
                    if (wr.IsAlive) {
                        return wr.Target as TValue;
                    } else {
                        return null;
                    }
                } else {
                    throw new KeyNotFoundException(key+" is not found in the table");
                }
            }
            set {
                if (_cache.ContainsKey(key)) {
                    WeakReference wr = _cache[key];
                    wr.Target = value;
                } else {
                    _cache.Add(key,new WeakReference(value, true));
                }
            }
        }


        #region IDictionary<TKey,TValue> メンバ

        /// <summary>
        /// Add item. throws an exception if the key is already exist.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void Add(TKey key, TValue value) {
            _cache.Add(key, new WeakReference(value,true));
        }

        public bool ContainsKey(TKey key) {
            return _cache.ContainsKey(key);
        }

        public ICollection<TKey> Keys {
            get { return _cache.Keys; }
        }

        public bool Remove(TKey key) {
            return _cache.Remove(key);
        }

        public bool TryGetValue(TKey key, out TValue value) {
            WeakReference wr;
            if (_cache.TryGetValue(key, out wr)) {
                if (wr.IsAlive) {
                    value = wr.Target as TValue;
                    return true;
                }
            }
            value = null;
            return false;
        }

        public ICollection<TValue> Values {
            get { throw new NotImplementedException(); }
        }

        #endregion

        #region ICollection<KeyValuePair<TKey,TValue>> メンバ

        public void Add(KeyValuePair<TKey, TValue> item) {
            Add(item.Key, item.Value);
        }

        public void Clear() {
            _cache.Clear();
        }

        public int Count {
            get {
                return _cache.Count;
            }
        }
        
        public bool Contains(KeyValuePair<TKey, TValue> item) {
            throw new NotImplementedException();
        }

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
            throw new NotImplementedException();
        }

        public bool IsReadOnly {
            get { return false; }
        }

        public bool Remove(KeyValuePair<TKey, TValue> item) {
            throw new NotImplementedException();
        }

        #endregion

        #region IEnumerable<KeyValuePair<TKey,TValue>> メンバ

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
            throw new NotImplementedException();
        }

        #endregion

        #region IEnumerable メンバ

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
            throw new NotImplementedException();
        }

        #endregion
    }

}
