/* MACHINE GENERATED FILE, DO NOT EDIT! */

#define VMDPLUGIN molfile_moldenplugin
#define STATIC_PLUGIN 1

/***************************************************************************
 *cr
 *cr            (C) Copyright 1995-2009 The Board of Trustees of the
 *cr                        University of Illinois
 *cr                         All Rights Reserved
 *cr
 ***************************************************************************/

/***************************************************************************
 * RCS INFORMATION:
 *
 *      $RCSfile: moldenplugin.c,v $
 *      $Author: johns $       $Locker:  $             $State: Exp $
 *      $Revision: 1.14 $       $Date: 2009/04/29 15:45:31 $
 *
 ***************************************************************************/

/* This is a plugin that will read input from a MOLDEN
** generated output file 
** some more details will go here soon 
** NOTE: The current version of the plugin relies
** on the fact that the [Atom] field comes before
** the [Geometries] field */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "molfile_plugin.h"



typedef struct {
  FILE *file;
  int trajectory;
  int numatoms;
  char *file_name;
  molfile_atom_t *atomlist;
} moldendata;

/* this will skip one line at a time */

static void eatline(FILE * fd)
{
  char readbuf[1025];
  fgets(readbuf, 1024, fd);
}

 
static void *open_molden_read(const char *filename, const char *filetype, int *natoms) {

  FILE *fd;
  moldendata *data;
  char moldentest1[7];
  char moldentest2[7];
  char buffer[1024];
  char tester[20];
  int i;
  char *s;

  fd = fopen(filename, "rb");
  if (!fd) return NULL;
  
  data = (moldendata *)malloc(sizeof(moldendata));
  data->file = fd;
  data->file_name = strdup(filename);

/* check if the file is MOLDEN format */

  fscanf(data->file, "%s %s",moldentest1,moldentest2);
  if (!strcmp(moldentest1,"[Molden") && \
      !strcmp(moldentest2,"Format]"))
  {
    printf("Detected MOLDEN file format!\n");
  }
  else
  {
    printf("The file does not seem to be in MOLDEN format!\n");
    return NULL;
  }

/* Unfortunately the molden file format has two possibilities:
** either there is a [ATOMS] section which provides the atom
** name, charges and coordinates or there is only a 
** XYZ style [GEOMETRIES] section, which still provides atom
** type and geometry information, hence I have to check which
** case I have */
  
/* check if there is an [ATOMS] section */

  do
  {
    i=fscanf(data->file, "%s",tester); 
    if (!strcmp(tester,"[Atoms]"))
    {
/* start counting the atoms; 
** read until I hit the first line that starts with a "["
** bracket */

      eatline(fd); 
      (*natoms)=0; 
      s=fgets(buffer,1024,fd);

/* Here I assume that the [Atoms] section goes
** on until another section starts, i.e. ther is
** a "[" or I encounter EOF */

      while ((buffer[0]!='[') && (s != NULL))
      {
       	(*natoms)++;     
	s=fgets(buffer,1024,fd);
      }
      data->numatoms=*natoms;
      rewind(fd);
      data->trajectory = 0;
      return data;
    }
    else if (!strcmp(tester,"[GEOMETRIES]"))
    {
      printf("Found [Geometry] section ...\n");
      data->trajectory = 1;	    
       
/* In this case I am lucky because the first line
** of the XYZ type [GEOMETRIES] input contains the
** number of atoms, i.e. skip to this line and the
** read this entry */

      eatline(fd);

      i=fscanf(data->file, "%d",natoms);
      if (i!=1)
      {
	printf("The [GEOMTRIES] output does not have \n");
	printf("the number of atoms in line number one !! \n");
      }

      data->numatoms=*natoms;
     
/* skip the next two lines, so the file can be parsed in the 
** structure section */      

      eatline(fd);
      eatline(fd);

      return data; 
    }
   } while (i>0);
  
  return NULL;
}

