/*
-----------------------------------------------------------------------------
denef - Decode NEF image files
Copyright (C) 2000 Daniel Stephens (daniel@cheeseplant.org)

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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
------------------------------------------------------------------------------
*/


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

#include "options.h"

static const char *rcsid="$Id: options.cc,v 1.2 2000/12/10 22:11:28 daniel Exp $";

bool 
options::Process_Options(int &argc, 
			 char **&argv, 
			 const vector<options::optionInterface *> &opts,
			 bool dash_delimits_files,
			 bool allow_intermixed_files)
{
    bool oksofar=true;

    vector<options::optionInterface *>::const_iterator o;

    for (int a=1; a<argc;++a) {
	if (argv[a][0]!='-') {
	    if (!allow_intermixed_files) return oksofar;
	    continue;
	} 
	const char *thisopt=argv[a];
	for (int av=a; av<(argc-1); ++av) {
	    argv[av]=argv[av+1];
	}
	argv[argc-1]=0;
	a--;
	argc--;

	if (thisopt[1]==0) {
	    if (dash_delimits_files) {
		return oksofar;
	    }  else {
		continue;
	    }
	}
	
	if (thisopt[1]=='-') {
	    bool found=false;
	    for (o=opts.begin(); (!found) && (o!= opts.end()); ++o) {
		const char *longname=(*o)->Long_Name();
		if (!longname) continue;
		int l=strlen(longname);
		if (strncmp(&thisopt[2],longname,l)!=0) continue;
		if (thisopt[2+l]=='=') {
		    found=true;
		    if (!(*o)->Takes_Argument()) {
			cerr << argv[0] << ": Error - option --" << longname
			     << " does not take an argument" << endl;
			oksofar=false;
			break;
		    }
		    oksofar &= (*o)->Process(&thisopt[2+l+1]);
		} else if (thisopt[2+l]==0) {
		    found=true;
		    if ((*o)->Requires_Argument()) {
			cerr << argv[0] << ": Error - option --" << longname
			     << " requires an argument" << endl;
			oksofar=false;
			break;
		    }
		    oksofar &= (*o)->Process(0);
		}
	    }
	    if (!found) {
		cerr << argv[0] << ": Error - unknown option '" << thisopt 
		     << "' used." << endl;
		oksofar=false;
	    }
	} else {
	    bool done=false;
	    for (int p=1; (!done) && thisopt[p]; ++p) {
		bool found=false;
		for (o=opts.begin(); (!found) && (o!= opts.end()); ++o) {
		    if ((*o)->Short_Name()!=thisopt[p]) continue;
		    found=true;
		    if (!(*o)->Takes_Argument()) {
			oksofar &= (*o)->Process(0);
			break;
		    } else {
			if ((*o)->Requires_Argument() && (!thisopt[p+1])) {
			    cerr << argv[0] << ": Error - option -" 
				 << thisopt[p] << " requires an argument"
				 << endl;
			    oksofar=false;
			    break;
			}
			oksofar &= (*o)->Process(&thisopt[p+1]);
			done=true;
			break;
		    }
		}
		if (!found) {
		    cerr << argv[0] << ": Error - unknown option '-" << 
			thisopt[p] << "' used." << endl;
		    oksofar=false;
		}
	    }
	}
    }

    return oksofar;
}

bool 
options::boolSetOption::Process(const char *) const 
{
    b=true;
    return true;
}

bool 
options::boolClearOption::Process(const char *) const 
{
    b=false;
    return true;
}

bool 
options::intSetOption::Process(const char *) const 
{
    var=val;
    return true;
}

bool 
options::boolOption::Process(const char *c) const 
{
    if (!c) {b=defval; return true;}

    if ((strcasecmp(c,"y")==0) ||
	(strcasecmp(c,"yes")==0) ||
	(strcasecmp(c,"true")==0) ||
	(strcasecmp(c,"1")==0) ||
	(strcasecmp(c,"on")==0)) {
	b=true;
	return true;
    } 

    if ((strcasecmp(c,"n")==0) ||
	(strcasecmp(c,"no")==0) ||
	(strcasecmp(c,"false")==0) ||
	(strcasecmp(c,"0")==0) ||
	(strcasecmp(c,"off")==0)) {
	b=false;
	return true;
    } 
    
    cerr << "Unknown boolean value for " << Long_Name() << endl;
    return false;
}

bool 
options::intOption::Process(const char *c) const {
    var=atoi(c);
    return true;
}

bool 
options::doubleOption::Process(const char *c) const 
{
    var=(double)atof(c); 
    return true;
}

bool 
options::stringOption::Process(const char *c) const 
{
    var=c; 
    return true;
}

bool 
options::actionOption::Process(const char *) const 
{
    Action();
    return true;
}

options::actionOption::~actionOption() {};

options::optionInterface::~optionInterface() {};
