/*******************************************************************************
*                                                                              *
*                                   Viewmol                                    *
*                                                                              *
*                                   T M . C                                    *
*                                                                              *
*                 Copyright (c) Joerg-R. Hill, October 2003                    *
*                                                                              *
********************************************************************************
*
* $Id: tm.c,v 1.7 2004/08/29 15:02:04 jrh Exp $
* $Log: tm.c,v $
* Revision 1.7  2004/08/29 15:02:04  jrh
* Release 2.4.1
*
* Revision 1.6  2003/11/07 11:17:02  jrh
* Release 2.4
*
* Revision 1.5  2000/12/10 15:17:50  jrh
* Release 2.3
*
* Revision 1.4  1999/05/24 01:27:41  jrh
* Release 2.2.1
*
* Revision 1.3  1999/02/07 21:57:41  jrh
* Release 2.2
*
* Revision 1.2  1998/01/26 00:49:38  jrh
* Release 2.1
*
* Revision 1.1  1996/12/10  18:44:15  jrh
* Initial revision
*
*/
#include<ctype.h>
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

#define MAXLENLINE 82
#define FALSE 0
#define TRUE  1

/* Prototypes */
int  main(int, char **);
void copyDataGroup(FILE *, FILE *, char *, char *, char *, int);
void readDataGroup(FILE *, FILE *, char *, char *, char *, int);
FILE *checkfile(FILE *, char *, char *);
void changeDs(char *);
void eof(int);

extern int  readFrame(FILE *, int, int, double, int, long *);
extern void *getmem(size_t, size_t);
extern void *expmem(void *, size_t, size_t);
extern void fremem(void **);

static char *buffer=NULL;

