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

#define PyAtom_API_pointers 1
#define PyAtomSpec_Type_NUM 0

PyAtomSpecObject *atom_new(void);
static PyObject *atom_getElement(PyObject *, PyObject *);
static PyObject *atom_coordinates(PyObject *, PyObject *);
static PyObject *atom_radius(PyObject *, PyObject *);
static PyObject *atom_radiusScaleFactor(PyObject *, PyObject *);
static PyObject *atom_neutronScatteringFactor(PyObject *, PyObject *);
static PyObject *atom_name(PyObject *, PyObject *);
static PyObject *atom_replace(PyObject *, PyObject *);
static PyObject *atom_delete(PyObject *, PyObject *);
static PyObject *atom_getattr(PyAtomSpecObject *, char *);
static void atom_dealloc(PyAtomSpecObject *);

extern PyElementSpecObject *element_new(void);
extern void buildMolecule(struct MOLECULE *, int, int, int);
extern int checkInterrupt(void);
extern void makeINSIntensity(void);

extern struct MOLECULE *molecules;
extern struct ELEMENT *elements;
extern int nmolecule, ne, element;

static char PyAtomSpec_Type__doc__[] =
  "Atom specification";

statichere PyTypeObject PyAtomSpec_Type = {
  PyObject_HEAD_INIT(NULL)
  0,                               /*ob_size*/
  "AtomSpec",                      /*tp_name*/
  sizeof(PyAtomSpecObject),        /*tp_basicsize*/
  0,                               /*tp_itemsize*/
  /* methods */
  (destructor)atom_dealloc,        /*tp_dealloc*/
  0,                               /*tp_print*/
  (getattrfunc)atom_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 */
  PyAtomSpec_Type__doc__
};

static PyMethodDef atom_methods[] = {
  {"getElement",                 atom_getElement, 1},
  {"coordinates",                atom_coordinates, 1},
  {"radius",                     atom_radius, 1},
  {"radiusScaleFactor",          atom_radiusScaleFactor, 1},
  {"neutronScatteringFactor",    atom_neutronScatteringFactor, 1},
  {"name",                       atom_name, 1},
  {"replace",                    atom_replace, 1},
  {"delete",                     atom_delete, 1},
  {NULL,                         NULL}
};

PyAtomSpecObject *atom_new(void)
{
  PyAtomSpecObject *self;

  self=PyObject_NEW(PyAtomSpecObject, &PyAtomSpec_Type);
  if (self == NULL)
  {
    PyErr_NoMemory();
    return(NULL);
  }
  self->moleculeID=0;
  self->atomID=0;
  return(self);
}

static PyObject *atom_getElement(PyObject *self, PyObject *args)
{
  PyAtomSpecObject *s;
  PyElementSpecObject *element;
  int imol, iatom;
  register int i;

  if (checkInterrupt()) return(NULL);
  if (!self)
  {
    Py_INCREF(Py_None);
    return(Py_None);
  }
  s=(PyAtomSpecObject *)self;
  imol=s->moleculeID;
  iatom=s->atomID;
  element=element_new();
  if (element == NULL) return(NULL);
  for (i=0; i<ne; i++)
  {
    if (!strncmp(molecules[imol].atoms[iatom].name, elements[i].symbol, 2))
    {
      element->elementID=i;
      return((PyObject *)element);
    }
  }
  for (i=0; i<ne; i++)
  {
    if (!strncmp(elements[i].symbol, "??", 2))
    {
      element->elementID=i;
      return((PyObject *)element);
    }
  }
  return(NULL);
}

static PyObject *atom_coordinates(PyObject *self, PyObject *args)
{
  PyAtomSpecObject *s;
  PyObject *tuple;
  int imol, iatom;
  double x=1.0e302, y=1.0e302, z=1.0e302;

  if (checkInterrupt()) return(NULL);
  if (!self)
  {
    Py_INCREF(Py_None);
    return(Py_None);
  }
  s=(PyAtomSpecObject *)self;
  imol=s->moleculeID;
  iatom=s->atomID;
  if (!PyArg_ParseTuple(args, "|ddd", &x, &y, &z)) return(NULL);
  if (x < 1.0e300 && y < 1.0e300 && z < 1.0e300)  /* set */
  {
    molecules[imol].atoms[iatom].x=x;
    molecules[imol].atoms[iatom].y=y;
    molecules[imol].atoms[iatom].z=z;
  }
  else
  {
    if ((tuple=PyTuple_New(4))) /* get */
    {
      PyTuple_SetItem(tuple, 0, PyFloat_FromDouble(molecules[imol].atoms[iatom].x));
      PyTuple_SetItem(tuple, 1, PyFloat_FromDouble(molecules[imol].atoms[iatom].y));
      PyTuple_SetItem(tuple, 2, PyFloat_FromDouble(molecules[imol].atoms[iatom].z));
      PyTuple_SetItem(tuple, 3, PyString_FromString(molecules[imol].atoms[iatom].name));
      return(tuple);
    }
  }
  Py_INCREF(Py_None);
  return(Py_None);
}

static PyObject *atom_radius(PyObject *self, PyObject *args)
{
  PyAtomSpecObject *s;
  double radius=-1.0e0;
  int imol, iatom;

  if (checkInterrupt()) return(NULL);
  if (!self)
  {
    Py_INCREF(Py_None);
    return(Py_None);
  }
  s=(PyAtomSpecObject *)self;
  imol=s->moleculeID;
  iatom=s->atomID;
  if (!PyArg_ParseTuple(args, "|d", &radius)) return(NULL);
  if (radius != -1.0e0) /* set */
  {
    if (radius >= 0.0)
      molecules[imol].atoms[iatom].rad=radius;
    else
    {
      PyErr_SetString(PyExc_ValueError, "Value out of range");
      return(NULL);
    }
  }
  else /* get */
    return(PyFloat_FromDouble(molecules[imol].atoms[iatom].rad));
  Py_INCREF(Py_None);
  return(Py_None);
}

