#if !USE_CUSTOM_VSTRING_SCRIPT
using System.Collections.Generic;

namespace Giant.Common
{
    /// <summary>
    /// 自定义字符串池
    /// </summary>
    public class VStringPool
    {
        private const int kTotalStringCount = 1000;
        private const int kNewStringCount = 20;



        private static VStringPool m_Instance;
        public static VStringPool Instance
        {
            get
            {
                if (null == m_Instance)
                    InitPool();
                return m_Instance;
            }
        }



        private static void InitPool()
        {
            if (null == m_Instance)
            {
                m_Instance = new VStringPool();
                m_Instance.Init();
            }
        }



        private Queue<VString> m_FreeStrings;
        private HashSet<VString> m_UsedStrings;
        private HashSet<VString> m_UsedTmpStrings;



        protected VStringPool() { }



        ~VStringPool()
        {
            Clear();
        }



        /// <summary>
        /// Init string pool
        /// </summary>
        public void Init()
        {
            int tCapacity       = kTotalStringCount + 1000;
            m_FreeStrings       = new Queue<VString>(tCapacity);
            m_UsedStrings       = new HashSet<VString>();
            m_UsedTmpStrings    = new HashSet<VString>();

            VString tXStr;
            for (int tIdx = 0; tIdx < kTotalStringCount; ++tIdx)
            {
                tXStr = new VString();
                tXStr.inStringPool = true;
                m_FreeStrings.Enqueue(tXStr);
            }
        }



        public void Clear()
        {
            m_FreeStrings.Clear();
            m_UsedStrings.Clear();
            m_UsedTmpStrings.Clear();
        }



        /// <summary>
        /// Free string to pool
        /// </summary>
        public void FreeString(VString _XStr)
        {
            if(null != _XStr && !_XStr.inStringPool)
            {
                _XStr.inStringPool = true;
                if (_XStr.allocType == AllocType.Tmp)
                    m_UsedTmpStrings.Remove(_XStr);
                else
                    m_UsedStrings.Remove(_XStr);
                m_FreeStrings.Enqueue(_XStr);
            }
        }



        /// <summary>
        /// Gets string from pool
        /// </summary>
        /// <param name="_Length">length of string</param>
        public VString GetString(int _Length, AllocType _AllocType)
        {
            VString tXStr;
            if (m_FreeStrings.Count == 0)
            {
                for (int tIdx = 0; tIdx < kNewStringCount; ++tIdx)
                {
                    tXStr = new VString();
                    tXStr.inStringPool = true;
                    m_FreeStrings.Enqueue(tXStr);
                }
            }
            tXStr = null;
            if (m_FreeStrings.Count > 0)
            {
                tXStr = m_FreeStrings.Dequeue();
                tXStr.Allocate(_Length, _AllocType);
                if (_AllocType == AllocType.Tmp)
                    m_UsedTmpStrings.Add(tXStr);
                else
                    m_UsedStrings.Add(tXStr);
            }
            else
                tXStr = new VString(_Length, _AllocType);
#if DISPOSE_LEAK_DETECT
                tXStr.EnableDisposeSentinel();
#endif
            tXStr.inStringPool = false;
            return tXStr;
        }



#if !RELEASE
        private const int kSizeOfChar = sizeof(char);
        public string GetSizeInfo()
        {
            int tFree = 0;
            foreach (var item in m_FreeStrings)
                tFree += item.capacity * kSizeOfChar;
            int tUsed = 0;
            foreach (var item in m_UsedStrings)
                tUsed += item.capacity * kSizeOfChar;
            int tTmpUsed = 0;
            foreach (var item in m_UsedTmpStrings)
                tTmpUsed += item.capacity * kSizeOfChar;
            int tTotal = tFree + tUsed + tTmpUsed;
            return string.Format("<color=blue>【VString】单位：bytes</color>;    Total:{0}，Free:{1}，Used:{2}，TmpUsed:{3};", tTotal, tFree, tUsed, tTmpUsed);
        }
#endif
    }
}
#endif