/*******************************************************************************
*                                                                              *
*                                   Viewmol                                    *
*                                                                              *
*                       S P E C T R U M M O D U L E . C                        *
*                                                                              *
*                 Copyright (c) Joerg-R. Hill, October 2003                    *
*                                                                              *
********************************************************************************
*
* $Id: spectrummodule.c,v 1.2 2003/11/07 11:16:27 jrh Exp $
* $Log: spectrummodule.c,v $
* Revision 1.2  2003/11/07 11:16:27  jrh
* Release 2.4
*
* Revision 1.1  2000/12/10 15:17:03  jrh
* Initial revision
*
*/     
#include<stdio.h>
#include<unistd.h>
#include<Xm/DrawingA.h>
#include<Xm/ToggleB.h>
#include "viewmol.h"

#define PySpectrum_API_pointers 1
#define PySpectrumSpec_Type_NUM 0

extern void initSpectrum(Widget, caddr_t, caddr_t);
extern void setAnimation(int);
extern void GetMode(Widget, caddr_t, XmToggleButtonCallbackStruct *);
extern void GetAnimate(Widget, caddr_t, XmToggleButtonCallbackStruct *);
extern void GetType(Widget, caddr_t, XmToggleButtonCallbackStruct *);
extern void saveZoom(int);
extern void setMenuItem(int, int);
extern void selectMolecule(Widget, caddr_t, XmToggleButtonCallbackStruct *);
extern void redraw(int);
extern void saveDrawing(int, int, char *);
extern void drawSpectrum(Widget, caddr_t, XmDrawingAreaCallbackStruct *);
extern void quitSpectrum(Widget, caddr_t, XmAnyCallbackStruct *);
extern void annotateNormalMode(struct MOLECULE *);
extern int checkInterrupt(void);

PySpectrumSpecObject *spectrum_new(void);
static PyObject *spectrum_show(PyObject *, PyObject *);
/*static PyObject *spectrum_hide(PyObject *, PyObject *);*/
static PyObject *spectrum_mode(PyObject *, PyObject *);
static PyObject *spectrum_deselect(PyObject *, PyObject *);
static PyObject *spectrum_type(PyObject *, PyObject *);
static PyObject *spectrum_display(PyObject *, PyObject *);
static PyObject *spectrum_style(PyObject *, PyObject *);
static PyObject *spectrum_amplitude(PyObject *, PyObject *);
static PyObject *spectrum_scaleFactor(PyObject *, PyObject *);
static PyObject *spectrum_zoom(PyObject *, PyObject *);
static PyObject *spectrum_saveDrawing(PyObject *, PyObject *);
static PyObject *spectrum_getattr(PySpectrumSpecObject *, char *);
static void spectrum_dealloc(PySpectrumSpecObject *);

extern struct WINDOW windows[];
extern struct MOLECULE *molecules;
extern double amplitude, wnScale;
extern int nmolecule, animate, lines;

static char PySpectrumSpec_Type__doc__[] =
  "Spectrum specification";

statichere PyTypeObject PySpectrumSpec_Type = {
  PyObject_HEAD_INIT(NULL)
  0,                               /*ob_size*/
  "SpectrumSpec",                  /*tp_name*/
  sizeof(PySpectrumSpecObject),    /*tp_basicsize*/
  0,                               /*tp_itemsize*/
  /* methods */
  (destructor)spectrum_dealloc,    /*tp_dealloc*/
  0,                               /*tp_print*/
  (getattrfunc)spectrum_getattr,   /*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*/
  /* Space for future expansion */
  0L,0L,
  /* Documentation string */
  PySpectrumSpec_Type__doc__
};

static PyMethodDef spectrum_methods[] = {
  {"show",             spectrum_show,  1},
/*{"hide",             spectrum_hide,  1},*/
  {"mode",             spectrum_mode,  1},
  {"deselect",         spectrum_deselect,  1},
  {"type",             spectrum_type,  1},
  {"display",          spectrum_display,  1},
  {"style",            spectrum_style,  1},
  {"amplitude",        spectrum_amplitude,  1},
  {"scaleFactor",      spectrum_scaleFactor,  1},
  {"zoom",             spectrum_zoom,  1},
  {"saveDrawing",      spectrum_saveDrawing,  1},
  {NULL,               NULL}
};

PySpectrumSpecObject *spectrum_new(void)
{
  PySpectrumSpecObject *self;

  self=PyObject_NEW(PySpectrumSpecObject, &PySpectrumSpec_Type);
  if (self == NULL)
  {
    PyErr_NoMemory();
    return(NULL);
  }
  self->spectrumID=0;
  return(self);
}

