#include "PySemsAudio.h"
#include "AmAudio.h"
#include "AmSession.h"

#include "log.h"

#ifdef PY_SEMS_WITH_TTS
#  include "flite.h"
#  define TTS_CACHE_PATH "/tmp/"

extern "C" cst_voice *register_cmu_us_kal();

#endif //PY_SEMS_WITH_TTS


static PyObject* PySemsAudioFile_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
  DBG("---------- PySemsAudioFile_alloc -----------\n");
  PySemsAudioFile *self;

  self = (PySemsAudioFile *)type->tp_alloc(type, 0);
	
  if (self != NULL) {

    self->af = new AmAudioFile();
    if(!self->af){
      Py_DECREF(self);
      return NULL;
    }

#ifdef PY_SEMS_WITH_TTS
    flite_init();
    self->tts_voice = register_cmu_us_kal();
    self->filename = new string();
#endif

  }

  return (PyObject *)self;
}

static void PySemsAudioFile_dealloc(PySemsAudioFile* self)
{
  DBG("---------- PySemsAudioFile_dealloc -----------\n");
  delete self->af;
  self->af = NULL;

#ifdef PY_SEMS_WITH_TTS
  if(self->del_file && !self->filename->empty())
    unlink(self->filename->c_str());
  delete self->filename;
#endif

  self->ob_type->tp_free((PyObject*)self);
}

static PyObject* PySemsAudioFile_open(PySemsAudioFile* self, PyObject* args)
{
  int                   ivr_open_mode;
  char*                 filename;
  bool                  is_tmp;
  PyObject*             py_is_tmp = NULL;
  AmAudioFile::OpenMode open_mode;

  if(!PyArg_ParseTuple(args,"si|O",&filename,&ivr_open_mode,&py_is_tmp))
    return NULL;

  switch(ivr_open_mode){
  case AUDIO_READ:
    open_mode = AmAudioFile::Read;
    break;
  case AUDIO_WRITE:
    open_mode = AmAudioFile::Write;
    break;
  default:
    PyErr_SetString(PyExc_TypeError,"Unknown open mode");
    return NULL;
    break;
  }

  if((py_is_tmp == NULL) || (py_is_tmp == Py_False))
    is_tmp = false;
  else if(py_is_tmp == Py_True)
    is_tmp = true;
  else {
    PyErr_SetString(PyExc_TypeError,"third parameter should be of type PyBool");
    return NULL;
  }

  if(self->af->open(filename,open_mode,is_tmp)){
    PyErr_SetString(PyExc_IOError,"Could not open file");
    return NULL;
  }

  Py_INCREF(Py_None);
  return Py_None;
}

static PyObject* PySemsAudioFile_fpopen(PySemsAudioFile* self, PyObject* args)
{
  int                   ivr_open_mode;
  char*                 filename;
  PyObject*             py_file = NULL;
  AmAudioFile::OpenMode open_mode;

  if(!PyArg_ParseTuple(args,"siO",&filename,&ivr_open_mode,&py_file))
    return NULL;

  switch(ivr_open_mode){
  case AUDIO_READ:
    open_mode = AmAudioFile::Read;
    break;
  case AUDIO_WRITE:
    open_mode = AmAudioFile::Write;
    break;
  default:
    PyErr_SetString(PyExc_TypeError,"Unknown open mode");
    return NULL;
    break;
  }

  FILE* fp = PyFile_AsFile(py_file);
  if(!fp){
    PyErr_SetString(PyExc_IOError,"Could not get FILE pointer");
    return NULL;
  }

  if(self->af->fpopen(filename,open_mode,fp)){
    PyErr_SetString(PyExc_IOError,"Could not open file");
    return NULL;
  }

  Py_INCREF(Py_None);
  return Py_None;
}

static PyObject* PySemsAudioFile_rewind(PySemsAudioFile* self, PyObject* args)
{
  self->af->rewind();
  Py_INCREF(Py_None);
  return Py_None;
}

#ifdef PY_SEMS_WITH_TTS
static PyObject* PySemsAudioFile_tts(PyObject* cls, PyObject* args)
{
  char* text;
  if(!PyArg_ParseTuple(args,"s",&text))
    return NULL;
    
  PyObject* constr_args = Py_BuildValue("(O)",Py_None);
  PyObject* tts_file = PyObject_CallObject(cls,constr_args);
  Py_DECREF(constr_args);

  if(tts_file == NULL){
    PyErr_Print();
    PyErr_SetString(PyExc_RuntimeError,"could not create new PySemsAudioFile object");
    return NULL;
  }

  PySemsAudioFile* self = (PySemsAudioFile*)tts_file;

  *self->filename = string(TTS_CACHE_PATH) + AmSession::getNewId() + string(".wav");
  self->del_file = true;
  flite_text_to_speech(text,self->tts_voice,self->filename->c_str());
    
  if(self->af->open(self->filename->c_str(),AmAudioFile::Read)){
    Py_DECREF(tts_file);
    PyErr_SetString(PyExc_IOError,"could not open TTS file");
    return NULL;
  }

  return tts_file;
}
#endif
    
