/*******************************************************************************
*                                                                              *
*                                   Viewmol                                    *
*                                                                              *
*                    E N E R G Y L E V E L M O D U L E . C                     *
*                                                                              *
*                 Copyright (c) Joerg-R. Hill, October 2003                    *
*                                                                              *
********************************************************************************
*
* $Id: energylevelmodule.c,v 1.2 2003/11/07 11:01:28 jrh Exp $
* $Log: energylevelmodule.c,v $
* Revision 1.2  2003/11/07 11:01:28  jrh
* Release 2.4
*
* Revision 1.1  2000/12/10 15:05:56  jrh
* Initial revision
*
*/     
#include<stdio.h>
#include<unistd.h>
#include<Xm/DrawingA.h>
#include<Xm/PushBG.h>
#include<Xm/SeparatoG.h>
#include<Xm/ToggleBG.h>
#include "viewmol.h"

#define PyEnergyLevel_API_pointers 1
#define PyEnergyLevelSpec_Type_NUM 0

extern void initSpectrum(Widget, caddr_t, caddr_t);
extern void initMODiagram(Widget, caddr_t, caddr_t);
extern void initHistory(Widget, caddr_t, caddr_t);
extern void GetUnit(Widget, struct TOGGLE *, XmToggleButtonCallbackStruct *);
extern void setMenuItem(int, int);
extern void setupEnergyUnits(struct TOGGLE *);
extern void drawMODiagram(Widget, caddr_t, XmDrawingAreaCallbackStruct *);
extern void selectMolecule(Widget, caddr_t, XmToggleButtonCallbackStruct *);
extern void redraw(int);
extern void saveDrawing(int, int, char *);
extern int  checkInterrupt(void);
extern void quitMODiagram(Widget, caddr_t, XmAnyCallbackStruct *);

PyEnergyLevelSpecObject *energylevels_new(void);
static PyObject *energylevels_show(PyObject *, PyObject *);
static PyObject *energylevels_unit(PyObject *, PyObject *);
static PyObject *energylevels_resolution(PyObject *, PyObject *);
static PyObject *energylevels_mode(PyObject *, PyObject *);
static PyObject *energylevels_selectMO(PyObject *, PyObject *);
static PyObject *energylevels_deselect(PyObject *, PyObject *);
static PyObject *energylevels_saveDrawing(PyObject *, PyObject *);
static PyObject *energylevels_getattr(PyEnergyLevelSpecObject *, char *);
static void energylevels_dealloc(PyEnergyLevelSpecObject *);

extern struct WINDOW windows[];
extern struct MOLECULE *molecules;
extern double denres;
extern int nmolecule, showForces, showInertia, label;

static char PyEnergyLevelSpec_Type__doc__[] =
  "Energy level specification";

statichere PyTypeObject PyEnergyLevelSpec_Type = {
  PyObject_HEAD_INIT(NULL)
  0,                                 /*ob_size*/
  "EnergyLevelSpec",                 /*tp_name*/
  sizeof(PyEnergyLevelSpecObject),   /*tp_basicsize*/
  0,                                 /*tp_itemsize*/
  /* methods */
  (destructor)energylevels_dealloc,  /*tp_dealloc*/
  0,                                 /*tp_print*/
  (getattrfunc)energylevels_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 */
  PyEnergyLevelSpec_Type__doc__
};

static PyMethodDef energylevels_methods[] = {
  {"show",             energylevels_show,  1},
  {"unit",             energylevels_unit, 1},
  {"resolution",       energylevels_resolution, 1},
  {"mode",             energylevels_mode, 1},
  {"selectMO",         energylevels_selectMO, 1},
  {"deselect",         energylevels_deselect, 1},
  {"saveDrawing",      energylevels_saveDrawing, 1},
  {NULL,               NULL}
};

PyEnergyLevelSpecObject *energylevels_new(void)
{
  PyEnergyLevelSpecObject *self;

  self=PyObject_NEW(PyEnergyLevelSpecObject, &PyEnergyLevelSpec_Type);
  if (self == NULL)
  {
    PyErr_NoMemory();
    return(NULL);
  }
  self->energyLevelID=0;
  return(self);
}

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

  if (checkInterrupt()) return(NULL);
  if (!self)
  {
    Py_INCREF(Py_None);
    return(Py_None);
  }
  s=(PyEnergyLevelSpecObject *)self;
  which=s->energyLevelID;
  if (windows[MO].widget == NULL)
  {
    set_save=windows[VIEWER].set;
    windows[VIEWER].set=which;
    initMODiagram((Widget)0, (caddr_t)0, (caddr_t)0);
    windows[VIEWER].set=set_save;
  }
  else
  {
    windows[MO].set=which;
    if (nmolecule > 1)
    {
      data.set=TRUE;
      (void)selectMolecule((Widget)0, (XtPointer)&(windows[MO].selectMenu[which]),
                           &data);
    }
    redraw(MO);
  }
  Py_INCREF(Py_None);
  return(Py_None);
}

