//<copyright>
//
// Copyright (c) 1996
// Institute for Information Processing and Computer Supported New Media (IICM),
// Graz University of Technology, Austria.
//
//</copyright>

//<file>
//
// Name:    optionparser.C
//
// Purpose: implementation of class OptionParser
//
// Created: 5 Sep 1996 Bernhard Heidegger
//
// $Id: optionparser.C,v 1.2 1997/02/10 10:29:10 gorasche Exp $
//
// Description:
//   
//</file>
//
// $Log: optionparser.C,v $
// Revision 1.2  1997/02/10 10:29:10  gorasche
// renamed enums for Win32
//
// Revision 1.1  1996/10/25 13:12:34  breising
// Initial revision
//
// Revision 1.2  1996/10/17 10:24:43  bheide
// changed indexa return test in nextisOption() according to match()
//
// Revision 1.1  1996/10/16 10:49:13  bheide
// Initial revision
//
//

static char rcsid[] = "$Id: optionparser.C,v 1.2 1997/02/10 10:29:10 gorasche Exp $";

#include "optionparser.h"

OptionParser::OptionParser(int argc, char ** argv, const OptionStruct * opts)
{
  
  cur_ = 0;
  argc_ = argc;
  argv_ = (const char **) argv;
  opts_ = opts;
  for (const OptionStruct * o = opts_; o->option; o++)
  {
    options_.append(RString(o->option));
  }
  state_ = OPTERROR;
  if (argc < 2)
  {
    error_ = OPTNOARGS;
    return;
  }
  if (options_.count() == 0)
  {
    error_ = OPTNOOPTS;
    return;
  }
  state_ = OPTOK;
  error_ = OPTNOERROR;
  
}

OptionParser::~OptionParser()
{
  
  options_.free();
  matches_.free();
  
}

// bool OptionParser::parse(const OptionStruct * options)
// {
  
//   // options_.free();
//   for (const char * p = *options, p, p++)
//     options_.insert(p);
//   if (options_.count())
//     error_ = NOERROR;
//   else
//     error_ = PARSE;
//   return (error_ == NOERROR);
  
// }

int OptionParser::getOption()
{
  
  if (state_ != OPTOK)
  {  // FIXME: better error handling
    return (error_);
  }
  cur_++;  // next one
  while ((cur_ < argc_) && (*argv_[cur_] != '-'))
    cur_++;  // skip parameters from last option
  if (cur_ == argc_)
  {
    state_ = OPTERROR;
    error_ = OPTNOMORE;
    return (error_);
  }
  int pos = -1;
  int matches = match(RString(argv_[cur_]), pos);
  switch (matches)
  {
    case 0:
      error_ = OPTUNKNOWN;
      break;
    case 1:
      if ((pos >= 0) && (pos < options_.count()))
      {
        return (opts_[pos].tag);
      }
      else
      {
        state_ = OPTERROR;
        error_ = OPTINTERNAL;
      }
      break;
    default:
      error_ = OPTAMBIGUOUS;
      break;
  }
  return (error_);  // FIXME: better error handling
  
}

RString OptionParser::getParam()
{
  
  cur_++;
  if (cur_ == argc_)
  {
    state_ = OPTERROR;
    error_ = OPTNOMORE;
    return RString();
  }
  return RString(argv_[cur_]);
  
}

bool OptionParser::nextisOption()
{
  
  if ((state_ != OPTOK) || ((cur_+1) >= argc_))
    return (false);
  
  RString next = RString(argv_[cur_+1]);
  int len = next.length();
  for (int i = 0; i < options_.count(); i++)
  {
    if (options_[i].indexa(next) == len)
      return (true);
  }
  return (false);
  
}

RString OptionParser::ambiguous()
{
  
  RString ret;
  
  for (int i = 0; i < matches_.count(); i++)
  {
    ret += matches_[i] + " ";
  }
  return (ret);
  
}

// private functions

int OptionParser::match(const RString opt, int& pos)
{
  
  int wmatches = 0, wpos = 0;
  RString wmatch;
  int len = opt.length();
  
  matches_.free();
  for (int i = 0; i < options_.count(); i++)
  {
    if (options_[i].indexa(opt) == len)
    {
      matches_.insert(options_[i]);  // this option matches
      pos = i;
      if ((wmatches <= 1) && (options_[i] == opt))
      {  // whole option match
        wmatches++;
        wmatch = options_[i];
        wpos = i;
      }
    }
  }
  if (matches_.count() > 1)
  {  // ambiguous; check whole matches
    if (wmatches == 1)
    {
      matches_.free();
      matches_.append(wmatch);
      pos = wpos;
    }
  }
  return (matches_.count());
  
}
