/**********************************************************************
 *
 * oaiargs.cpp --
 *
 * Copyright (C) 2004-2010  The New Zealand Digital Library Project
 *
 * A component of the Greenstone digital library software
 * from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *********************************************************************/

#include "oaiargs.h"
#include "cgiutils.h"

// read the arguments from a stream for an OAI action
void oaiargs::readArgs(istream &in)
{
  unsigned char  buffer[256];
  unsigned char *end = buffer + 256;
  unsigned char *here = end;
  unsigned char *start, *equals;

  // if no parameters, return now.
  if (in.eof()) {
    cerr << "Aborting on EOF" << endl;
    return;
  }

  // fill the buffer with the stream
  this->fillBuffer(in, buffer, &here, end);

  // start at the beginning of the buffer, read
  // the stream until exhausted
  here = buffer;
  while (*here != '\0')
  {
    // each iteration of the outer loop reads a single argument

    // we start an argument and continue until the buffer is
    // exhausted or the next argument is found
    start = here;
    equals = NULL;
    while (*here != '&' && *here != '\0') {
      // remember where the equals sign was if necessary
      if (equals == NULL && *here == '=') {
	equals = here;
      }

      // move to the next character
      ++here;

      // and refill the buffer as necessary
      if (here == end) {
	this->fillBuffer(in, buffer, &here, end);
      }
    }
    
    // we've now got the scope of one argument, where it begins, ends
    // and where the equals sign is; we now split it up accordingly
    // to create the actual text_t type elements for the label and the
    // value.
    text_t label, value;
    if (equals == NULL) {
      label.setcarr((char *) start, (long) here - (long) start);
      value = label;
    }
    else {
      label.setcarr((char *) start, (long) equals - (long) start);
      ++equals;
      value.setcarr((char *) equals, (long) here - (long) equals);
    }

    decode_cgi_arg(value);
    
    // output to the screen for tracing purposes
    // cerr << label << "?" << value << endl;

    // if the argument already exists, raise an error
    if (this->arguments.count(label) > 0) {
      this->duplicateArg = true;
    }
    else {
      // add this argument to the argument map
      this->arguments[label] = value;
    }

    // don't choke on an argument separator; swallow it so we don't get
    // inifinite loops above
    if (*here == '&') {
      ++here;
    }
  }
}

void oaiargs::fillBuffer(istream &in, unsigned char *buffer, unsigned char **currentPtr, unsigned char *end)
{
  unsigned char *fill = buffer;

  // copy out the remaining buffer space
  while (*currentPtr != end) {
    *fill = **currentPtr;
    *currentPtr++;
  }

  // set the buffer appropriately
  *currentPtr = fill;

  // refill the buffer
  in.get((char *)*currentPtr, (char *)end - (char *)*currentPtr);
}

