#ifndef HGL_MEM_BLOCK_INCLUDE
#define HGL_MEM_BLOCK_INCLUDE

#include<hgl/type/DataType.h>
#include<hgl/io/FileInputStream.h>
#include<hgl/filesystem/FileSystem.h>
#include<hgl/thread/ThreadMutex.h>
namespace hgl
{
    /**
     * 内存块模版
     */
    template<typename T> class MemBlock
    {
    protected:

        T *buf;
        size_t cur_size;
        size_t buf_size;

    public:

                size_t GetLength	()const{return cur_size;}										///<取得内存块长度(注：非字节数)
        const	size_t GetMaxLength	()const{return buf_size;}										///<取得内存块最大长度(注：非字节数)
        const	size_t GetBytes		()const{return cur_size*sizeof(T);}								///<取得内存块字节数
        const	size_t GetMaxBytes	()const{return buf_size*sizeof(T);}								///<取得内存块最大字节数

        /**
         * 分配指定空间出来，供未来使用
         */
        void Malloc(size_t size)
        {
            if(size<=buf_size)
                return;

            buf_size=power_to_2(size);

            if(!buf)
                buf=(T *)hgl_malloc(buf_size*sizeof(T));
            else
                buf=(T *)hgl_realloc(buf,buf_size*sizeof(T));
        }

        /**
         * 设置当前数据长度
         */
        void SetLength(size_t size)																	///<设置内存块长度(注：非字节数)
        {
            Malloc(size);

            cur_size=size;
        }

        void AddLength(size_t size)
        {
            SetLength(cur_size+size);
        }

    public:

        MemBlock()
        {
            buf=0;
            cur_size=0;
            buf_size=0;
        }

        MemBlock(size_t size)
        {
            if(size<=0)
                buf=0;
            else
                buf=(T *)hgl_malloc(size*sizeof(T));

            if(buf)
            {
                cur_size=size;
                buf_size=size;
            }
            else
            {
                cur_size=0;
                buf_size=0;
            }
        }

        virtual ~MemBlock()
        {
            Clear();
        }

        void Clear()
        {
            if(buf)
                hgl_free(buf);

            cur_size=0;
            buf_size=0;
        }

        void ClearData()
        {
            cur_size=0;
        }

        void Zero()
        {
            if(buf)
                memset(buf,0,buf_size);
        }

        /**
         * 设置数据,请保证数据使用hgl_malloc分配，否则会因为释放函数不配对出现错误
         */
        void SetData(T *d,int s)
        {
            Clear();

            buf=d;
            buf_size=s;
            cur_size=s;
        }

        /**
         * 解除数据关联
         */
        void Unlink()
        {
            buf=nullptr;
            cur_size=0;
            buf_size=0;
        }

        /**
         * 复制内存块中的数据
         * @param d 复制出来的缓冲区指针
         * @param s 要复制出来的数据个数
         */
        void CopyData(T *d,int s)
        {
            SetLength(s);
            memcpy(buf,d,s*sizeof(T));
        }

        T *data()const{return buf;}
        T *GetData()const{return buf;}

        size_t length()const{return cur_size;}
        size_t GetCount()const{return cur_size;}

        size_t bytes()const
        {
            return cur_size*sizeof(T);
        }

        operator T *()const
        {
            return buf;
        }

        T *operator ->()const
        {
            return buf;
        }

        T &operator[](int n)
        {
            return buf+n;
        }
    };//template<typename T> class MemBlock

    /**
     * 加载一个文件到内存块类中
     */
    template<typename T> MemBlock<T> *LoadFileToMemBlock(const OSString &filename)
    {
        io::FileInputStream fis;

        if(!fis.Open(filename))return(nullptr);

        const size_t file_size	=fis.GetSize();
        const size_t size		=(file_size+sizeof(T)-1)/sizeof(T);

        MemBlock<T> *mb=new MemBlock<T>(size);

        fis.Read(mb->data(),file_size);

        return(mb);
    }

    /**
     * 保存一个内存块到文件
     */
    template<typename T> bool SaveMemBlockToFile(const OSString &filename,const MemBlock<T> &mb)
    {
        const size_t size=mb.bytes();

        if(size<=0)return(true);

        return(hgl::filesystem::SaveMemoryToFile(filename,mb.data(),mb.bytes())==size);
    }
}//namespace hgl
#endif//HGL_MEM_BLOCK_INCLUDE
