/* Utility functions */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "utils.h"

void print_NONLINEAR(NONLINEAR* nums)
{
    int i;
    for (i=0; i<nums->noEntries; i++)
    {
	printf("value[%d]      %3d \n",i,nums->value[i]);
    }
}

void print_NONLINEAR_cols(NONLINEAR* nums)
{
    int i;
    for (i=0; i<nums->noEntries; i++)
    {
	printf("%d ",nums->value[i]);
	if ((i+1)%20 == 0 ) 
	  printf ("\n");
    }
}
int NONLINEARasStr( char* str, char* format, NONLINEAR* nums)
{
    if (nums->isValid)
    {
	return (sprintf(str,format,nums->field) != 0);
    }
    else
    {
	return (blankOut(str,getWidth(format)));
    }
}

int BITSasStr( char* str, char* format, BITS* num)
{
    if (num->isValid)
    {
	return (sprintf(str,format,num->value) != 0);
    }
    else
    {
	return (blankOut(str,getWidth(format)));
    }
}

int INTasStr( char* str, char* format, INT* num)
{
    int i;
    if (num->isValid)
    {
	return (sprintf(str,format,num->value) != 0);
    }
    else
    {
	return (blankOut(str,getWidth(format)));
    }
}

int FLOATasStr( char* str, char* format, FLOAT* num)
{
    if (num->isValid)
    {
	int len;
	int reqPrec=getPrecision(format);	
	int width=getWidth(format);	
        int newWidth=width;
        int newPrec=reqPrec;
        char newFormat[8],firstPart[3]="\0  ";	
	if (reqPrec > num->precision) 
	{
           newWidth=width - (reqPrec -num->precision);
	   newPrec=num->precision;
	}
	/* Decide about padding and sign */
	if ((format[1] == '+' && num->value != 0)|| format[1] == '0' )
	{
	   firstPart[0]=format[1];
	   if (format[2] == '0')
	   {
	      firstPart[1]='0';
	      firstPart[2]='\0';
	   }
	   else
	      firstPart[1]='\0';
	}	
	if (newPrec==0)	
	{
	/* Special case when we want something like 322. with no zeros */
	   sprintf(newFormat,"%%%s%d.%df.",firstPart,newWidth-1,newPrec);
	}
	else
	{
	   sprintf(newFormat,"%%%s%d.%df",firstPart,newWidth,newPrec);
	}
	
	   sprintf(str,"%s.",str);
	sprintf(str,newFormat,num->value);


	while (reqPrec > num->precision)
        { /* add spaces */
	   reqPrec--;
           sprintf(str,"%s%s",str," ") ;
	}
        sprintf(str,"%s%s",str,"\0") ;
	len = strlen(str);
	if (len > width)
	{
	/* horible case where we have a format which means we have to 
 	   drop the leading zero  because of a minus sign*/
	   if (str[0]=='-' && str[1]=='0')
	   {
              sprintf(str,"-%s",&str[2]) ;
	   }
	   else
	      fprintf(stderr,"Format not wide enough in FLOATasStr %s\n",
				str);
	}
    }
    else
    {
	return (blankOut(str,getWidth(format)));
    }
}

void strAsNONLINEAR (char* str, NONLINEAR* nums)
{
   if (str)
   {
      strcpy(nums->field,str);
      nums->noEntries=crackStr((int *)nums->value,str,3);
      nums->isValid=!isBlank(str);
   }
   else
   {
      fprintf(stderr,"strAsNONLINEAR called with NULL str - bad data ?\n");
   }
}

void strAsBITS (char* str, BITS* num)
{
   if (str)
   {
      num->value=atol(str);
      intToBits((char *)&num->bitString,num->value);
      num->isValid=!isBlank(str);
   }
   else
   {
      fprintf(stderr,"strAsBITS called with NULL str - bad data ?\n");
   }
}

void strAsINT (char* str, INT* num)
{
   if (str)
   {
      num->value=atol(str);
      num->isValid=!isBlank(str);
   }
   else
   {
      fprintf(stderr,"strAsINT called with NULL str - bad data ?\n");
   }
}

void strAsFLOAT (char* str, FLOAT* num)
{
   if (str)
   {
      char *pos=&str[0];
      num->value=atof(str);
      num->isValid=!isBlank(str);
      num->precision=0;
      /* work out precision */
       /* printf ("For %s \n",pos);*/
      while (pos[0] != '\0' && pos[0] != '.') 
      {
        pos++; 
      }
      /* got to decimal  now consume it */
      pos++;
      while (pos[0] != '\0' && pos[0] != ' ') 
      {
        pos++; 
        num->precision +=1;
      }
   }
   else
   {
      fprintf(stderr,"strAsFLOAT called with NULL str - bad data ?\n");
   }
}

