#include <gracetmpl.h>

#include <string.h>
#include <complex>
#include <set>

/* python headers */
#include <Python.h>
/* numarray headers */
#include <numarray/numarray.h>
#include <numarray/arrayobject.h>

/********************************************************/
/******************* graceTMPL.data type ***************/
/********************************************************/

typedef struct
{
  PyObject_HEAD
  GraceTMPL::Data *data;
} graceTMPL_dataObject;

static void graceTMPL_dataDealloc(graceTMPL_dataObject *);
static PyObject *graceTMPL_dataGetattr(graceTMPL_dataObject *, char *);
static int graceTMPL_dataSetattr(graceTMPL_dataObject *, char *, PyObject *);

static PyTypeObject graceTMPL_dataType =
{
  PyObject_HEAD_INIT(NULL)
  0,
  "data",
  sizeof(graceTMPL_dataObject),
  0,
  (destructor)graceTMPL_dataDealloc, /*tp_dealloc*/
  0,          /*tp_print*/
  (getattrfunc)graceTMPL_dataGetattr, /*tp_getattr*/
  (setattrfunc)graceTMPL_dataSetattr, /*tp_setattr*/
  0,          /*tp_compare*/
  0,          /*tp_repr*/
  0,          /*tp_as_number*/
  0,          /*tp_as_sequence*/
  0,          /*tp_as_mapping*/
  0,          /*tp_hash */
}; // PyTypeObject graceTMPL_dataType

#define graceTMPLdata_Check(op) ((op)->ob_type == graceTMPL_dataType)

/******************* attribute member functions *******************/

static char doc_data_setEnv[] = "setEnv(string, string): Set an environment definition.";

static PyObject* graceTMPL_data_setEnv(graceTMPL_dataObject *self,
					PyObject *args)
{
  char *name;
  char *value;
  
  if (!PyArg_ParseTuple(args, "ss:graceTMPL.data.setEnv(name, value)", 
			&name, &value)){
    PyErr_SetString(PyExc_TypeError,
		    "graceTMPL.data.setEnv(string, string) expected as arguments.");
    return NULL;
  }
  self->data->setenv(std::string(name), std::string(value));

  return Py_None;
} // graceTMPL_data_setEnv(PyObject *, PyObject *)

static PyMethodDef graceTMPL_dataMethods[] =
{
  {"setEnv", (PyCFunction)graceTMPL_data_setEnv,
   METH_VARARGS, doc_data_setEnv},
  {NULL, NULL} /* sentinel */
}; // PyMethodDef graceTMPL_dataMethods[]

/******************* type member functions *******************/

static void graceTMPL_dataDealloc(graceTMPL_dataObject *self)
{
  delete self->data;
  PyObject_Del(self);
} // graceTMPL_dataDealloc(graceTMPL_dataObject *)

static PyObject *graceTMPL_dataGetattr(graceTMPL_dataObject *self, char *name)
{
  return Py_FindMethod(graceTMPL_dataMethods, (PyObject *)self, name);
} // graceTMPL_dataGetattr(graceTMPL_dataObject *, char *)

static int graceTMPL_dataSetattr(graceTMPL_dataObject *self, char *name, PyObject *op)
{
  PyErr_SetString(PyExc_AttributeError, "Attribute does not exist or cannot be set");
  return -1;
} // graceTMPL_dataSetattr(graceTMPL_dataObject *, char *, PyObject *)

/********************************************************/
/******************* graceTMPL.graph type ***************/
/********************************************************/

typedef struct
{
  PyObject_HEAD
  std::multiset<graceTMPL_dataObject *> *dataSet;
  GraceTMPL::Graph *graph;
} graceTMPL_graphObject;

static void graceTMPL_graphDealloc(graceTMPL_graphObject *);
static PyObject *graceTMPL_graphGetattr(graceTMPL_graphObject *, char *);
static int graceTMPL_graphSetattr(graceTMPL_graphObject *, char *, PyObject *);