static PyObject *spectrum_show(PyObject *self, PyObject *args)
{
  PySpectrumSpecObject *s;
  XmToggleButtonCallbackStruct data;
  int which, set_save;

  if (checkInterrupt()) return(NULL);
  if (!self)
  {
    Py_INCREF(Py_None);
    return(Py_None);
  }
  s=(PySpectrumSpecObject *)self;
  which=s->spectrumID;
  if (windows[SPECTRUM].widget == NULL)
  {
    set_save=windows[VIEWER].set;
    windows[VIEWER].set=which;
    initSpectrum((Widget)0, (caddr_t)0, (caddr_t)0);
    drawSpectrum((Widget)0, (caddr_t)0, (XmDrawingAreaCallbackStruct *)0);
    windows[VIEWER].set=set_save;
  }
  else
  {
    windows[SPECTRUM].set=which;
    if (nmolecule > 1)
    {
      data.set=TRUE;
      (void)selectMolecule((Widget)0, (XtPointer)&(windows[SPECTRUM].selectMenu[which]),
  				   &data);
    }
    redraw(SPECTRUM);
  }
  Py_INCREF(Py_None);
  return(Py_None);
}
/*
static PyObject *spectrum_hide(PyObject *self, PyObject *args)
{
  quitSpectrum((Widget)0, (caddr_t)0, (XmAnyCallbackStruct *)0);
  Py_INCREF(Py_None);
  return(Py_None);
}
*/
static PyObject *spectrum_mode(PyObject *self, PyObject *args)
{
  PySpectrumSpecObject *s;
  int which, mode=(-1);

  if (checkInterrupt()) return(NULL);
  if (!PyArg_ParseTuple(args, "|i", &mode)) return(NULL);

  s=(PySpectrumSpecObject *)self;
  which=s->spectrumID;
  if (mode == -1)                 /* get */
    return(PyInt_FromLong((long)molecules[which].mode+1));
  else                            /* set */
  {
    if (mode > 0 && mode <= molecules[which].nmodes)
    {
      molecules[which].mode=mode;
      annotateNormalMode(&molecules[which]);
      redraw(SPECTRUM);
      if (animate == ANIMATE) setAnimation(animate);
    }
    else
    {
      PyErr_SetString(PyExc_ValueError, "Mode out of range");
      return(NULL);
    }
    Py_INCREF(Py_None);
    return(Py_None);
  }
}

static PyObject *spectrum_deselect(PyObject *self, PyObject *args)
{
  PySpectrumSpecObject *s;
  int which;

  if (checkInterrupt()) return(NULL);
  s=(PySpectrumSpecObject *)self;
  which=s->spectrumID;
  molecules[which].mode=(-1);
  annotateNormalMode(&molecules[which]);
  redraw(SPECTRUM);
  Py_INCREF(Py_None);
  return(Py_None);
}

static PyObject *spectrum_type(PyObject *self, PyObject *args)
{
  XmToggleButtonCallbackStruct data;
  PySpectrumSpecObject *s;
  int which, set_save, type=(-1);

  if (checkInterrupt()) return(NULL);
  if (!PyArg_ParseTuple(args, "|i", &type)) return(NULL);

  s=(PySpectrumSpecObject *)self;
  which=s->spectrumID;
  if (type == -1)
    return(PyInt_FromLong((long)windows[SPECTRUM].mode));
  else
  {
    if (type != SPECTRUM_ALL && type != SPECTRUM_IR && 
    	  type != SPECTRUM_RAMAN && type != SPECTRUM_INS)
    {
      PyErr_SetString(PyExc_ValueError, "Type is unknown");
      return(NULL);
    }
    data.set=TRUE;
    set_save=windows[SPECTRUM].set;
    windows[SPECTRUM].set=which;
    GetMode((Widget)0, (caddr_t)type, &data);
    windows[SPECTRUM].set=set_save;
    redraw(SPECTRUM);
    Py_INCREF(Py_None);
    return(Py_None);
  }
}

static PyObject *spectrum_display(PyObject *self, PyObject *args)
{
  XmToggleButtonCallbackStruct data;
  PySpectrumSpecObject *s;
  int which, display=(-1);

  if (checkInterrupt()) return(NULL);
  if (!PyArg_ParseTuple(args, "|i", &display)) return(NULL);

  s=(PySpectrumSpecObject *)self;
  which=s->spectrumID;
  if (display == -1)
    return(PyInt_FromLong((long)animate));
  else
  {
    if (display != ANIMATE && display != ARROWS && display != DISTORT)
    {
      PyErr_SetString(PyExc_ValueError, "Type is unknown");
      return(NULL);
    }
    data.set=TRUE;
    GetAnimate((Widget)0, (caddr_t)display, &data);
    redraw(SPECTRUM);
    Py_INCREF(Py_None);
    return(Py_None);
  }
}

static PyObject *spectrum_style(PyObject *self, PyObject *args)
{
  XmToggleButtonCallbackStruct data;
  PySpectrumSpecObject *s;
  int which, style=(-1);

  if (checkInterrupt()) return(NULL);
  if (!PyArg_ParseTuple(args, "|i", &style)) return(NULL);

  s=(PySpectrumSpecObject *)self;
  which=s->spectrumID;
  if (style == (-1))
    return(PyInt_FromLong((long)lines));
  else
  {
    if (style != TRUE && style != FALSE)
    {
      PyErr_SetString(PyExc_ValueError, "Style is unknown");
      return(NULL);
    }
    data.set=TRUE;
    GetType((Widget)0, (caddr_t)style, &data);
    redraw(SPECTRUM);
    Py_INCREF(Py_None);
    return(Py_None);
  }
}