static PyObject *atom_radiusScaleFactor(PyObject *self, PyObject *args)
{
  PyAtomSpecObject *s;
  double radScale=-1.0e0;
  int imol, iatom;

  if (checkInterrupt()) return(NULL);
  if (!self)
  {
    Py_INCREF(Py_None);
    return(Py_None);
  }
  s=(PyAtomSpecObject *)self;
  imol=s->moleculeID;
  iatom=s->atomID;
  if (!PyArg_ParseTuple(args, "|d", &radScale)) return(NULL);
  if (radScale != -1.0e0) /* set */
  {
    if (radScale >= 0.0)
      molecules[imol].atoms[iatom].radScale=radScale;
    else
    {
      PyErr_SetString(PyExc_ValueError, "Value out of range");
      return(NULL);
    }
  }
  else  /* get */
    return(PyFloat_FromDouble(molecules[imol].atoms[iatom].radScale));
  Py_INCREF(Py_None);
  return(Py_None);
}

static PyObject *atom_neutronScatteringFactor(PyObject *self, PyObject *args)
{
  PyAtomSpecObject *s;
  double factor=-1.0e0;
  int imol, iatom;

  if (checkInterrupt()) return(NULL);
  if (!self)
  {
    Py_INCREF(Py_None);
    return(Py_None);
  }
  s=(PyAtomSpecObject *)self;
  imol=s->moleculeID;
  iatom=s->atomID;
  if (!PyArg_ParseTuple(args, "|d", &factor)) return(NULL);
  if (factor != -1.0e0) /* set */
  {
    if (factor >= 0.0)
    {
      molecules[imol].atoms[iatom].neutronScatterfac=factor;
      makeINSIntensity();
    }
    else
    {
      PyErr_SetString(PyExc_ValueError, "Value out of range");
      return(NULL);
    }
  }
  else /* get */
    return(PyFloat_FromDouble(molecules[imol].atoms[iatom].neutronScatterfac));
  Py_INCREF(Py_None);
  return(Py_None);
}

static PyObject *atom_name(PyObject *self, PyObject *args)
{
  PyAtomSpecObject *s;
  int imol, iatom;
  char *n=NULL, name[MAXLENLINE];

  if (checkInterrupt()) return(NULL);
  if (!self)
  {
    Py_INCREF(Py_None);
    return(Py_None);
  }
  s=(PyAtomSpecObject *)self;
  imol=s->moleculeID;
  iatom=s->atomID;
  if (!PyArg_ParseTuple(args, "|s", &n)) return(NULL);
  if (n != NULL) /* set */
  {
    if (strlen(n) > 8)
    {
      PyErr_SetString(PyExc_ValueError, "Name is too long");
      return(NULL);
    }
    else
      strncpy(molecules[imol].atoms[iatom].name, n, 8);
  }
  else /* get */
  {
    sprintf(name, "%s%d", molecules[imol].atoms[iatom].name, iatom+1); 
    return(PyString_FromString(name));
  }
  Py_INCREF(Py_None);
  return(Py_None);
}

static PyObject *atom_replace(PyObject *self, PyObject *args)
{
  PyAtomSpecObject *s;
  int imol, iatom, i, found;
  char *symbol;

  if (checkInterrupt()) return(NULL);
  if (!self)
  {
    Py_INCREF(Py_None);
    return(Py_None);
  }
  s=(PyAtomSpecObject *)self;
  imol=s->moleculeID;
  iatom=s->atomID;
  if (!PyArg_ParseTuple(args, "s", &symbol)) return(NULL);
  symbol[0]=toupper(symbol[0]);
  symbol[1]=tolower(symbol[1]);
  found=FALSE;
  for (i=0; i<ne; i++)
  {
    if (!strncmp(elements[i].symbol, symbol, 2))
    {
      found=TRUE;
      break;
    }
  }
  if (found)
  {
    element=i;
    buildMolecule(&molecules[imol], iatom, REPLACE_ATOM, FALSE);
    Py_INCREF(Py_None);
    return(Py_None);
  }
  else
  {
    PyErr_SetString(PyExc_ValueError, "Element unknown");
    return(NULL);
  }
}

static PyObject *atom_delete(PyObject *self, PyObject *args)
{
  PyAtomSpecObject *s;
  int imol, iatom;

  if (checkInterrupt()) return(NULL);
  if (self)
  {
    s=(PyAtomSpecObject *)self;
    imol=s->moleculeID;
    iatom=s->atomID;
    buildMolecule(&molecules[imol], iatom, DELETE_ATOM, FALSE);
  }
  Py_INCREF(Py_None);
  return(Py_None);
}

static void atom_dealloc(PyAtomSpecObject *self)
{
  if (!self) return;
  PyMem_DEL(self);
}

static PyObject *atom_getattr(PyAtomSpecObject *self, char *name)
{
  return(Py_FindMethod(atom_methods, (PyObject *)self, name));
}

void initAtomModule(void)
{
  PyObject *module, *dict;
  static void *PyAtom_API[PyAtom_API_pointers];

  PyAtomSpec_Type.ob_type=&PyType_Type;

  module=Py_InitModule("atom", atom_methods);
  dict=PyModule_GetDict(module);

  PyAtom_API[PyAtomSpec_Type_NUM]=(void *)&PyAtomSpec_Type;
  PyDict_SetItemString(dict, "_C_API", PyCObject_FromVoidPtr((void *)PyAtom_API, NULL));
}