static PyTypeObject graceTMPL_graphType =
{
  PyObject_HEAD_INIT(NULL)
  0,
  "graph",
  sizeof(graceTMPL_graphObject),
  0,
  (destructor)graceTMPL_graphDealloc, /*tp_dealloc*/
  0,          /*tp_print*/
  (getattrfunc)graceTMPL_graphGetattr, /*tp_getattr*/
  (setattrfunc)graceTMPL_graphSetattr, /*tp_setattr*/
  0,          /*tp_compare*/
  0,          /*tp_repr*/
  0,          /*tp_as_number*/
  0,          /*tp_as_sequence*/
  0,          /*tp_as_mapping*/
  0,          /*tp_hash */
}; // PyTypeObject graceTMPL_graphType

#define graceTMPLgraph_Check(op) ((op)->ob_type == graceTMPL_graphType)

/******************* attribute member functions *******************/

static char doc_graph_setEnv[] = "setEnv(string, string): Set an environment definition.";

static PyObject* graceTMPL_graph_setEnv(graceTMPL_graphObject *self,
					PyObject *args)
{
  char *name;
  char *value;
  
  if (!PyArg_ParseTuple(args, "ss:graceTMPL.graph.setEnv(name, value)", 
			&name, &value)){
    PyErr_SetString(PyExc_TypeError,
		    "graceTMPL.graph.setEnv(string, string) expected as arguments.");
    return NULL;
  }
  self->graph->setenv(std::string(name), std::string(value));

  return Py_None;
} // graceTMPL_graph_setEnv(PyObject *, PyObject *)

static char doc_graph_addData[] = "addData(numarray.array): Add a dataset to this graph.";

static PyObject* graceTMPL_graph_addData(graceTMPL_graphObject *self,
					 PyObject *args)
{
  char *name;
  PyObject *oDataArray = Py_None;
  PyArrayObject *dataArray = 0;
  GraceTMPL::Data *newData = 0;
  graceTMPL_dataObject *dataObject = 0;
  int cols, rows;
  
  if (!PyArg_ParseTuple(args, "sO:graceTMPL.graph.addData(name, dataArray)",
			&name, &oDataArray)){
    PyErr_SetString(PyExc_TypeError,
		    "graceTMPL.graph.addData(string, numarray.array) expected as arguments.");
    return NULL;
  }
  dataArray = NA_InputArray(oDataArray, tFloat64, C_ARRAY);

  if (dataArray->nd != 2 || dataArray->descr->type_num != PyArray_DOUBLE){
    PyErr_SetString(PyExc_ValueError,
		    "data array has to have exactly two axes and has to be of type float");
    return NULL;
  }
  if(dataArray->dimensions[0] < 2){
    PyErr_SetString(PyExc_ValueError,
		    "data array has to have at least dimension 2 in first axis");
    return NULL;
  }
  XXX_PyArray_INCREF(dataArray);
  cols = dataArray->dimensions[0];
  rows = dataArray->dimensions[1];
  if(cols > 4)
    cols = 4;
  double **data = new double *[cols];
  for(int c = 0; c < cols; ++c){
    data[c] = new double[rows];
    for(int r = 0; r < rows; ++r)
      data[c][r] = *(double *)(dataArray->data +
			       c * dataArray->strides[0] +
			       r * dataArray->strides[1]);
  }
  XXX_PyArray_XDECREF(dataArray);
  switch(cols){
  case 2:
    newData = new GraceTMPL::Data(std::string(name), rows,
				  data[0], data[1]);
    break;
  case 3:
    newData = new GraceTMPL::Data(std::string(name), rows,
				  data[0], data[1],
				  data[2]);
    break;
  default:
    newData = new GraceTMPL::Data(std::string(name), rows,
				  data[0], data[1],
				  data[2], data[3]);
  } // switch(cols)
  
  for(int c = 0; c < cols; ++c)
    delete[] data[c];
  delete[] data;
  
  dataObject = PyObject_New(graceTMPL_dataObject, &graceTMPL_dataType);
  dataObject->data = newData;

  Py_INCREF(dataObject);
  self->dataSet->insert(dataObject);

  self->graph->addData(newData);

  return (PyObject*)dataObject;
} // graceTMPL_graph_addData(PyObject *, PyObject *)

