/* 
 * author:  msturm, 
 * created: 16 Apr 1997
 * changes:
 *
 * contains routines for command line parsing 
 * (mostly copied from gaudi toolbox, changed to templated functions)
 *
 */

#ifndef __ARGIO_H__
#define __ARGIO_H__

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



const int ipMAXTOKLEN = 255; // max. length of a token

// some workarounds for template function
typedef char* charp;

inline float fatof(const char *str) {
  return (float) atof(str);
}

// command line parsing

template <class T>
inline T ipGetArgument(const char **argv, const char *keystr, 
		       T (*convert) (const char *str), const T defval) {
  for (int i=1; argv[i]; i++)
    if (strstr(argv[i],keystr)) {
      if (argv[i+1]) return convert(argv[i+1]);
      else {
	fprintf(stderr,"Error: ipGetArgument: argument value of option \"%s\" is missing!\n", 
		argv[i]);

	exit(-1);
      }
    }

  return defval;
}

inline charp ipGetStringArgument(const char **argv, const char *keystr, const charp defval)
{
  char *_defval = (defval ? strdup(defval): NULL);
  //return ipGetArgument(argv, keystr, strdup, _defval);
  for (int i=1; argv[i]; i++)
    if (strstr(argv[i],keystr)) {
      if (argv[i+1]) return strdup(argv[i+1]);
      else {
	fprintf(stderr,"Error: ipGetArgument: argument value of option \"%s\" is missing!\n", 
		argv[i]);

	exit(-1);
      }
    }

  return _defval;
}

// reads in multiple string arguments started by keystr and ended by an '-' or
// end of args
inline int ipGetStringMultipArgument(const char **argv, const char *keystr, char **out, const int max) {
  int i = 1, num;
  while (argv[i]) {
    if (strstr(argv[i],keystr)) {
      // keystr found
      if (argv[i+1] && (argv[i+1])[0] != '-') {
        i++;
        num = 0;
        out[0] = strdup(argv[i]);
        i++; num++;
        while (argv[i] && num < max && (argv[i])[0] != '-') {
          out[num] = strdup(argv[i]);
          i++;num++; }
        return num;
        // jump back !
      } else {
        fprintf(stderr,"Error: ipGetArgument: argument value of option \"%s\" is missing!\n", argv[i]);
        exit(-1); } } // if keystr
    i++; } //while
  return 0;}


inline int ipGetIntArgument(const char **argv, const char *keystr, const int defval) {
  //return ipGetArgument(argv, keystr, atoi, defval);{
  for (int i=1; argv[i]; i++)
    if (strstr(argv[i],keystr)) {
      if (argv[i+1]) return atoi(argv[i+1]);
      else {
	fprintf(stderr,"Error: ipGetArgument: argument value of option \"%s\" is missing!\n", 
		argv[i]);

	exit(-1);
      }
    }
  return defval;
}

inline float ipGetFloatArgument(const char **argv, const char *keystr, const float defval) {
  //return ipGetArgument(argv, keystr, fatof, defval);
  for (int i=1; argv[i]; i++)
    if (strstr(argv[i],keystr)) {
      if (argv[i+1]) return fatof(argv[i+1]);
      else {
	fprintf(stderr,"Error: ipGetArgument: argument value of option \"%s\" is missing!\n", 
		argv[i]);

	exit(-1);
      }
    }
  return defval;
}

inline double ipGetDoubleArgument(const char **argv, const char *keystr, const double defval) {
  //return ipGetArgument(argv, keystr, atof, defval);
  for (int i=1; argv[i]; i++)
    if (strstr(argv[i],keystr)) {
      if (argv[i+1]) return atof(argv[i+1]);
      else {
	fprintf(stderr,"Error: ipGetArgument: argument value of option \"%s\" is missing!\n", 
		argv[i]);

	exit(-1);
      }
    }
  return defval;
}

inline int ipExistsArgument(const char **argv, const char *keystr) {
  for (int i=1; argv[i]; i++) 
    if (strstr(argv[i],keystr)) return 1;
  
  return 0;
}


// string utilities
// appends src to resized dst and returns it
inline char *ipAppendString(char *&dst, const char *src){
  if (dst) {
    dst = (char *) realloc(dst, strlen(dst) + strlen(src) + 1);
    return strcat(dst, src);  }
  else return strdup(src);}

     