bool isBlank (char* str)
{
   bool blank=TRUE;
   int i=0;
   
   if (str)
      while (blank && !(str[i] == '\0'))
      {
         blank = (str[i] == ' ' || str[i] == '\0');
         i++;
      }
   return blank;
}

int getWidth (char* format)
{
/* Look in format string after % and get the number representing the width */
    return (atoi(&format[1]));
}

int getPrecision (char* format)
{
/* Look in format string after % and get the number representing the precision*/
    int i=1;
    while (format[i] != '\0' && format[i] != '.') 
    {
	i++;
    }
    return (atoi(&format[i+1]));
}

bool blankOut (char *str, int width)
{
/* put width blanks in str */
   int i;
   if (sprintf(str,"%s"," ")!= 0) 
   {
      for (i =1; i< width; i++)
         sprintf(str,"%s%s",str," ") ;
      return TRUE;
   }
   else
      return FALSE;
}

bool intToBits( char* bits, int num)
{/* Convert the integer to a string of bits and put it in bits 
    This is encoded so 2^0 is at location 0 in the array - i.e.
    if you print this bitstring out it is the wrong way round 
    it fills it out woth zeros also */
   int i=0,div,rem,done=0;
   div=num;
   while (!done)
   {
      done=0>=div;
      rem=div % 2;
      div=div / 2;
      if (0 == rem)
         bits[i]='0';
      else
         bits[i]='1';
      i++ ;
   }
   while (i<BITSTRLEN) bits[i++]='0';
   bits[BITSTRLEN]='\0';
   return TRUE;
}

void showFlags( char* flags[],BITS* bits)
{  /* Look at the bit string and if a bit is set then print
      the flag from the provided array of flags */
   int i=0;
   while (flags[i] && (i < BITSTRLEN))
   {
	if (bits->bitString[i] == '1')
	{
	   printf ("\t(%s)\n",flags[i]);
	}
	i++;
   }
}

int crackStr(int* value, char* str, int width)
{  /* split a string up into numbers based on fixed width 
      put them in the integer array privided in value*/
   int i=0,count=0,cploc=0;
   int len=strlen(str);
   while ( str[i] != '\0' && (i < len))
   {
   	char strnum[8]="       \0";
	for (cploc=0;cploc < width; cploc++)
	{
	   strnum[cploc]=str[i+cploc];
	}
	value[count]=atoi(strnum);	
	i+=width;
	count++;
   }
   return count; 
}
void checkIfCommandLineFlag (char **argv,int argc,int* i, int *cols,int *decode, int* quite, long* multiRecs)
{
/* Parse the argument to see if it begins with + or - and set the provided
   variables acordingly.
   This also prints the option list for all applications
*/
   while (*i < argc && (argv[*i][0] == '-' || argv[*i][0] == '+'))
   {
      if (argv[*i][0] == '-')
      { /* expect flags */  
	int flag=1;
	while (argv[*i][flag] != '\0')
	{
	   switch (argv[*i][flag])
	   {
	      case 'b': *decode+=DECODEBITS; break;
	      case 'a': *decode=DECODEBITS+PRINTSUBRECS+EXTRACTCOEFF; break;
	      case 's': *decode+=PRINTSUBRECS; break;
	      case 'c': *decode+=EXTRACTCOEFF; break;
	      case 't': *cols=1; break;
	      case 'q': *quite=1; break;
	      default : if (argv[*i][flag] != 'h')
			   printf ("Invalid option - valid options are\n");
 			printf ("\tUSAGE: %s [-habcst] [+n] identifier [..identifier]\n",argv[0]);
			printf ("\th - print this message\n");
			printf ("\ta - apply b, c, s together\n");
			printf ("\tb - bit field decoding (HEPA and TEPA)\n");
			printf ("\tc - correlation coefficient extraction (applicable to DMSA/C, G, O, V)\n");
			printf ("\ts - sub-record print\n");
			printf ("\tt - tabular print \n");
			printf ("\tq - supress header from -t \n");
			printf ("\t+n - print next n records after the one with the given key\n");
			printf ("\tOptions may be applied together i.e -tcs\n");
			printf ("\tThe + option must have a space before it.\n");
			printf ("\tFor shipdm and shipdmc if you specify -t and some other option\n");
			printf ("\tyou shoud also specify -s to show the CORR and COMP records\n");
			printf ("\tof the hip_dm_c record.\n");
			printf ("\tBy default the main record is printed verbose.\n");
			exit (1); /* Quit Program */
			break;
	    } /* Close switch */
	    flag++;
         } /* Close while */
      } /* Close (if '-') */

      if (argv[*i][0] == '+')
      { /* expect number of recs to retrieve */  
	*multiRecs = atol(&argv[*i][1]);
      }
      *i += 1;
   }
   if (*i>=argc)
   {  /* In this case there is no more args so something is wrong */   
      printf ("Try %s -h \n",argv[0]);
      exit (1); /* Quit Program */
   }
 
}

