#if !USE_CUSTOM_VSTRING_SCRIPT
using System;
using System.Runtime.InteropServices;

namespace Giant.Common
{
    /// <summary>
    /// Memory pool for chars
    /// </summary>
    public sealed class CharMemoryPool
    {
        /// <summary>
        /// Block的最大数量
        /// </summary>
        private const int kMaxBlockCount = 64;



        /// <summary>
        /// Block中的Chunk最大字节容量
        /// </summary>
        private const int kSmallBlockMaxSize = 64;



        private static CharMemoryPool s_MemoryPool;
        static public CharMemoryPool Instance
        {
            get
            {
                if (null == s_MemoryPool)
                    InitPool();
                return s_MemoryPool;
            }
        }



        private static void InitPool()
        {
            if (null == s_MemoryPool)
            {
                s_MemoryPool = new CharMemoryPool();
                s_MemoryPool.Init();
            }
        }



        private IntPtr m_Memory;



        private MemoryBlock[] m_FreeBlocks = new MemoryBlock[kSmallBlockMaxSize / 2];



        private CharMemoryPool() { }



        ~CharMemoryPool()
        {
            Free();
        }



        /// <summary>
        /// free memory to system
        /// </summary>
        private void Free()
        {
            if (IntPtr.Zero != m_Memory)
            {
                Marshal.FreeHGlobal(m_Memory);
                m_Memory = IntPtr.Zero;
            }
        }



        /// <summary>
        /// Init memory pool list
        /// </summary>
        private void Init()
        {
            int tBlockIdx = 0;
            int tTotalMemory = 0;
            for (int tBlockSize = 2; tBlockSize <= kSmallBlockMaxSize; tBlockSize += 2)
            {
                MemoryBlock tBlock = new MemoryBlock();
                //每个Block中的Chunk大小从2开始，最大为64，数量为kMaxBlockCount
                tTotalMemory += (tBlockSize * kMaxBlockCount);
                m_FreeBlocks[tBlockIdx++] = tBlock;
            }

            m_Memory = Marshal.AllocHGlobal(tTotalMemory);

            tBlockIdx = 0;
            Int64 tP = m_Memory.ToInt64();
            for (int tBlockSize = 2; tBlockSize <= kSmallBlockMaxSize; tBlockSize += 2)
            {
                m_FreeBlocks[tBlockIdx++].Init(tP, tBlockSize, kMaxBlockCount);
                tP += (tBlockSize * kMaxBlockCount);
            }
        }


        /// <summary>
        /// Gets memory from pool
        /// </summary>
        public Int64 AllocMemory(int _TotalBytes)
        {
            if (_TotalBytes <= kSmallBlockMaxSize)
                return m_FreeBlocks[_TotalBytes / 2 - 1].AllocMemory();
            else
                return Marshal.AllocHGlobal(_TotalBytes).ToInt64();
        }



        /// <summary>
        /// Free memory
        /// </summary>
        public void FreeMemory(ref IntPtr _Ptr, int _ByteLength)
        {
            if (_ByteLength <= kSmallBlockMaxSize)
                m_FreeBlocks[_ByteLength / 2 - 1].FreeMemory(ref _Ptr);
            else
                Marshal.FreeHGlobal(_Ptr);
        }



#if !RELEASE
        /// <summary>
        /// debug memory info
        /// </summary>
        public string GetSizeInfo()
        {
            X2StringBuilder.Clear();
            X2StringBuilder.Append("<color=blue>【CharMemoryPool】单位：bytes，容量：");
            X2StringBuilder.Append(kMaxBlockCount);
            X2StringBuilder.Append("</color>;");
            int tTotalMemory = 0;
            for (int tBlockIdx = 0; tBlockIdx < m_FreeBlocks.Length; ++tBlockIdx)
            {
                X2StringBuilder.Append(m_FreeBlocks[tBlockIdx].GetSizeInfo());
                tTotalMemory += (tBlockIdx + 1) * 2 * kMaxBlockCount;
            }
            X2StringBuilder.Append("    Memory pool total memory: ");
            X2StringBuilder.Append(tTotalMemory);
            X2StringBuilder.Append(";");
            return X2StringBuilder.ConvertToString();
        }
#endif
    }
}
#endif