static PyObject* PySemsAudioFile_close(PySemsAudioFile* self, PyObject*)
{
  self->af->close();
  Py_INCREF(Py_None);
  return Py_None;
}

static PyObject* PySemsAudioFile_getDataSize(PySemsAudioFile* self, PyObject*)
{
  return PyInt_FromLong(self->af->getDataSize());
}

static PyObject* PySemsAudioFile_setRecordTime(PySemsAudioFile* self, PyObject* args)
{
  int rec_time;
  if(!PyArg_ParseTuple(args,"i",&rec_time))
    return NULL;

  self->af->setRecordTime(rec_time);
    
  Py_INCREF(Py_None);
  return Py_None;
}

static PyObject* PySemsAudioFile_exportRaw(PySemsAudioFile* self, PyObject*)
{
  if(self->af->getMode() == AmAudioFile::Write)
    self->af->on_close();
    
  self->af->rewind();

  return PyFile_FromFile(self->af->getfp(),"","rwb",NULL);
}


static PyMethodDef PySemsAudioFile_methods[] = {
  {"open", (PyCFunction)PySemsAudioFile_open, METH_VARARGS,
   "open the audio file"
  },
  {"fpopen", (PyCFunction)PySemsAudioFile_fpopen, METH_VARARGS,
   "open the audio file"
  },
  {"close", (PyCFunction)PySemsAudioFile_close, METH_NOARGS,
   "close the audio file"
  },
  {"rewind", (PyCFunction)PySemsAudioFile_rewind, METH_NOARGS,
   "rewind the audio file"
  },
  {"getDataSize", (PyCFunction)PySemsAudioFile_getDataSize, METH_NOARGS,
   "returns the recorded data size"
  },
  {"setRecordTime", (PyCFunction)PySemsAudioFile_setRecordTime, METH_VARARGS,
   "set the maximum record time in millisecond"
  },
  {"exportRaw", (PyCFunction)PySemsAudioFile_exportRaw, METH_NOARGS,
   "creates a new Python file with the actual file"
   " and eventually flushes headers (audio->on_stop)"
  },
#ifdef PY_SEMS_WITH_TTS
  {"tts", (PyCFunction)PySemsAudioFile_tts, METH_CLASS | METH_VARARGS,
   "text to speech"
  },
#endif
  {NULL}  /* Sentinel */
};


static PyObject* PySemsAudioFile_getloop(PySemsAudioFile* self, void*)
{
  if (self->af->loop.get()) {
    Py_RETURN_TRUE;
  } else {
    Py_RETURN_FALSE;
  }
}

static int PySemsAudioFile_setloop(PySemsAudioFile* self, PyObject* value, void*)
{
  if (value == NULL) {
    PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
    return -1;
  }
  
  if(value == Py_True)
    self->af->loop.set(true);

  else if(value == Py_False)
    self->af->loop.set(false);

  else {
    PyErr_SetString(PyExc_TypeError, 
		    "The first attribute value must be a boolean");
    return -1;
  }

  return 0;
}

static PyGetSetDef PySemsAudioFile_getseters[] = {
  {"loop", 
   (getter)PySemsAudioFile_getloop, (setter)PySemsAudioFile_setloop,
   "repeat mode",
   NULL},
  {NULL}  /* Sentinel */
};
    
PyTypeObject PySemsAudioFileType = {
	
  PyObject_HEAD_INIT(NULL)
  0,                         /*ob_size*/
  "ivr.PySemsAudioFile",        /*tp_name*/
  sizeof(PySemsAudioFile),      /*tp_basicsize*/
  0,                         /*tp_itemsize*/
  (destructor)PySemsAudioFile_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*/
  "An audio file",           /*tp_doc*/
  0,		               /* tp_traverse */
  0,		               /* tp_clear */
  0,		               /* tp_richcompare */
  0,		               /* tp_weaklistoffset */
  0,		               /* tp_iter */
  0,		               /* tp_iternext */
  PySemsAudioFile_methods,      /* tp_methods */
  0,                         /* tp_members */
  PySemsAudioFile_getseters,    /* 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 */
  PySemsAudioFile_new,          /* tp_new */
};
