// py_ex_lzo.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <eter/py_tinker.h>

#include "lzo/lzoconf.h"
#include "lzo/lzo1x.h"

#pragma comment(lib, "lzo2.lib")

using namespace py_tinker;

class Buffer
{
    public:
        Buffer()
        {
            m_base = NULL;
            m_size = 0;
        }
        ~Buffer()
        {
            delete m_base;
        }

        bool Alloc(int size)
        {
            if (size < 0)
                return false;

            if (m_size >= size)
                return true;

            if (m_size < size)
                delete m_base;

            m_base = new char[size];
            m_size = size;
            return true;
        }
        bool IsEmpty()
        {
            return (m_base == NULL);
        }
        void* GetBase()
        {
            return m_base;
        }

    private:
        char* m_base;
        int m_size;
};

static Buffer gs_wrkMem;
static Buffer gs_dstMem;

PyObject* pylzo1x_decompress(PyObject* src, int buf_len)
{
    if (!gs_wrkMem.Alloc(LZO1X_999_MEM_COMPRESS))
    {
        throw PyTinkerException(PyExc_RuntimeError, "lzo.wrkmem.error");
        return NULL;
    }

    lzo_uint src_len = (lzo_uint)PyString_Size(src);
    lzo_uint dst_len = buf_len;
    gs_dstMem.Alloc(dst_len);

    if (lzo1x_decompress(
            (const lzo_bytep)PyString_AsString(src),
            src_len,
            (lzo_bytep)gs_dstMem.GetBase(), &dst_len,
            (lzo_voidp)gs_wrkMem.GetBase()) != LZO_E_OK)
    {
        throw PyTinkerException(PyExc_RuntimeError, "lzo.decomress.error");
        return NULL;
    }
    return PyString_FromStringAndSize((const char*)gs_dstMem.GetBase(), dst_len);
}

PyObject* pylzo1x_999_compress(PyObject* src, int buf_len)
{
    if (!gs_wrkMem.Alloc(LZO1X_999_MEM_COMPRESS))
    {
        throw PyTinkerException(PyExc_RuntimeError, "lzo.wrkmem.error");
        return NULL;
    }

    lzo_uint src_len = (lzo_uint)PyString_Size(src);
    lzo_uint std_len = 4 + (src_len + src_len/64 + 16 + 3)  + 8;
    lzo_uint dst_len = buf_len;
    if (dst_len < std_len)
        dst_len = std_len;

    gs_dstMem.Alloc(dst_len);

    if (lzo1x_999_compress(
                (const lzo_bytep)PyString_AsString(src),
                src_len,
                (lzo_bytep)gs_dstMem.GetBase(), &dst_len,
                (lzo_voidp)gs_wrkMem.GetBase()) != LZO_E_OK)
    {
        throw PyTinkerException(PyExc_RuntimeError, "lzo.comress.error");
        return NULL;
    }

    return PyString_FromStringAndSize((const char*)gs_dstMem.GetBase(), dst_len);
}

void pylzo_init()
{
    if (lzo_init() != LZO_E_OK)
    {
        throw PyTinkerException(PyExc_RuntimeError, "lzo.error");
        return;
    }
}

PyMODINIT_FUNC
initlzo2()
{
    module_("lzo2")
        .DEFT(lzo_version_string)
        .DEFT(lzo_version_date)
        .deft("lzo1x_decompress", pylzo1x_decompress)
        .deft("lzo1x_999_compress", pylzo1x_999_compress)
        .defv("lzo_init", pylzo_init)
        ;
}

int main(int argc, char* argv[])
{
	Py_Initialize();
	Py_SetProgramName((char*)"py_test");
				
	initlzo2();
	py_tinker::PyEmbed_RunMainFile("ex_lzo.py");
	Py_Finalize();	
	return 0;
}
