
/*
	file: util.c
	contains utility routines for resmf
*/

#include "stdvadar.h"
#include <ctype.h>
#include <string.h>

#define SKIP     -9

#define NAME_LOC 12
#define NAME_EXTRA_LOC 16
#define RES_LOC 17
#define CHAIN_LOC 21
#define RESNUM_LOC 22 /* renum the location so that it can read num > 1000, modified by haiyan zhang */
#define RESNUM_EXTRA_LOC 26
#define COORD_LOC 30

char	lastExtra = '-';
char	resNumExtra;
int	lastresNum = -999;
int	resNumAdd;
int     skip_res;
char    skip_resextra;


/**************************************************************
* PURPOSE: to varify Residue Name 
**************************************************************/
char varify_residueName(resname)
char *resname;
{
  if( !strcmp( resname, "ALA" ) )  return('A');
  if( !strcmp( resname, "CYS" ) )  return('C');
  if( !strcmp( resname, "ASP" ) )  return('D');
  if( !strcmp( resname, "GLU" ) )  return('E');
  if( !strcmp( resname, "PHE" ) )  return('F');
  if( !strcmp( resname, "GLY" ) )  return('G');
  if( !strcmp( resname, "HIS" ) )  return('H');
  if( !strcmp( resname, "ILE" ) )  return('I');
  if( !strcmp( resname, "LYS" ) )  return('K');
  if( !strcmp( resname, "LEU" ) )  return('L');
  if( !strcmp( resname, "MET" ) )  return('M');
  if( !strcmp( resname, "ASN" ) )  return('N');
  if( !strcmp( resname, "PRO" ) )  return('P');
  if( !strcmp( resname, "GLN" ) )  return('Q');
  if( !strcmp( resname, "ARG" ) )  return('R');
  if( !strcmp( resname, "SER" ) )  return('S');
  if( !strcmp( resname, "THR" ) )  return('T');
  if( !strcmp( resname, "VAL" ) )  return('V');
  if( !strcmp( resname, "TRP" ) )  return('W');
  if( !strcmp( resname, "TYR" ) )  return('Y');

  return('X');
}


/*************************************************************/
/* read one atom from pdb file, excluding H atoms
*/
char *read_pdb(pdbfp, atom, hflag) 
FILE 		*pdbfp;
ATOM_REC	*atom;
int hflag;
{
int ret=0;
char line[MAX_LINE_LEN];

	ret = read_one_pdb(pdbfp, atom, line);
	if (hflag)
		while ((ret != 0) && (ret == SKIP) )
			ret = read_one_pdb(pdbfp, atom, line);

	else
		while ((ret != 0) && ((ret == SKIP) || (atom->atomName[0] == 'H')) )
			ret = read_one_pdb(pdbfp, atom, line);

	if (ret == 0)
		return(NULL);
	else return(line);

}	/* read_pdb */