static PyMethodDef graceTMPL_graphMethods[] =
{
  {"setEnv", (PyCFunction)graceTMPL_graph_setEnv,
   METH_VARARGS, doc_graph_setEnv},
  {"addData", (PyCFunction)graceTMPL_graph_addData,
   METH_VARARGS, doc_graph_addData},
  {NULL, NULL} /* sentinel */
}; // PyMethodDef graceTMPL_graphMethods[]

/******************* type member functions *******************/

static void graceTMPL_graphDealloc(graceTMPL_graphObject *self)
{
  std::multiset<graceTMPL_dataObject*>::iterator data;
  for(data = self->dataSet->begin(); data != self->dataSet->end(); ++data)
    Py_DECREF(*data);
  delete self->graph;
  delete self->dataSet;
  PyObject_Del(self);
} // graceTMPL_graphDealloc(graceTMPL_graphObject *)

static PyObject *graceTMPL_graphGetattr(graceTMPL_graphObject *self, char *name)
{
  if(strcmp(name, "xoffset") == 0){
    return PyFloat_FromDouble(self->graph->xoffset());
  }
  if(strcmp(name, "yoffset") == 0){
    return PyFloat_FromDouble(self->graph->yoffset());
  }
  if(strcmp(name, "scaling") == 0){
    return PyFloat_FromDouble(self->graph->scale());
  }
  
  return Py_FindMethod(graceTMPL_graphMethods, (PyObject *)self, name);
} // graceTMPL_graphGetattr(graceTMPL_graphObject *, char *)

static int graceTMPL_graphSetattr(graceTMPL_graphObject *self, char *name, PyObject *op)
{
  if(strcmp(name, "xoffset") == 0){
    if (!PyFloat_Check(op)) 
      return -1;
    self->graph->setXOffset(PyFloat_AsDouble(op));
    return 0;
  }
  if(strcmp(name, "yoffset") == 0){
    if (!PyFloat_Check(op)) 
      return -1;
    self->graph->setYOffset(PyFloat_AsDouble(op));
    return 0;
  }
  if(strcmp(name, "scaling") == 0){
    if (!PyFloat_Check(op)) 
      return -1;
    self->graph->setScaling(PyFloat_AsDouble(op));
    return 0;
  }

  PyErr_SetString(PyExc_AttributeError, "Attribute does not exist or cannot be set");

  return -1;
} // graceTMPL_graphSetattr(graceTMPL_graphObject *, char *, PyObject *)

/********************************************************/
/******************* graceTMPL.save type ****************/
/********************************************************/

typedef struct
{
  PyObject_HEAD
  std::multiset<graceTMPL_graphObject *> *graphSet;
  GraceTMPL::Save *save;
} graceTMPL_saveObject;

static void graceTMPL_saveDealloc(graceTMPL_saveObject *);
static PyObject *graceTMPL_saveGetattr(graceTMPL_saveObject *, char *);
static int graceTMPL_saveSetattr(graceTMPL_saveObject *, char *, PyObject *);

static PyTypeObject graceTMPL_saveType =
{
  PyObject_HEAD_INIT(NULL)
  0,
  "save",
  sizeof(graceTMPL_saveObject),
  0,
  (destructor)graceTMPL_saveDealloc, /*tp_dealloc*/
  0,          /*tp_print*/
  (getattrfunc)graceTMPL_saveGetattr, /*tp_getattr*/
  (setattrfunc)graceTMPL_saveSetattr, /*tp_setattr*/
  0,          /*tp_compare*/
  0,          /*tp_repr*/
  0,          /*tp_as_number*/
  0,          /*tp_as_sequence*/
  0,          /*tp_as_mapping*/
  0,          /*tp_hash */
}; // PyTypeObject graceTMPL_saveType