int main(int argc, char **argv)
{
  FILE *mainfile, *file=NULL;
  double *mode;
  long offset;
  char line[MAXLENLINE], copy[MAXLENLINE], fullpath[MAXLENLINE], *word;
  char *column[6], form[8], pointGroup[4];
  int n=0, version, atomsDone=FALSE, titleDone=FALSE, MOsDone=FALSE, msi=FALSE;
  size_t nmodes=100;
  register int i, j;

  if (!strcmp(argv[1], "-msi"))
  {
    msi=TRUE;
    i=2;
  }
  else
    i=1;
  if ((mainfile=fopen(argv[i], "r")) == NULL)
  {
    printf("$error noFile 1 %s\n", argv[i]);
    printf("$end\n");
    exit(-1);
  }
  if ((word=strrchr(argv[i], '/')) != NULL)
  {
    strncpy(fullpath, argv[i], (int)(word-argv[i]));
    fullpath[(int)(word-argv[i])]='\0';
  }
  else
    strcpy(fullpath, ".");
  while (fgets(line, MAXLENLINE, mainfile) != NULL)
  {
    if (line[0] == '#')
      continue;
    else if (strstr(line, "$coord") && !strstr(line, "update"))
    {
      if (strstr(line, "type=car") != NULL)
      {
        if ((file=checkfile(mainfile, line, fullpath)) != NULL)
        {
          if (strstr(line, "!BIOSYM archive") == NULL)
          {
            printf("$error wrongReference 1 %s\n", argv[i]);
            printf("$end\n");
            exit(-1);
          }
          sscanf(line+15, "%d", &version);
          if (version != 3)
          {
            printf("$error unsupportedVersion 1 %d\n", version);
            printf("$end\n");
            exit(-1);
          }
          fgets(line, MAXLENLINE, file);
          readFrame(file, FALSE, TRUE, 0.52917706, version, &offset);
          titleDone=TRUE;
        }
        else
        {
          printf("$end\n");
          exit(-1);
        }
      }
      else
        copyDataGroup(mainfile, file, line, "$coord 0.52917706", fullpath,
                      MOsDone);
    }
    else if (strstr(line, "$title") && !titleDone)
      copyDataGroup(mainfile, file, line, "$title", fullpath, MOsDone);
    else if (strstr(line, "$symmetry"))
    {
      printf("%s", line);
      word=strtok(line, " \t");
      word=strtok(NULL, " \t");
      strcpy(pointGroup, word);
      if ((word=strrchr(pointGroup, '\n')) != NULL) *word='\0';
    }
    else if (strstr(line, "$vibrational spectrum"))
    {
      if ((file=checkfile(mainfile, line, fullpath)) != NULL)
      {
        if (file != mainfile)
        {
          while (fgets(line, MAXLENLINE, file) != NULL)
            if (strstr(line, "$vibrational spectrum")) break;
        }
        printf("$vibrational spectrum\n");
        if (fgets(line, MAXLENLINE, file) != NULL)
        {
          while (line[0] != '$')
          {
             if (line[0] != '#')
            {
              column[0]=strtok(line, " \t\n");
              column[1]=strtok(NULL, " \t\n");
              column[2]=strtok(NULL, " \t\n");
              column[3]=strtok(NULL, " \t\n");
	      if (column[3] == NULL)
	      {
                column[1][0]=(char)toupper(column[1][0]);
                printf("%s %s 1.0000000 1.0000000\n", column[1], column[2]);
	      }
	      else
	      {
                column[4]=strtok(NULL, " \t\n");
                column[5]=strtok(NULL, " \t\n");
                if (*column[4] != '-')
                {
                  column[1][0]=(char)toupper(column[1][0]);
                  printf("%s %s %s ", column[1], column[2], column[3]);
                  if (strstr(column[5], "NO"))
                    printf("0.0000000\n");
                  else
                    printf("1.0000000\n");
                }
                else
                  printf("- %s %s 0.0000000\n", column[1], column[2]);
	      }
            }
            if (fgets(line, MAXLENLINE, file) == NULL) break;
          }
        }
        if (file != mainfile) fclose(file);
        fseek(file, -strlen(line), SEEK_CUR);
      }
    }
    else if (strstr(line, "$vibrational normal modes"))
    {
      if (msi)      /* in MSI's version the normal modes are transposed */
      {
        if ((file=checkfile(mainfile, line, fullpath)) != NULL)
        {
          if (file != mainfile)
          {
            while (fgets(line, MAXLENLINE, file) != NULL)
                if (strstr(line, "$vibrational normal modes")) break;
          }
          printf("$vibrational normal modes\n");
          mode=(double *)getmem(nmodes, sizeof(double));
          i=0;
          if (fgets(line, MAXLENLINE, file) != NULL)
          {
            while (line[0] != '$')
            {
              if (line[0] != '#')
              {
                strtok(line, " \t");
                strtok(NULL, " \t");
                while ((word=strtok(NULL, " \t")) != NULL)
                {
                  mode[i++]=atof(word);
                  if (i >= nmodes)
                  {
                    nmodes+=100;
                    mode=(double *)expmem((void *)mode, nmodes, sizeof(double));
                  }
                }
              }
              if (fgets(line, MAXLENLINE, file) == NULL) break;
            }
          }
          nmodes=(int)(sqrt((double)i));
          for (i=0; i<nmodes; i++)
          {
            printf("%3d %3d ", i+1, 1);
            for (j=0; j<nmodes; j++)
            {
              printf("%14.10f", mode[j*nmodes+i]);
              if ((j+1) % 5 == 0) printf("\n%3d %3d ", i+1, j+1);
            }
            printf("\n");
          }
          fremem((void **)&mode);
        }
        if (file != mainfile) fclose(file);
        fseek(file, -strlen(line), SEEK_CUR);
      }
      else
        copyDataGroup(mainfile, file, line, "$vibrational normal modes",
                      fullpath, MOsDone);
    }
    else if (strstr(line, "$grad"))
    {
      if ((file=checkfile(mainfile, line, fullpath)) != NULL)
      {
        printf("%s\n", line);
        if (fgets(line, MAXLENLINE, file) == NULL) eof(MOsDone);
        while (line[0] != '$')
        {
          if (line[0] != '#')
          {
            strcpy(copy, line);
            strtok(copy, " ");
            strtok(NULL, " ");
            strtok(NULL, " ");
            if (strtok(NULL, " ") == NULL)
            {
              changeDs(line);
              printf("%s\n", line);
            }
            else
              printf("%s", line);
          }
          if (fgets(line, MAXLENLINE, file) == NULL) eof(MOsDone);
        }
        if (file != mainfile) fclose(file);
        fseek(file, -strlen(line), SEEK_CUR);
      }
    }
    else if (strstr(line, "$scfmo") || strstr(line, "uhfmo_alpha") ||
             strstr(line, "uhfmo_beta"))
    {
      if ((file=checkfile(mainfile, line, fullpath)) != NULL)
      {
        if (!strstr(line, "conv") && !strstr(line, "firstorder"))
        {
          printf("$error notConverged 0 control\n");
          if (file != mainfile) fclose(file);
          continue;
        }
        if (!strcmp(pointGroup, "c1"))
          printf("%s\n", line);
        else
          printf("%s symmetrized\n", line);
        if ((word=strchr(line, '.')) != NULL)
        {
          *word--='\0';
          while (isdigit(*word)) word--;
          n=atoi(++word);
          sprintf(form, "%%.%ds ", n);
        }
        if (fgets(line, MAXLENLINE, file) == NULL) eof(MOsDone);
        while (line[0] != '$')
        {
          if (line[0] != '#')
          {
            if (strstr(line, "eigenvalue"))
            {
              changeDs(line);
              printf("%s\n", line);
            }
            else
            {
              changeDs(line);
              word=line;
              while (word-strlen(line) < line)
              {
                printf(form, word);
                word+=n;
              }
              printf("\n");
            }
          }
          if (fgets(line, MAXLENLINE, file) == NULL) eof(MOsDone);
        }
        if (file != mainfile) fclose(file);
        fseek(file, -strlen(line), SEEK_CUR);
        MOsDone=TRUE;
      }
    }
    else if (strstr(line, "$closed shells"))
      readDataGroup(mainfile, file, line, "$closed shells", fullpath, MOsDone);
    else if (strstr(line, "$alpha shells"))
      readDataGroup(mainfile, file, line, "$alpha shells", fullpath, MOsDone);
    else if (strstr(line, "$beta shells"))
      readDataGroup(mainfile, file, line, "$beta shells", fullpath, MOsDone);
    else if (strstr(line, "$atoms"))
    {
      copyDataGroup(mainfile, file, line, "$atoms", fullpath, MOsDone);
      atomsDone=TRUE;
    }
    else if (strstr(line, "$basis"))
    {
      if (atomsDone)
        copyDataGroup(mainfile, file, line, "$basis", fullpath, MOsDone);
      else
        readDataGroup(mainfile, file, line, "$basis", fullpath, MOsDone);
    }
    else if (strstr(line, "$pople"))
    {
      if (strstr(line, "CAO")) printf("$pople 6d/10f/15g\n");
      else                     printf("$pople 5d/7f/9g\n");
    }
    else if (strstr(line, "$grid"))
    {
      printf("%s", line);
      i=TRUE;
      while ((fgets(line, MAXLENLINE, mainfile)) != NULL)
      {
        if (line[0] == '$') break;
        if (i)
        {
          printf(" type %s", line);
          i=FALSE;
        }
        if (strstr(line, "outfile"))
        {
          if ((file=checkfile(mainfile, line, fullpath)) != NULL)
          {
            line[0]=' ';
            printf("%s\n", line);
            while ((fgets(line, MAXLENLINE, file)) != NULL)
            {
              if (strstr(line, "$m") || strstr(line, "$end")) break;
              if (strstr(line, "$origin") || strstr(line, "$vector") || 
                  strstr(line, "$grid") || strstr(line, "$title") ||
                  strstr(line, "$plotdata")) line[0]=' ';
              changeDs(line);
              printf("%s\n", line);
            }
            fclose(file);
          }
        }
      }
      fseek(mainfile, -strlen(line), SEEK_CUR);
    }
  }
  eof(MOsDone);
  return(0);
}

