#ifndef STANDALONE
#include <Python.h>
#endif
#include <stdint.h>
#include "../bitstream.h"
#include "../array.h"
#include "../ogg.h"
#ifndef STANDALONE
#define STANDALONE
#include "flac.h"
#undef STANDALONE
#else
#include "flac.h"
#endif

/********************************************************
 Audio Tools, a module and set of tools for manipulating audio data
 Copyright (C) 2007-2015  Brian Langenberger

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*******************************************************/

#ifndef STANDALONE
typedef struct {
    PyObject_HEAD

    FILE* ogg_file;
    OggPacketIterator* ogg_packets;
    int channel_mask;

    struct flac_STREAMINFO streaminfo;

    uint32_t crc16;
    audiotools__MD5Context md5;
    int stream_finalized;
    int closed;

    /*temporary buffers we don't want to reallocate each time*/
    aa_int* subframe_data;
    a_int* residuals;
    a_int* qlp_coeffs;
    a_int* framelist_data;

    /*a framelist generator*/
    PyObject* audiotools_pcm;
} decoders_OggFlacDecoder;

static PyObject*
OggFlacDecoder_sample_rate(decoders_OggFlacDecoder *self, void *closure);

static PyObject*
OggFlacDecoder_bits_per_sample(decoders_OggFlacDecoder *self, void *closure);

static PyObject*
OggFlacDecoder_channels(decoders_OggFlacDecoder *self, void *closure);

static PyObject*
OggFlacDecoder_channel_mask(decoders_OggFlacDecoder *self, void *closure);

static PyObject*
OggFlacDecoder_read(decoders_OggFlacDecoder *self, PyObject *args);

static PyObject*
OggFlacDecoder_close(decoders_OggFlacDecoder *self, PyObject *args);

static PyObject*
OggFlacDecoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds);

void
OggFlacDecoder_dealloc(decoders_OggFlacDecoder *self);

int
OggFlacDecoder_init(decoders_OggFlacDecoder *self,
                    PyObject *args, PyObject *kwds);

static PyObject*
OggFlacDecoder_enter(decoders_OggFlacDecoder* self, PyObject *args);

static PyObject*
OggFlacDecoder_exit(decoders_OggFlacDecoder* self, PyObject *args);

PyGetSetDef OggFlacDecoder_getseters[] = {
    {"sample_rate", (getter)OggFlacDecoder_sample_rate, NULL,
     "sample rate", NULL},
    {"bits_per_sample", (getter)OggFlacDecoder_bits_per_sample,
     NULL, "bits-per-sample", NULL},
    {"channels", (getter)OggFlacDecoder_channels,
     NULL, "channels", NULL},
    {"channel_mask", (getter)OggFlacDecoder_channel_mask,
     NULL, "channel mask", NULL},
    {NULL}
};

PyMethodDef OggFlacDecoder_methods[] = {
    {"read", (PyCFunction)OggFlacDecoder_read,
     METH_VARARGS, "read(pcm_frame_count) -> FrameList"},
    {"close", (PyCFunction)OggFlacDecoder_close,
     METH_NOARGS, "close() -> None"},
    {"__enter__", (PyCFunction)OggFlacDecoder_enter,
     METH_NOARGS, "enter() -> self"},
    {"__exit__", (PyCFunction)OggFlacDecoder_exit,
     METH_VARARGS, "exit(exc_type, exc_value, traceback) -> None"},
    {NULL}
  };

PyTypeObject decoders_OggFlacDecoderType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "decoders.OggFlacDecoder",     /*tp_name*/
    sizeof(decoders_OggFlacDecoder), /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)OggFlacDecoder_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 | Py_TPFLAGS_BASETYPE, /*tp_flags*/
    "OggFlacDecoder objects",      /* tp_doc */
    0,                         /* tp_traverse */
    0,                         /* tp_clear */
    0,                         /* tp_richcompare */
    0,                         /* tp_weaklistoffset */
    0,                         /* tp_iter */
    0,                         /* tp_iternext */
    OggFlacDecoder_methods,        /* tp_methods */
    0,                         /* tp_members */
    OggFlacDecoder_getseters,      /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    (initproc)OggFlacDecoder_init, /* tp_init */
    0,                         /* tp_alloc */
    OggFlacDecoder_new,            /* tp_new */
};

int
OggFlacDecoder_update_md5sum(decoders_OggFlacDecoder *self,
                             PyObject *framelist);

int
OggFlacDecoder_verify_okay(decoders_OggFlacDecoder *self);
#endif

/*given a STREAMINFO packet, reads the data into "streaminfo"
  and the total number of header packets into "header_packets"

  returns 1 of processed successfully, 0 if not*/
int
oggflac_read_streaminfo(BitstreamReader *bitstream,
                        struct flac_STREAMINFO *streaminfo,
                        uint16_t *header_packets);