#define graceTMPLsave_Check(op) ((op)->ob_type == graceTMPL_saveType)

/******************* attribute member functions *******************/

static char doc_save_loadTemplate[] = "loadTemplate(string, bool): Load a xmgrace file as template.";

static PyObject* graceTMPL_save_loadTemplate(graceTMPL_saveObject *self, PyObject *args)
{
  char *name;
  int useS0 = 0;

  if (!PyArg_ParseTuple(args, "s|i:graceTMPL.save.loadTemplate(name, useS0=0)",
			&name, &useS0)){
    PyErr_SetString(PyExc_TypeError,
		    "graceTMPL.save.loadTemplate(string, int) expected as arguments.");
    return NULL;
  }

  self->save->loadTemplate(name, useS0);

  return Py_None;
} // graceTMPL_save_LoadTemplate(PyObject *, PyObject *)

static char doc_save_setEnv[] = "setEnv(string, string): Set an environment definition.";

static PyObject* graceTMPL_save_setEnv(graceTMPL_saveObject *self, PyObject *args)
{
  char *name;
  char *value;
  
  if (!PyArg_ParseTuple(args, "ss:graceTMPL.save.setEnv(name, value)", 
			&name, &value)){
    PyErr_SetString(PyExc_TypeError,
		    "graceTMPL.save.setEnv(string, string) expected as arguments.");
    return NULL;
  }
  self->save->setenv(std::string(name), std::string(value));

  return Py_None;
} // graceTMPL_save_setEnv(PyObject *, PyObject *)

static char doc_save_addGraph[] = "addGraph(int=0): Create and store a new Graph within this object.";

static PyObject* graceTMPL_save_addGraph(graceTMPL_saveObject *self, PyObject *args)
{
  graceTMPL_graphObject *graphObject;
  std::multiset<graceTMPL_dataObject *> *dataSet;
  int logplot = 0;

  if(!PyArg_ParseTuple(args, "|i:save.addGraph(logplot=0)",
		       &logplot)){
    PyErr_SetString(PyExc_TypeError,
		    "graceTMPL.save.addGraph(int=0) expected as arguments.");
    return NULL;
  }
  graphObject = PyObject_New(graceTMPL_graphObject, &graceTMPL_graphType);
  Py_INCREF(graphObject);
  self->graphSet->insert(graphObject);
  dataSet = new std::multiset<graceTMPL_dataObject *>;
  graphObject->graph = self->save->newGraph(logplot);
  graphObject->dataSet = dataSet;

  return (PyObject*)graphObject;
} // graceTMPL_save_addGraph(PyObject *, PyObject *)

static char doc_save_save[] = "save.save(): Save all graphs to a file.";

static PyObject *graceTMPL_save_save(graceTMPL_saveObject* self, PyObject *name){
  char *filename;

  if(!PyArg_ParseTuple(name, "s:save.save(filename)", &filename)){
    PyErr_SetString(PyExc_TypeError,
		    "graceTMPL.save.save(string) expected as argument.");
    return NULL;
  }
  self->save->setOutputName(filename);
  self->save->save();
  return Py_None;
}

static char doc_save_info[] = "save.info(): Quey information about datasets the template requests.";

static PyObject *graceTMPL_save_info(graceTMPL_saveObject* self, PyObject *args){
  if(!PyArg_ParseTuple(args, ":save.info()")){
    PyErr_SetString(PyExc_TypeError,
		    "graceTMPL.save.save(): no argument expected.");
    return NULL;
  }
  GraceTMPL::String2Vec templateInfo = self->save->templateDataRequestInfo();

  PyObject *infoList;
  PyObject *subList;
  infoList = PyList_New(0);
  GraceTMPL::String2Vec::iterator subVec;
  GraceTMPL::StringVec::iterator entry;
  for(subVec = templateInfo.begin();
      subVec != templateInfo.end();
      ++subVec){
    subList = PyList_New(0);
    for(entry = subVec->begin();
	entry != subVec->end();
	++entry)
      PyList_Append(subList,
		    PyString_FromStringAndSize(entry->c_str(), entry->size()));
    PyList_Append(infoList, subList);
  }
  
  return (PyObject*)infoList;
}