static PyObject *energylevels_unit(PyObject *self, PyObject *args)
{
  PyEnergyLevelSpecObject *s;
  XmToggleButtonCallbackStruct data;
  struct TOGGLE toggle[4];
  int which, unit=0, set_save;

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

  s=(PyEnergyLevelSpecObject *)self;
  which=s->energyLevelID;
  if (unit == 0)        /* get */
    return(PyInt_FromLong((long)unit));
  else                  /* set */
  {
    if (unit != HARTREE && unit != KJ_MOL && unit != EV && unit != CM)
    {
      PyErr_SetString(PyExc_ValueError, "Unknown unit for energy levels");
      return(NULL);
    }
    setupEnergyUnits(toggle);
    data.set=TRUE;
    set_save=windows[MO].set;
    windows[MO].set=which;
    GetUnit((Widget)0, &toggle[unit-1], &data);
    windows[MO].set=set_save;
    redraw(MO);
    Py_INCREF(Py_None);
    return(Py_None);
  }
}

static PyObject *energylevels_resolution(PyObject *self, PyObject *args)
{
  double res=-1.0e0;

  if (checkInterrupt()) return(NULL);
  if (!PyArg_ParseTuple(args, "|d", &res)) return(NULL);
  if (res == -1.0e0)      /* get */
    return(PyFloat_FromDouble(denres));
  else                    /* set */
  {
    if (res < 0.0e0)
    {
	PyErr_SetString(PyExc_ValueError, "Resolution for density must be greater than zero");
	return(NULL);
    }
    denres=res;
    redraw(MO);
    Py_INCREF(Py_None);
    return(Py_None);
  }
}

static PyObject *energylevels_mode(PyObject *self, PyObject *args)
{
  int mode=0;

  if (checkInterrupt()) return(NULL);
  if (!PyArg_ParseTuple(args, "|i", &mode)) return(NULL);
  if (mode == 0)       /* get */
    return(PyInt_FromLong((long)windows[MO].mode));
  else                 /* set */
  {
    if (mode != DENSITY_OF_STATES && mode != ENERGY_LEVELS)
    {
	PyErr_SetString(PyExc_ValueError, "Unknown drawing mode for energy levels");
	return(NULL);
    }
    windows[MO].mode=mode;
    drawMODiagram((Widget)0, (caddr_t)0, (XmDrawingAreaCallbackStruct *)0);
    redraw(MO);
    Py_INCREF(Py_None);
    return(Py_None);
  }
}

static PyObject *energylevels_selectMO(PyObject *self, PyObject *args)
{
  PyEnergyLevelSpecObject *s;
  int which, set_save, i, j=0;

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

  s=(PyEnergyLevelSpecObject *)self;
  which=s->energyLevelID;
  i--;
  j--;
  if (i < 0  || i > molecules[which].nbasfu ||
	j < -1 || j > molecules[which].nbasfu)
  {
    PyErr_SetString(PyExc_ValueError, "Number of MO out of range");
    return(NULL);
  }
  if (j != (-1))
  {
    molecules[which].imo=j;
    molecules[which].imosave=i;
  }
  else
    molecules[which].imo=i;
  set_save=windows[MO].set;
  windows[MO].set=which;
  redraw(MO);
  windows[MO].set=set_save;
  Py_INCREF(Py_None);
  return(Py_None);
}

static PyObject *energylevels_deselect(PyObject *self, PyObject *args)
{
  PyEnergyLevelSpecObject *s;
  int which, set_save;

  if (checkInterrupt()) return(NULL);

  s=(PyEnergyLevelSpecObject *)self;
  which=s->energyLevelID;
  molecules[which].imo=(-1);
  molecules[which].imosave=(-1);
  set_save=windows[MO].set;
  windows[MO].set=which;
  redraw(MO);
  windows[MO].set=set_save;
  Py_INCREF(Py_None);
  return(Py_None);
}

static PyObject *energylevels_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(MO, format, filename);
  Py_INCREF(Py_None);
  return(Py_None);
}

static void energylevels_dealloc(PyEnergyLevelSpecObject *self)
{
  if (!self) return;
  PyMem_DEL(self);
  quitMODiagram((Widget)0, (caddr_t)0, (XmAnyCallbackStruct *)0);
  (void)checkInterrupt();
}

static PyObject *energylevels_getattr(PyEnergyLevelSpecObject *self, char *name)
{
  return(Py_FindMethod(energylevels_methods, (PyObject *)self, name));
}

void initEnergyLevelModule(void)
{
  PyObject *module, *dict;
  static void *PyEnergyLevel_API[PyEnergyLevel_API_pointers];

  PyEnergyLevelSpec_Type.ob_type=&PyType_Type;

  module=Py_InitModule("energylevels", energylevels_methods);
  dict=PyModule_GetDict(module);

  PyEnergyLevel_API[PyEnergyLevelSpec_Type_NUM]=(void *)&PyEnergyLevelSpec_Type;
  PyDict_SetItemString(dict, "_C_API", PyCObject_FromVoidPtr((void *)PyEnergyLevel_API, NULL));
  PyDict_SetItemString(dict, "HARTREE", PyInt_FromLong((long)HARTREE));
  PyDict_SetItemString(dict, "KJ/MOL", PyInt_FromLong((long)KJ_MOL));
  PyDict_SetItemString(dict, "EV", PyInt_FromLong((long)EV));
  PyDict_SetItemString(dict, "1/CM", PyInt_FromLong((long)CM));
  PyDict_SetItemString(dict, "DENSITY_OF_STATES", PyInt_FromLong((long)DENSITY_OF_STATES));
  PyDict_SetItemString(dict, "ENERGY_LEVELS", PyInt_FromLong((long)ENERGY_LEVELS));
}