/*************************************************************
 * counts the words on one line 
 ************************************************************/ 
inline int ipLineWordCount(const char *s){
    int n = 0;
    for (;;) {
        while (isspace(*s)) s++;
        if (*s == '\0') return n;
        while (isgraph(*s)) s++;
        n++;    }}


/*************************************************************
 * gets the generic name of a file cutting the extension 
 ************************************************************/ 
inline char *ipGetBaseName(const char *string){
  unsigned int i;
  char *ret = NULL, *retp = NULL; 
  if (!(ret = strdup(string))) {
    fprintf(stderr, "Error: ipGetBaseName [%s, line %d]: strdup() failed:",
            __FILE__, __LINE__);
    perror("");
    exit(errno);  }  
  for(i=0, retp=ret; i<strlen(string);i++, retp++)
    if (*retp == '.') {
      *retp = '\0';
      break;    } 
  return ret;}

     
/*************************************************************
 * reads a line into s (already allocated) and returns length
 * lim describes the max line length.
 * function proposed by Kernighan and Ritchie
 ************************************************************/ 
inline int ipfgetline(FILE* f, char* s, int lim){
    int   c,i;
    for(i=0; (i<lim-1) && ((c=getc(f))!=EOF) && (c!='\n'); ++i)
        s[i]=c;
    if (c=='\n'){
        s[i]=c;
        ++i;
    }
    s[i]='\0';
    return(i);}           

// extracts string tokens from a string which are either separeted by 
//    - white-space (isspace()) or 
//    - punctuation (ispunct()) except '.', '+', '-', '_'
// and converts them to type <class T>.
//
// at most n tokens will be extracted, tokenval[] has to be
// allocated
// returns number of tokens found, converted tokens in tokenval[]

template <class T>
int ipExtractTokens(T *tokenval, const char *tokenstr, const int n,
		    T (*convert) (const char *str)) {
  char *tmp_token = new char [ipMAXTOKLEN];
  char *tmp_tokenp = tmp_token;
  const char *tokenp = tokenstr;
  int  i = 0;

  while ((i < n) && (*tokenp)) {
    memset(tmp_token, '\0', ipMAXTOKLEN * sizeof(char));
    while (isspace(*tokenp) && *tokenp) tokenp++;
    tmp_tokenp = tmp_token;
    while ((*tokenp) && (isalnum(*tokenp) || (*tokenp == '.') || 
			 (*tokenp == '-') || (*tokenp == '+') || 
			 (*tokenp == '_') ) && 
	   ((tmp_tokenp - tmp_token) < ipMAXTOKLEN)) 
      *(tmp_tokenp++) = *(tokenp++);
    if(*tokenp) tokenp++; // skip separator
    tokenval[i++] = convert(tmp_token);
  }
  
  delete [] tmp_token;

  return i;
}

// extracts string tokens from a string which are either separeted by 
//    - white-space (isspace()) or
//    - commas
// and converts them to type <class T>.
//
// at most n tokens will be extracted, tokenval[] has to be
// allocated
// returns number of tokens found, converted tokens in tokenval[]

template <class T>
int ipExtractSpaceSepTokens(T *tokenval, const char *tokenstr, const int n,
			    T (*convert) (const char *str)) {
  char *tmp_token = new char [ipMAXTOKLEN];
  char *tmp_tokenp = tmp_token;
  const char *tokenp = tokenstr;
  int  i = 0;

  while ((i < n) && (*tokenp)) {
    memset(tmp_token, '\0', ipMAXTOKLEN * sizeof(char));
    while (isspace(*tokenp) && *tokenp) tokenp++;
    tmp_tokenp = tmp_token;
    while ((*tokenp) && (isspace(*tokenp) || (*tokenp != ',') ) && 
	   ((tmp_tokenp - tmp_token) < ipMAXTOKLEN)) 
      *(tmp_tokenp++) = *(tokenp++);
    if(*tokenp) tokenp++; // skip separator
    tokenval[i++] = convert(tmp_token);
  }
  
  delete [] tmp_token;

  return i;
}


