// ----------------------------------------------------------------------------
//
// Copyright (C) Columbia University, 1994. All Rights Reserved.
// Sameer A. Nene, Shree K. Nayar, Hiroshi Murase
//
// See file LICENSE for details of software license agreement.
//
// ----------------------------------------------------------------------------
//
// parser.C
//
// Author:               Sameer Nene
// Date:                 08/29/94
// Version:              1.0.5
//
// Modification History:
//   06/07/94: Added CommandParser::getVerboseFlag()
//             Added CommandParser::getTemporaryDirectory()
//   08/13/94: Deleted CommandParser::getTemporaryDirectory()
//             Added CommandParser::getEigenValueFilename()
//             Added CommandParser::getAverageFlag()
//             Added CommandParser::getEigenValueFlag()
//             Changes to the way CommandParser::getAverageVectorFileName()
//               returns values.
//   08/18/94: Fixed bug which was causing d_numsparams to remain uinitialized
//   08/26/94: Fixed bug which was causing d_sstart_p and d_svalues_p to remain
//             uninitialized
//   08/29/94: Added implementation for optional command-line parameters.
//   12/06/95: Fixed bug in -s parameter
//
//
// Bugs:
//   Coredumps if argc <= 1.
//
// Classes:
//   CommandParser
//
// Notes:
//   This module contains implementation of classes declared in parser.h
//   
// ----------------------------------------------------------------------------

#include <stdlib.h>
#include <string.h>
#include "errorscope.h"
#include "stringary.h"
#include "parser.h"

extern char* optarg;
extern int optind;

CommandParser::CommandParser(int argc, char* const *argv, const char *opts) :
d_error(ErrorScope::OK), d_nameary_p(0), d_avg_p(0), d_eigen_p(0),
d_numeigen(0), d_dir_p(0), d_numvparams(0), d_numvalues(0), d_vstart_p(0),
d_values_p(0), d_aflag(0), d_cflag(0), d_vflag(0), d_combine_p(0), d_evl_p(0),
d_lflag(0), d_numsparams(0), d_numsvalues(0), d_sstart_p(0), d_svalues_p(0)
{
  int c, t, i, j;
  char *p, *r, *op;

  if(opts == 0)
    op = "a:c:e:l:m:n:s:v:ACD:LV";
  else
    op = (char *)opts;
  optind = 1;
  
  while((c = getopt(argc, (char **)argv, op)) != -1)
    switch(c) {
    case 'a':
      strcpy(d_avg_p = new char[strlen(optarg) + 1], optarg);
      break;
    case 'c':
      strcpy(d_combine_p = new char[strlen(optarg) + 1], optarg);
      break;
    case 'e':
      strcpy(d_eigen_p = new char[strlen(optarg) + 1], optarg);
      break;
    case 'l':
      strcpy(d_evl_p = new char[strlen(optarg) + 1], optarg);
      break;
    case 'm':
      if((d_mem = int(strtol(optarg, &p, 10))) <= 0) {
	d_error = PARAMETER_ERROR;
	return;
      }
      if(p == optarg) {
	d_error = PARAMETER_ERROR;
	return;
      }
      break;
    case 'n':
      if((d_numeigen = int(strtol(optarg, &p, 10))) <= 0) {
	d_error = PARAMETER_ERROR;
	return;
      }
      if(p == optarg) {
	d_error = PARAMETER_ERROR;
	return;
      }
      break;
    case 's':
      ++d_numsparams;
      p = optarg;
      do {
	strtod(p, &r);
	if(r == p) {
	  d_error = PARAMETER_ERROR;
	  return;
	}
	++d_numsvalues;
	p = r + 1;
      }
      while(*r == ',');
      break; 
    case 'v':
      ++d_numvparams;
      p = optarg;
      do {
	strtod(p, &r);
	if(r == p) {
	  d_error = PARAMETER_ERROR;
	  return;
	}
	++d_numvalues;
	p = r + 1;
      }
      while(*r == ',');
      break;
    case 'A':
      d_aflag = 1;
      break;
    case 'C':
      d_cflag = 1;
      break;
    case 'D':
      strcpy(d_dir_p = new char[strlen(optarg) + 1], optarg);
      break;
    case 'L':
      d_lflag = 1;
    case 'V':
      d_vflag = 1;
      break;
    default:
      d_error = PARAMETER_ERROR;
      return;
    }

  for(c = optind; c < argc; ++c)
    if(*(argv[c]) == '-') {
      d_error = PARAMETER_ERROR;
      return;
    }

  if(argc != optind)
    d_nameary_p = new StringAry(argc - optind);
  else {
    d_error = PARAMETER_ERROR;
    return;
  }

  for(c = optind, t = 0; c < argc; ++c) {
    d_nameary_p -> set(c - optind, argv[c]);
    t += strlen(argv[c]);
  }

  if(d_avg_p == 0) {
    strcat(strcpy(d_avg_p = new char[t + (argc - optind) << 1 + 8],
		  argv[optind]), "__");
    for(c = optind + 1; c < argc; ++c)
      strcat(strcat(d_avg_p, argv[c]), "__");
    strcat(d_avg_p, "avg.vec");
  }

  if(d_evl_p == 0) {
    strcat(strcpy(d_evl_p = new char[t + (argc - optind) << 1 + 8],
		  argv[optind]), "__");
    for(c = optind + 1; c < argc; ++c)
      strcat(strcat(d_evl_p, argv[c]), "__");
    strcat(d_evl_p, "evl.vec");
  }

  if(d_eigen_p == 0) {
    strcpy(d_eigen_p = new char[t + (argc - optind) << 1 + 5], argv[optind]);
    for(c = optind + 1; c < argc; ++c)
      strcat(strcat(d_eigen_p, "__"), argv[c]);
    strcat(d_eigen_p, ".evc");
  }

  if(d_combine_p == 0) {
    strcat(strcpy(d_combine_p = new char[t + (argc - optind) << 1 + 8],
		  argv[optind]), "__");
    for(c = optind + 1; c < argc; ++c)
      strcat(strcat(d_combine_p, argv[c]), "__");
    strcat(d_combine_p, "combine");
  }
 
  if(d_mem == 0)
    d_mem = 4;

  if(d_dir_p == 0)
    strcpy(d_dir_p = new char[2], ".");

  if(d_numvparams != 0) {
    d_vstart_p = new double*[d_numvparams];
    d_values_p = new double[d_numvalues];

    i = j = 0;
    optind = 1;
    
    while((c = getopt(argc, (char **)argv, op)) != -1)
      switch(c) {
      case 'v':
	d_vstart_p[i++] = &d_values_p[j];
	p = optarg;
	do
	  d_values_p[j++] = strtod(p, &p);
	while(*(p++) == ',');
      }
  }

  if(d_numsparams != 0) {
    d_sstart_p = new double*[d_numsparams];
    d_svalues_p = new double[d_numsvalues];

    i = j = 0;
    optind = 1;
    
    while((c = getopt(argc, (char **)argv, op)) != -1)
      switch(c) {
      case 's':
	d_sstart_p[i++] = &d_svalues_p[j];
	p = optarg;
	do
	  d_svalues_p[j++] = strtod(p, &p);
	while(*(p++) == ',');
      }
  }
}