static int read_molden_structure(void *mydata, int *optflags, 
    molfile_atom_t *atoms) 
 {
  int i;
  char atname[1024];
  char buffer[1024];
  char geotest[11];
  int num,charge;
  float x,y,z;
  molfile_atom_t *atom;
  moldendata *data = (moldendata *)mydata;

  *optflags = MOLFILE_NOOPTIONS; /* no optional data */

/* here I have two possibilities, either there is an
** [Atoms] section (i.e. data->trajectory=0) and I can
** read there structure information right there,
** or I have to extract it from the [GEOMETRIES]
** output (i.e. data->trajectory=1) */

  if(data->trajectory==0)
  { 

/* Skip the first three lines */

    eatline(data->file);
    eatline(data->file);

/* Now read in the atom types, names, charges as well
** as x,y,z coordinates */

    for(i=0;i<data->numatoms;i++) 
    {
      atom = atoms+i;
      fgets(buffer,1024,data->file);    
      sscanf(buffer,"%s %d %d %f %f %f",atname,&num,&charge,\
	  &x,&y,&z);
      strncpy(atom->name,atname,sizeof(atom->name)); 
      strncpy(atom->type, atom->name, sizeof(atom->type));
      atom->resname[0] = '\0';
      atom->resid = 1;
      atom->chain[0] = '\0';
      atom->segid[0] = '\0';
    }


/* finally and important skip the the beginning of the xyz
** section */

    do 
    {
      fscanf(data->file, "%s",geotest);   
    } while (strcmp(geotest,"[GEOMETRIES]")!=0);
  
     printf("Found Geometry Section\n");

  /* advance to the beginning of the XYZ list */

    eatline(data->file);
    eatline(data->file);
    eatline(data->file); 

/* time to go back */

    return MOLFILE_SUCCESS; 
  }
  else if(data->trajectory==1)
  {
    
/* in the read section I already forwarded to the correct
** location in the file hence I can start reading right
** away */


    for(i=0;i<data->numatoms;i++) 
    {
      atom = atoms+i;
      fgets(buffer,1024,data->file);    
      sscanf(buffer,"%s %f %f %f",atname,&x,&y,&z);
      strncpy(atom->name,atname,sizeof(atom->name)); 
      strncpy(atom->type, atom->name, sizeof(atom->type));
      atom->resname[0] = '\0';
      atom->resid = 1;
      atom->chain[0] = '\0';
      atom->segid[0] = '\0';
    }

/* now rewind the file and go back to the [GEOMETRIES]
** section */

    rewind(data->file);
    
    do 
    {
      fscanf(data->file, "%s",geotest);   
    } while (strcmp(geotest,"[GEOMETRIES]")!=0);
  
     printf("Found Geometry Section\n");

/* advance to the beginning of the XYZ list */

     eatline(data->file);
     eatline(data->file);
     eatline(data->file);

/* time to go back */

     return MOLFILE_SUCCESS;

   }

  printf("Sorry, could not obtain structure information \n");
  printf("from either the [Atoms] or [GEOMETRIES] section! \n");
  printf("Please check your MOLDEN output file! \n"); 
  return MOLFILE_ERROR; 
}


static int read_next_timestep(void *mydata, int natoms, molfile_timestep_t *ts) {

  int i;
  char *k;
  char atname[1024];
  char buffer[1024];
  float x, y, z;
  
  moldendata *data = (moldendata *)mydata;
  
/* read the coordinates */

  for(i=0;i<data->numatoms;i++) 
  {
      k=fgets(buffer,1024,data->file);
      sscanf(buffer,"%s %f %f %f",atname,&x,&y,&z);

/* save coordinates only if given a timestep pointer
** otherwise assume that VMD would like to skip past
** it */

/* if I don't check for EOF file I get stuck in
** an infinite loop */

      if ( k==NULL)
      {
	return MOLFILE_ERROR;
      }
      
      if (ts!=NULL) 
      {
       ts->coords[3*i  ] = x;
       ts->coords[3*i+1] = y;
       ts->coords[3*i+2] = z;     
      } 
  }     

/* skip the two comment lines, which separate
** the individual coordinate entries 
** (for now, cause contains useful information
** like energies) */

  eatline(data->file);
  eatline(data->file); 

/* done and go back */

  return MOLFILE_SUCCESS;
}
  

static void close_molden_read(void *mydata) {
  moldendata *data = (moldendata *)mydata;
  fclose(data->file);
  free(data->file_name);
  free(data);
}


/* registration stuff */
static molfile_plugin_t plugin;

VMDPLUGIN_API int VMDPLUGIN_init() {
  memset(&plugin, 0, sizeof(molfile_plugin_t));
  plugin.abiversion = vmdplugin_ABIVERSION;
  plugin.type = MOLFILE_PLUGIN_TYPE;
  plugin.name = "molden";
  plugin.prettyname = "Molden";
  plugin.author = "Markus Dittrich";
  plugin.majorv = 0;
  plugin.minorv = 2;
  plugin.is_reentrant = VMDPLUGIN_THREADSAFE;
  plugin.filename_extension = "molden";
  plugin.open_file_read = open_molden_read;
  plugin.read_structure = read_molden_structure;
  plugin.read_next_timestep = read_next_timestep;
  plugin.close_file_read = close_molden_read;
  return VMDPLUGIN_SUCCESS;
}

VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
  (*cb)(v, (vmdplugin_t *)&plugin);
  return VMDPLUGIN_SUCCESS;
}

VMDPLUGIN_API int VMDPLUGIN_fini() {
  return VMDPLUGIN_SUCCESS;
}

