/********************************************************************
	created:	2018/01/08
	created:	8:1:2018   20:49
	filename: 	F:\work\x2m\mainline\dev\client\Assets\Script\X2Interface\Core\Kernel\FastListMap.cs
	file path:	F:\work\x2m\mainline\dev\client\Assets\Script\X2Interface\Core\Kernel
	file base:	FastListMap
	file ext:	cs
	author:		zhang qiang
	
	purpose:	the collection of list and dictionary, for search and access quickly
*********************************************************************/

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

namespace Giant.Common
{
    /// the collection of list and dictionary
    /// for search quickly and access quickly   
    public class ListMap<TKey, TValue>
    {
        /// cache list for removed key
        private List<TKey> _rmoveCache = null;

        /// map list for search element quickly
        public Dictionary<TKey, TValue> Map
        {
            get; protected set;
        }

        /// array list for acces element quickly
        public List<TValue> ValueList
        {
            get; protected set;
        }

        public void Release()
        {
            ListPool<TValue>.Release(ValueList);
            if(_rmoveCache != null)
                ListPool<TKey>.Release(_rmoveCache);
            DictionaryPool<TKey, TValue>.Release(Map);
        }

        /// constructor,you must determine the capacity
        public ListMap(int iCapacity)
        {
            ValueList = ListPool<TValue>.Get();
            ValueList.Capacity = iCapacity;
                    
            Map = new Dictionary<TKey, TValue>(iCapacity);
            Map = DictionaryPool<TKey, TValue>.Get();
        }

        // for access element like array
        public TValue this[TKey key]
        {
            get
            {
                return Map[key];
            }
            set
            {
                SetValue(key, value);
            }
        }

        // update and add element
        public void SetValue(TKey key, TValue value)
        {
            if (value != null)
            {
                TValue oldValue;
                if (Map.TryGetValue(key, out oldValue))
                {
                    if (!CheckEquals(oldValue, value))
                    {
                        ValueList.Remove(oldValue);
                        Map[key] = value;
                        ValueList.Add(value);
                    }
                }
                else
                {
                    Map.Add(key, value);
                    ValueList.Add(value);
                }
            }
        }

        public delegate bool EqualCheckHandle(TValue v1, TValue v2);

        private EqualCheckHandle _equalCheckHandle = null;

        /// set the check handle
        public void SetEqualCheckHandle(EqualCheckHandle handle)
        {
            _equalCheckHandle = handle;
        }

        /// Check the value equal whether or not
        private bool CheckEquals(TValue oldValue, TValue value)
        {
            if (_equalCheckHandle != null)
            {
                return _equalCheckHandle(oldValue, value);
            }
            return EqualityComparer<TValue>.Default.Equals(oldValue, value);
        }

        /// search  an key exist
        public bool ContainsKey(TKey key)
        {
            return Map.ContainsKey(key);
        }

        /// search  an value exist
        public bool ContainsValue(TValue value)
        {
            return ValueList.Contains(value);
        }

        /// search and get an element
        public bool TryGetValue(TKey key, out TValue value)
        {
            return Map.TryGetValue(key, out value);
        }

        /// remove an element
        public bool Remove(TKey key)
        {
            TValue value;
            if (Map.TryGetValue(key, out value))
            {
                Map.Remove(key);
                ValueList.Remove(value);
                return true;
            }
            return false;
        }

        /// clear all the element
        public void Clear()
        {
            Map.Clear();
            ValueList.Clear();
        }

        /// cached the remove key, remove it later
        public void CachedRemove(TKey key)
        {
            if (_rmoveCache == null)
            {
                _rmoveCache = ListPool<TKey>.Get();
            }
                
            _rmoveCache.Add(key);
        }

        /// remove the cached key
        public void RemoveFromCache()
        {
            if (_rmoveCache == null)
                return;
            for (int i = 0; i < _rmoveCache.Count; i++)
            {
                this.Remove(_rmoveCache[i]);
            }
            _rmoveCache.Clear();
        }
    }
}