CommandParser::~CommandParser()
{
  delete d_nameary_p;
  delete[] d_avg_p;
  delete[] d_eigen_p;
  delete[] d_dir_p;
  delete[] d_vstart_p;
  delete[] d_values_p;
  delete[] d_sstart_p;
  delete[] d_svalues_p;
}

ErrorScope::Error CommandParser::error() const
{
  return d_error;
}

char* CommandParser::getAverageVectorFileName() const
{
  return d_avg_p;
}

char* CommandParser::getEigenVectorFileName() const
{
  return d_eigen_p;
}

char* CommandParser::getEigenValueFileName() const
{
  return d_evl_p;
}

int CommandParser::getNumEigenVectors() const
{
  return d_numeigen;
}

int CommandParser::getMemRequired() const
{
  return d_mem;
}

char* CommandParser::getObjectDirectory() const
{
  return d_dir_p;
}

StringAry& CommandParser::getObjectList() const
{
  return *d_nameary_p;
}

int CommandParser::getNumValueParams() const
{
  return d_numvparams;
}

int CommandParser::getNumValues(int i) const
{
  return i < d_numvparams - 1 ? d_vstart_p[i + 1] - d_vstart_p[i] :
  &d_values_p[d_numvalues] - d_vstart_p[i];
}

double CommandParser::getValue(int p, int i) const
{
  return d_vstart_p[p][i];
}

int CommandParser::getNumSampleValueParams() const
{
  return d_numsparams;
}

int CommandParser::getNumSampleValues(int i) const
{
  return i < d_numsparams - 1 ? d_sstart_p[i + 1] - d_sstart_p[i] :
  &d_svalues_p[d_numsvalues] - d_sstart_p[i];
}

double CommandParser::getSampleValue(int p, int i) const
{
  return d_sstart_p[p][i];
}

int CommandParser::getEigenValueFlag() const
{
  return d_lflag;
}

int CommandParser::getAverageFlag() const
{
  return d_aflag;
}

int CommandParser::getCombineFlag() const
{
  return d_cflag;
}

int CommandParser::getVerboseFlag() const
{
  return d_vflag;
}

char* CommandParser::getCombineName() const
{
  return d_combine_p;
}
