/**
 * Copyright (c) 2017-present, Gregory Szorc
 * All rights reserved.
 *
 * This software may be modified and distributed under the terms
 * of the BSD license. See the LICENSE file for details.
 */

#include "python-zstandard.h"

extern PyObject *ZstdError;

FrameParametersObject *get_frame_parameters(PyObject *self, PyObject *args,
                                            PyObject *kwargs) {
    static char *kwlist[] = {"data", NULL};

    Py_buffer source;
    ZSTD_frameHeader header;
    FrameParametersObject *result = NULL;
    size_t zresult;

    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*:get_frame_parameters",
                                     kwlist, &source)) {
        return NULL;
    }

    zresult = ZSTD_getFrameHeader(&header, source.buf, source.len);

    if (ZSTD_isError(zresult)) {
        PyErr_Format(ZstdError, "cannot get frame parameters: %s",
                     ZSTD_getErrorName(zresult));
        goto finally;
    }

    if (zresult) {
        PyErr_Format(ZstdError,
                     "not enough data for frame parameters; need %zu bytes",
                     zresult);
        goto finally;
    }

    result = PyObject_New(FrameParametersObject, &FrameParametersType);
    if (!result) {
        goto finally;
    }

    result->frameContentSize = header.frameContentSize;
    result->windowSize = header.windowSize;
    result->dictID = header.dictID;
    result->checksumFlag = header.checksumFlag ? 1 : 0;

finally:
    PyBuffer_Release(&source);
    return result;
}

static void FrameParameters_dealloc(PyObject *self) {
    PyObject_Del(self);
}

static PyMemberDef FrameParameters_members[] = {
    {"content_size", T_ULONGLONG,
     offsetof(FrameParametersObject, frameContentSize), READONLY,
     "frame content size"},
    {"window_size", T_ULONGLONG, offsetof(FrameParametersObject, windowSize),
     READONLY, "window size"},
    {"dict_id", T_UINT, offsetof(FrameParametersObject, dictID), READONLY,
     "dictionary ID"},
    {"has_checksum", T_BOOL, offsetof(FrameParametersObject, checksumFlag),
     READONLY, "checksum flag"},
    {NULL}};

PyTypeObject FrameParametersType = {
    PyVarObject_HEAD_INIT(NULL, 0) "FrameParameters", /* tp_name */
    sizeof(FrameParametersObject),                    /* tp_basicsize */
    0,                                                /* tp_itemsize */
    (destructor)FrameParameters_dealloc,              /* tp_dealloc */
    0,                                                /* tp_print */
    0,                                                /* tp_getattr */
    0,                                                /* tp_setattr */
    0,                                                /* tp_compare */
    0,                                                /* tp_repr */
    0,                                                /* tp_as_number */
    0,                                                /* tp_as_sequence */
    0,                                                /* tp_as_mapping */
    0,                                                /* tp_hash  */
    0,                                                /* tp_call */
    0,                                                /* tp_str */
    0,                                                /* tp_getattro */
    0,                                                /* tp_setattro */
    0,                                                /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT,                               /* tp_flags */
    0,                                                /* tp_doc */
    0,                                                /* tp_traverse */
    0,                                                /* tp_clear */
    0,                                                /* tp_richcompare */
    0,                                                /* tp_weaklistoffset */
    0,                                                /* tp_iter */
    0,                                                /* tp_iternext */
    0,                                                /* tp_methods */
    FrameParameters_members,                          /* tp_members */
    0,                                                /* tp_getset */
    0,                                                /* tp_base */
    0,                                                /* tp_dict */
    0,                                                /* tp_descr_get */
    0,                                                /* tp_descr_set */
    0,                                                /* tp_dictoffset */
    0,                                                /* tp_init */
    0,                                                /* tp_alloc */
    0,                                                /* tp_new */
};

void frameparams_module_init(PyObject *mod) {
    Py_SET_TYPE(&FrameParametersType, &PyType_Type);
    if (PyType_Ready(&FrameParametersType) < 0) {
        return;
    }

    Py_INCREF(&FrameParametersType);
    PyModule_AddObject(mod, "FrameParameters",
                       (PyObject *)&FrameParametersType);
}