inline int ipExtractIntTokens(int *tokenval, const char *tokenstr, const int n) {
  //  return ipExtractTokens(tokenval, tokenstr, n, atoi);
  char *tmp_token = new char [ipMAXTOKLEN];
  char *tmp_tokenp = tmp_token;
  const char *tokenp = tokenstr;
  int  i = 0;

  while ((i < n) && (*tokenp)) {
    memset(tmp_token, '\0', ipMAXTOKLEN * sizeof(char));
    while (isspace(*tokenp) && *tokenp) tokenp++;
    tmp_tokenp = tmp_token;
    while ((*tokenp) && (isalnum(*tokenp) || (*tokenp == '.') || 
			 (*tokenp == '-') || (*tokenp == '+') || 
			 (*tokenp == '_') ) && 
	   ((tmp_tokenp - tmp_token) < ipMAXTOKLEN)) 
      *(tmp_tokenp++) = *(tokenp++);
    if(*tokenp) tokenp++; // skip separator
    tokenval[i++] = atoi(tmp_token);
  }
  
  delete [] tmp_token;

  return i;
}

inline int ipExtractFloatTokens(float *tokenval, const char *tokenstr, const int n) {
  //  return ipExtractTokens(tokenval, tokenstr, n, fatof);
  char *tmp_token = new char [ipMAXTOKLEN];
  char *tmp_tokenp = tmp_token;
  const char *tokenp = tokenstr;
  int  i = 0;

  while ((i < n) && (*tokenp)) {
    memset(tmp_token, '\0', ipMAXTOKLEN * sizeof(char));
    while (isspace(*tokenp) && *tokenp) tokenp++;
    tmp_tokenp = tmp_token;
    while ((*tokenp) && (isalnum(*tokenp) || (*tokenp == '.') || 
			 (*tokenp == '-') || (*tokenp == '+') || 
			 (*tokenp == '_') ) && 
	   ((tmp_tokenp - tmp_token) < ipMAXTOKLEN)) 
      *(tmp_tokenp++) = *(tokenp++);
    if(*tokenp) tokenp++; // skip separator
    tokenval[i++] = fatof(tmp_token);
  }
  
  delete [] tmp_token;

  return i;
}

inline int ipExtractDoubleTokens(double *tokenval, const char *tokenstr, const int n) {
  // return ipExtractTokens(tokenval, tokenstr, n, atof);
  char *tmp_token = new char [ipMAXTOKLEN];
  char *tmp_tokenp = tmp_token;
  const char *tokenp = tokenstr;
  int  i = 0;

  while ((i < n) && (*tokenp)) {
    memset(tmp_token, '\0', ipMAXTOKLEN * sizeof(char));
    while (isspace(*tokenp) && *tokenp) tokenp++;
    tmp_tokenp = tmp_token;
    while ((*tokenp) && (isalnum(*tokenp) || (*tokenp == '.') || 
			 (*tokenp == '-') || (*tokenp == '+') || 
			 (*tokenp == '_') ) && 
	   ((tmp_tokenp - tmp_token) < ipMAXTOKLEN)) 
      *(tmp_tokenp++) = *(tokenp++);
    if(*tokenp) tokenp++; // skip separator
    tokenval[i++] = atof(tmp_token);
  }
  
  delete [] tmp_token;

  return i;
}

inline int ipExtractStringTokens(char **tokenval, const char *tokenstr, const int n) {
  // return ipExtractSpaceSepTokens(tokenval, tokenstr, n, strdup);
  char *tmp_token = new char [ipMAXTOKLEN];
  char *tmp_tokenp = tmp_token;
  const char *tokenp = tokenstr;
  int  i = 0;

  while ((i < n) && (*tokenp)) {
    memset(tmp_token, '\0', ipMAXTOKLEN * sizeof(char));
    while (isspace(*tokenp) && *tokenp) tokenp++;
    tmp_tokenp = tmp_token;
    while ((*tokenp) && (isalnum(*tokenp) || (*tokenp == '.') || 
			 (*tokenp == '-') || (*tokenp == '+') || 
			 (*tokenp == '_') ) && 
	   ((tmp_tokenp - tmp_token) < ipMAXTOKLEN)) 
      *(tmp_tokenp++) = *(tokenp++);
    if(*tokenp) tokenp++; // skip separator
    tokenval[i++] = strdup(tmp_token);
  }
  
  delete [] tmp_token;

  return i;
}

#endif