/***************************************************************************
* PURPOSE:  to read one atom record (line) from the pdb file
*/
int read_one_pdb(pdbfp, atom, line)
FILE 		*pdbfp;
ATOM_REC	*atom;
char 		*line;
{
char *ret, atom2[6], *pt;
static float Nx, Ny, Nz;
int i,j;

    // printf("POS NAME_LOC:%d NAME_EXTRA_LOC:%d\n", NAME_LOC, NAME_EXTRA_LOC);

	/* read one line in, just read one line using file pointer */

	while ( ret = fgets(line, MAX_LINE_LEN-1, pdbfp) ) {
		if( strncmp(line, "ATOM", 4) == 0)  break;
	}
	if (ret == NULL)
		return(0);

	/* read and set atom name from pdb file */
    // printf("108 libc/util.c line:\n %s", line);
	// sscanf(line+NAME_LOC, "%4s", atom2); 
    //  printf("\t atom2:%s", atom2);

    // switch 2011.06.06 grep the atom name from fixed column position
	// 2011.06.20 add memset for reset memory 
    memset(&atom2[0], 0, sizeof(atom2));
    j = 0;
    for(i=NAME_LOC; i <= NAME_LOC+3; i++) {
             if(line[i] != ' ') atom2[j++]=line[i];
             // printf("\tpos:%d-%c(%s)  ", i, line[i], atom2);
    }
    // printf("\tfor atom2:%s \n\n", atom2);

    pt=strtok(atom2," ");
    strcpy(atom->atomName, pt);

    // switch with above code because of reading exact atom name
    // sscanf(line+NAME_LOC, "%3s", atom->atomName); 

    if (strcmp(atom->atomName, "OE")  == 0) strcpy(atom->atomName, "OE1");
	if (strcmp(atom->atomName, "AE1") == 0) strcpy(atom->atomName, "OE1");
	if (strcmp(atom->atomName, "AE2") == 0) strcpy(atom->atomName, "NE2");
	if (strcmp(atom->atomName, "AD1") == 0) strcpy(atom->atomName, "OD1");
	if (strcmp(atom->atomName, "AD2") == 0) strcpy(atom->atomName, "ND2");

	/* this is a check for an atom name of the form NNNX, where
	 * NNN is the atom name, and X is a character (A or B) only
	 * the A atoms should be read (the B's are duplicates)
         */
	if ( (line[NAME_EXTRA_LOC] != ' ') && (line[NAME_EXTRA_LOC] != 'A') ) {
		return(read_one_pdb(pdbfp, atom, line));
        }

	/* also ignore hydrogen atom's - those starting with H */
    /* eg. 1HD2, 2HG1 */
	if (line[NAME_LOC+1] == 'H') {
	//	printf("%s\nReturn becaus of H: %c %s\n", line, line[NAME_LOC+1], atom);	 
		return(read_one_pdb(pdbfp, atom, line));
	}	

    /* ignore the atom start with 'Q', add by Haiyan zhang */
	/* 2011.06.20 add 'D' cases like 'DH11' on 5PTI  by BHan*/
    if (line[NAME_LOC+1] == 'Q'|| line[NAME_LOC]=='D' || line[NAME_LOC+1]=='D')
               return(read_one_pdb(pdbfp, atom, line));

	/* residue name */
	sscanf(line+RES_LOC, "%3s", atom->resName); 

    // add 2011.06.06, to check strange/weird residue name
    if( varify_residueName(atom->resName) == 'X' )  {
         // printf("Strange ResName: %s\n", line);
         return(SKIP);
    }

    // ignore atom begin with 'D' like 'DH21', 'DH22', 'DE21'. Those are not listed on bmrb/pdb naming systems
	// DH21 intead of 1DH2; so use NAME_LOC not NAME_LOC+1
	if (line[NAME_LOC] == 'D') return(SKIP);

	/* chain indicator */
	sscanf(line+CHAIN_LOC, "%c", &atom->chain);

	/* x, y, and z coordinates */
	sscanf(line+COORD_LOC,  "%f%f%f", &(atom->x), &(atom->y), &(atom->z));

    // printf("%satom  %s %f %f %f\n", line, atom->atomName, atom->x, atom->y, atom->z);

	if (SKIP == get_res_num(line, atom, Nx, Ny, Nz))
	{ 
            printf("skip get_res_num\n"); /* add by Haiyan */
        	return(SKIP);
    }
 
	if (strcmp(atom->atomName, "N") == 0) {
		Nx = atom->x;
		Ny = atom->y;
		Nz = atom->z;
	}
	return(1);

}	/* read_one_pdb */



int get_res_num(line, atom, Nx, Ny, Nz)
char		*line;
ATOM_REC	*atom;
float Nx, Ny, Nz;
{
	sscanf(line+RESNUM_LOC, "%d", &atom->origResNum); 
	atom->resNum = atom->origResNum;

	/* there may be a character here.  This happens when an extra res
	 * is added to the pdb file, but instead of renumbering the file,
	 * a character such as A is added to the res num.  But, we must
	 * renumber the pdb file if this happens, for the programs to run.
	 * It is also possible that this is a duplicate residue (alternate).
	 * If so, it will have the same coordinates as the previous residue,
	 * and then this residue should be discarded.
	 */
	resNumExtra = line[RESNUM_EXTRA_LOC];

    atom->insCode = resNumExtra; // add 2011.08.24

	if ( (resNumExtra != lastExtra ) && (lastExtra != '-') &&
		(atom->resNum == lastresNum) ) {
		if (duplicate_res(atom, Nx, Ny, Nz)) {
            printf("duplicated residue: %d\n", atom->resNum);
			return(SKIP);
		}
		else resNumAdd++;
	}
	lastExtra = resNumExtra;
	lastresNum = atom->resNum;
	atom->resNum += resNumAdd;

	return(1);

}	/* get_res_num */


int duplicate_res(atom, Nx, Ny, Nz)
ATOM_REC *atom;
float Nx, Ny, Nz;
{

	if ( (atom->x == Nx) && (atom->y == Ny) && (atom->z == Nz) ) {
		skip_res = atom->resNum;
		skip_resextra = resNumExtra;
		return(TRUE);
	}

	if ( (atom->resNum == skip_res) && (resNumExtra == skip_resextra) ) {
		return(TRUE);
	}
	return(FALSE);

}	/* duplicate_atom */
