/* Read data set from a .cube file */

/* Copyright (c) 2014--2023 MJ Rutter 
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3
 * of the Licence, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see http://www.gnu.org/licenses/
 */ 

#include<stdio.h>
#include<stdlib.h> /* malloc */
#include<string.h>

#include "c2xsf.h"

#define LINE_SIZE 100

void cube_read(FILE* infile, struct unit_cell *c, struct contents *m,
               struct grid *gptr){
  static char buffer[LINE_SIZE+1];
  char *ptr;
  int i,j,n,comps,mo;
  long size;
  double x,y,z,t[3],scale;

  mo=0;
  if (debug>2) fprintf(stderr,"cube_read called\n");

  fgets(buffer,LINE_SIZE,infile);
  /* Was the title more than spaces and an end-of-line? */
  ptr=buffer;
  while((*ptr==' ')||(*ptr=='\n')) ptr++;
  if (*ptr){
    m->title=malloc(strlen(buffer)+1);
    if (!m->title) error_exit("Malloc error for title in cube_read()");
    strcpy(m->title,buffer);
    /* Remove newline */
    m->title[strlen(m->title)-1]=0;
  }

  fgets(buffer,LINE_SIZE,infile);
  /* Was the property description more than spaces and an end-of-line? */
  ptr=buffer;
  while((*ptr==' ')||(*ptr=='\n')) ptr++;
  if (*ptr){
    gptr->name=malloc(strlen(buffer)+1);
    if (!gptr->name) error_exit("Malloc error for title in cube_read()");
    strcpy(gptr->name,buffer);
    /* Remove newline */
    gptr->name[strlen(gptr->name)-1]=0;
  }

  fgets(buffer,LINE_SIZE,infile);
  i=sscanf(buffer,"%d %lf %lf %lf %d",&n,&x,&y,&z,&comps);
  if (i==4){
    comps=1;
    i=5;
  }
  if (i!=5)
    error_exit("Scan error 3rd line");
  if (n<0){
    n=-n;
    mo=1;
  }
  
  if ((comps!=1)&&(comps!=3))
    error_exit("Only cube files with one or three components"
	       " per voxel supported");
  
  if ((n<=0)||(x!=0)||(y!=0)||(z!=0))
    error_exit("Unexpected data 3rd line");

  if (!(c->basis=malloc(9*sizeof(double))))
    error_exit("Malloc error in cube_read for c->basis");

  gptr=grid_new(gptr);
  
  for(i=0;i<3;i++){
    fgets(buffer,LINE_SIZE,infile);
    if (sscanf(buffer,"%d %lf %lf %lf",gptr->size+i,t,t+1,t+2)!=4)
      error_exit("Scan error in grid description");
    for(j=0;j<3;j++) c->basis[i][j]=t[j]*gptr->size[i]*BOHR;
  }

  if(!(m->atoms=malloc(n*sizeof(struct atom))))
    error_exit("Malloc error in cube_read for atoms");
  m->n=n;
  init_atoms(m->atoms,n);
  
  for(i=0;i<n;i++){
    fgets(buffer,LINE_SIZE,infile);
    if (sscanf(buffer,"%d %lf %lf %lf %lf",&(m->atoms[i].atno),
               &(m->atoms[i].chg),t,t+1,t+2)!=5)
      error_exit("Scan error in atom description");
    for(j=0;j<3;j++) m->atoms[i].abs[j]=t[j]*BOHR;
  }

  real2rec(c);
  addfrac(m->atoms,m->n,c->recip);

  size=gptr->size[0]*gptr->size[1]*gptr->size[2];
  if (size==0) return;
  if (mo) fgets(buffer,LINE_SIZE,infile);
  gptr->comps=comps;
  if(!(gptr->data=malloc(comps*size*sizeof(double))))
    error_exit("Malloc error in cube_read for grid data");

  n=0;
  scale=1/(BOHR*BOHR*BOHR);
  for(i=0;i<size;i++){
    for(j=0;j<comps;j++){
      if (fscanf(infile,"%lf",gptr->data+i+j*size)!=1){n=1;break;}
      if (flags&DE_AU) gptr->data[i+j*size]*=scale;
    }
    if (n) break;
  }

  if (n) error_exit("Read error for grid data");

  /* Discard volumetic data if it is a dummy single point of zero set */
  if ((gptr->size[0]==1)&&(gptr->size[1]==1)&&(gptr->size[2]==1)&&
      (*gptr->data==0)&&(comps==1)){
    free(gptr->data);
    gptr->data=NULL;
    gptr->size[0]=gptr->size[1]=gptr->size[2]=0;
  }
  else
    if (!gptr->name) gptr->name="Density";

}