void copyDataGroup(FILE *mainfile, FILE *file, char *line, char *dataGroup,
                   char *fullpath, int MOsDone)
{
  int found;
  char l[MAXLENLINE];

  if ((file=checkfile(mainfile, line, fullpath)) != NULL)
  {
    strcpy(l, dataGroup);
    strtok(l, " ");
    if (file != mainfile && !strstr(line, l))
    {
      found=FALSE;
      while (fgets(line, MAXLENLINE, file) != NULL)
      {
        if (strstr(line, dataGroup))
        {
          found=TRUE;
          break;
        }
      }
      if (!found)
      {
        fclose(file);
        return;
      }
    }
    printf("%s\n", dataGroup);
    if (fgets(line, MAXLENLINE, file) == NULL)
      if (file == mainfile) eof(MOsDone);
    while (line[0] != '$')
    {
      if (line[0] != '#') printf("%s", line);
      if (fgets(line, MAXLENLINE, file) == NULL)
        if (file == mainfile) eof(MOsDone);
    }
    if (file != mainfile) fclose(file);
    else fseek(file, -strlen(line), SEEK_CUR);
  }
}

void readDataGroup(FILE *mainfile, FILE *file, char *line, char *dataGroup,
                   char *fullpath, int MOsDone)
{
  static size_t bufsiz=1000;

  if (buffer == NULL) buffer=(char *)getmem(bufsiz, sizeof(char));

  if ((file=checkfile(mainfile, line, fullpath)) != NULL)
  {
    strcat(buffer, dataGroup);
    strcat(buffer, "\n");
    if (fgets(line, MAXLENLINE, file) == NULL) eof(MOsDone);
    while (line[0] != '$')
    {
      if (line[0] != '#')
      {
        if (strlen(buffer)+strlen(line) < bufsiz)
          strcat(buffer, line);
        else
        {
          bufsiz+=1000;
          buffer=(char *)expmem((void *)buffer, bufsiz, sizeof(char));
          strcat(buffer, line);
        }
      }
      if (fgets(line, MAXLENLINE, file) == NULL) eof(MOsDone);
    }
    if (file != mainfile) fclose(file);
    fseek(file, -strlen(line), SEEK_CUR);
  }
}