static PyMethodDef graceTMPL_saveMethods[] =
{
  {"save", (PyCFunction)graceTMPL_save_save,
   METH_VARARGS, doc_save_save},
  {"loadTemplate", (PyCFunction)graceTMPL_save_loadTemplate,
   METH_VARARGS, doc_save_loadTemplate},
  {"setEnv", (PyCFunction)graceTMPL_save_setEnv,
   METH_VARARGS, doc_save_setEnv},
  {"addGraph", (PyCFunction)graceTMPL_save_addGraph,
   METH_VARARGS, doc_save_addGraph},
  {"info", (PyCFunction)graceTMPL_save_info,
   METH_VARARGS, doc_save_info},
  {NULL, NULL}
}; // PyMethodDef graceTMPL_saveMethods[]

/******************* type member functions *******************/

static void graceTMPL_saveDealloc(graceTMPL_saveObject *self)
{
  std::multiset<graceTMPL_graphObject*>::iterator graph;
  for(graph = self->graphSet->begin(); graph != self->graphSet->end(); ++graph)
    Py_DECREF(*graph);
  delete self->save;
  delete self->graphSet;
  PyObject_Del(self);
} // graceTMPL_saveDealloc(graceTMPL_saveObject *)

static PyObject *graceTMPL_saveGetattr(graceTMPL_saveObject *self, char *name)
{
  return Py_FindMethod(graceTMPL_saveMethods, (PyObject *)self, name);
} // graceTMPL_saveGetattr(graceTMPL_saveObject *, char *)

static int graceTMPL_saveSetattr(graceTMPL_saveObject *self, char *name, PyObject *op)
{
  if(strcmp(name, "outputName") == 0){
    if (!PyString_Check(op)) 
      return -1;
    self->save->setOutputName(PyString_AsString(op));
    return 0;
  }
  PyErr_SetString(PyExc_AttributeError, "Attribute does not exist or cannot be set");
  return -1;
} // graceTMPL_saveSetattr(graceTMPL_saveObject *, char *, PyObject *)

/********************************************************/
/******************* module functions *******************/
/********************************************************/

static char doc_save[] = "save() will return a new save object.";

static PyObject* graceTMPL_save(PyObject* self, PyObject* args)
{
  graceTMPL_saveObject* saveObject;
  GraceTMPL::Save *save;
  std::multiset<graceTMPL_graphObject *> *graphSet;

  if (!PyArg_ParseTuple(args,":save")){
    PyErr_SetString(PyExc_TypeError,
		    "graceTMPL.save() no arguments expected.");
    return NULL;
  }
  save = new GraceTMPL::Save;
  graphSet = new std::multiset<graceTMPL_graphObject *>;
  saveObject = PyObject_New(graceTMPL_saveObject, &graceTMPL_saveType);
  saveObject->save = save;
  saveObject->graphSet = graphSet;

  return (PyObject*)saveObject;
} // graceTMPL_save(PyObject *, PyObject *)

static PyMethodDef graceTMPL_Methods[] =
{
  {"save", graceTMPL_save, METH_VARARGS | METH_KEYWORDS, doc_save},
  {NULL, NULL}
}; // PyMethodDef graceTMPL_Methods[]

#ifdef __cplusplus
extern "C"
{
#endif

DL_EXPORT(void) initgraceTMPL(void) 
{
  graceTMPL_dataType.ob_type = &PyType_Type;
  graceTMPL_graphType.ob_type = &PyType_Type;
  graceTMPL_saveType.ob_type = &PyType_Type;

  Py_InitModule("graceTMPL", graceTMPL_Methods);
  import_libnumarray();
} // initgraceTMPL(void)

#ifdef __cplusplus
}
#endif


syntax highlighted by Code2HTML, v. 0.9.1