static PyObject *spectrum_amplitude(PyObject *self, PyObject *args)
{
  double a=400.0e0;

  if (checkInterrupt()) return(NULL);
  if (!PyArg_ParseTuple(args, "|d", &a)) return(NULL);

  if (a == 400.0e0)
    return(PyFloat_FromDouble(amplitude/windows[VIEWER].top));
  else
  {
    amplitude=a*windows[VIEWER].top;
    redraw(SPECTRUM);
    Py_INCREF(Py_None);
    return(Py_None);
  }
}

static PyObject *spectrum_scaleFactor(PyObject *self, PyObject *args)
{
  double sf=(-1.0e0);

  if (checkInterrupt()) return(NULL);
  if (!PyArg_ParseTuple(args, "|d", &sf)) return(NULL);

  if (sf == -1.0e0)
    return(PyFloat_FromDouble(wnScale));
  else
  {
    wnScale=sf;
    redraw(SPECTRUM);
    Py_INCREF(Py_None);
    return(Py_None);
  }
}

static PyObject *spectrum_zoom(PyObject *self, PyObject *args)
{
  double x1, x2, y1, y2;

  if (checkInterrupt()) return(NULL);
  if (!PyArg_ParseTuple(args, "dddd", &x1, &y1, &x2, &y2)) return(NULL);

  if (x1 == x2 || y1 == y2)
  {
    PyErr_SetString(PyExc_ValueError, "x1 and x2 as well as y1 and y2 have to be different");
    return(NULL);
  }
  saveZoom(SPECTRUM);
  windows[SPECTRUM].left=x1;
  windows[SPECTRUM].right=x2;
  windows[SPECTRUM].top=y1;
  windows[SPECTRUM].bottom=y2;
  setMenuItem(SPECTRUM_ZOOMOUT, True);
  redraw(SPECTRUM);
  Py_INCREF(Py_None);
  return(Py_None);
}

static PyObject *spectrum_saveDrawing(PyObject *self, PyObject *args)
{
  int format;
  char *filename;

  if (checkInterrupt()) return(NULL);
  if (!PyArg_ParseTuple(args, "is", &format, &filename)) return NULL;
  if (!access(filename, F_OK))
  {
    PyErr_SetString(PyExc_IOError, "File already exists.");
    return(NULL);
  }
  if (format != TIFFFILE && format != PNGFILE && format != HPGL &&
      format != POSTSCRIPT)
  {
    PyErr_SetString(PyExc_ValueError, "Format not recognised.");
    return(NULL);
  }
  saveDrawing(SPECTRUM, format, filename);
  Py_INCREF(Py_None);
  return(Py_None);
}

static void spectrum_dealloc(PySpectrumSpecObject *self)
{
  if (!self) return;
  PyMem_DEL(self);
  quitSpectrum((Widget)0, (caddr_t)0, (XmAnyCallbackStruct *)0);
  (void)checkInterrupt();
}

static PyObject *spectrum_getattr(PySpectrumSpecObject *self, char *name)
{
  return(Py_FindMethod(spectrum_methods, (PyObject *)self, name));
}

void initSpectrumModule(void)
{
  PyObject *module, *dict;
  static void *PySpectrum_API[PySpectrum_API_pointers];

  PySpectrumSpec_Type.ob_type=&PyType_Type;

  module=Py_InitModule("spectrum", spectrum_methods);
  dict=PyModule_GetDict(module);

  PySpectrum_API[PySpectrumSpec_Type_NUM]=(void *)&PySpectrumSpec_Type;
  PyDict_SetItemString(dict, "_C_API", PyCObject_FromVoidPtr((void *)PySpectrum_API, NULL));
  PyDict_SetItemString(dict, "ALLMODES", PyInt_FromLong(SPECTRUM_ALL));
  PyDict_SetItemString(dict, "IRMODES", PyInt_FromLong(SPECTRUM_IR));
  PyDict_SetItemString(dict, "RAMANMODES", PyInt_FromLong(SPECTRUM_RAMAN));
  PyDict_SetItemString(dict, "INSMODES", PyInt_FromLong(SPECTRUM_INS));
  PyDict_SetItemString(dict, "ANIMATE", PyInt_FromLong(ANIMATE));
  PyDict_SetItemString(dict, "ARROWS", PyInt_FromLong(ARROWS));
  PyDict_SetItemString(dict, "DISTORT", PyInt_FromLong(DISTORT));
  PyDict_SetItemString(dict, "LINES", PyInt_FromLong(TRUE));
  PyDict_SetItemString(dict, "GAUSSIANS", PyInt_FromLong(FALSE));
}