FILE *checkfile(FILE *mainfile, char *line, char *fullpath)
{
  FILE *file;
  char *filename, l[MAXLENLINE], *word;

  if ((word=strrchr(line, '\n')) != NULL) *word='\0';
  if (strstr(line, "file"))
  {
    filename=strchr(line, '=')+1;
    while (isspace(*filename)) filename++;
    if ((word=strchr(filename, ' ')) != NULL) *word='\0';
    strcpy(l, fullpath);
    strcat(l, "/");
    strcat(l, filename);
    filename=l;
    if ((file=fopen(filename, "r")) == NULL)
    {
      if (strstr(line, "$coord"))
         printf("$error noFile 1 %s\n", filename);
      else
         printf("$error noFile 0 %s\n", filename);
    }
    else
    {
      fgets(l, MAXLENLINE, file);
      strcpy(line, l);
      if ((word=strrchr(line, '\n')) != NULL) *word='\0';
    }
    return(file);
  }
  else
    return(mainfile);
}

void changeDs(char *line)
{
  char *p;

  p=line;
  while (*p != '\0')
  {
    if (*p == 'D') *p='e';
    if (*p == '\n') *p='\0';
    p++;
  }
}

void eof(int MOsDone)
{
  register char *p1, *p2;

  if (buffer != NULL)
  {
    if (!MOsDone)
    {
      if ((p1=strstr(buffer, "$closed shells")) != NULL)
      {
        if ((p2=strchr(p1+1, '$')) != NULL)
        {
          (void)memmove(p1, (const char *)p2, strlen(p2));
          p1+=strlen(p2);
          *p1='\0';
        }
        else
        {
          fremem((void **)&buffer);
          printf("$end\n");
          exit(0);
        }
      }
    }
    printf("%s", buffer);
    fremem((void **)&buffer);
  }
  printf("$end\n");
  exit(0);
}
