/*
 * Program options
 *
 * Copyright (C) 2003--2010  Enrico Zini <enrico@debian.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#define APPNAME PACKAGE
#else
#warning No config.h found: using fallback values
#define APPNAME "missing appname"
#define VERSION "unknown"
#endif

#include "options.h"
#include "util/output.h"
#include "util/netsender.h"
#include "util/netwatcher.h"
#include "scanner/iwscan.h"
#include "GuessnetParser.h"
#include "IfaceParser.h"

#include <wibble/commandline/parser.h>

#if 0
#include <cstdio>
#include <cstdarg>
#include <cstdlib>
#endif

using namespace std;

namespace wibble {
namespace commandline {

struct GuessnetOptions : public StandardParserWithManpage
{
public:
	BoolOption* verbose;
	BoolOption* debug;
	BoolOption* syslog;
	BoolOption* ifupdown;
	BoolOption* autofilter;
	StringOption* defprof;
	IntOption* timeout;
	IntOption* inittime;
	IntOption* initdelay;
	IntOption* iwscan_tries;
	ExistingFileOption* configfile;

	GuessnetOptions() 
		: StandardParserWithManpage(APPNAME, VERSION, 8, "enrico@enricozini.org")
	{
		usage = "[options] [iface]";
		description = "Guess the current network location";

		verbose = add<BoolOption>("verbose", 'v', "verbose", "",
						"enable verbose output");
		debug = add<BoolOption>("debug", 0, "debug", "",
						"enable debugging output (including verbose output)");
		syslog = add<BoolOption>("syslog", 0, "syslog", "",
						"send messages to syslog facility DAEMON, in addition to stderr");
		configfile = add<ExistingFileOption>("configfile", 'C', "config-file", "",
						"name of the configuration file to read (default: stdin or"
						"/etc/network/interfaces in ifupdown mode");
		ifupdown = add<BoolOption>("ifupdown", 'i', "ifupdown-mode", "",
						"use /etc/network/interfaces file instead of the usual"
						" guessnet configuration file");
		defprof = add<StringOption>("defprof", 'd', "default", "name",
						"profile name to report if no known networks are found"
						" (defaults to \"none\")");
		timeout = add<IntOption>("timeout", 't', "timeout", "seconds",
						"timeout (in seconds) used to wait for response packets"
						" (defaults to 5 seconds)");
		inittime = add<IntOption>("inittime", 0, "init-time", "seconds",
						"time (in seconds) to wait for the interface to initialize"
						" when not found already up (defaults to 3 seconds)");
		autofilter = add<BoolOption>("autofilter", 0, "autofilter", "",
						"enable autofiltering interfaces based on their name (default: off)");
		initdelay = add<IntOption>("initdelay", 0, "init-delay", "seconds",
		                           "sleep a given number of seconds before starting operations (default: 0)");
		iwscan_tries = add<IntOption>("iwscantries", 0, "iwscan-tries", "",
		                              "number of tries for wireless network scanning (default: 1)");
	}
};

}
}


Options options;

// Initialize the environment with default values
Options::Options()
	: iface("eth0"), defprof("none"), timeout(5), init_timeout(3),
	  iwscan_tries(1), iface_filter(0)
{
}

Options::~Options()
{
	if (iface_filter) delete iface_filter;
}

void Options::init(int argc, const char* argv[])
{
	wibble::commandline::GuessnetOptions opts;

	if (opts.parse(argc, (const char**)argv))
		exit(0);

	// Set verbosity
	util::Output::get().verbose(opts.verbose->boolValue());
	util::Output::get().debug(opts.debug->boolValue());
	util::Output::get().syslog(opts.syslog->boolValue());

	// Find out the interface to be tested
	if (opts.hasNext())
		iface = opts.next();
	else
		iface = "eth0";

	// Find out the configuration file to use
	if (opts.hasNext())
		config_file = opts.next();
	else if (opts.configfile->isSet())
		config_file = opts.configfile->stringValue();

	// Find out the default profile name
	if (opts.defprof->boolValue())
	{
		defprof = opts.defprof->stringValue();
		::verbose("Default profile set to `%s'\n", defprof.c_str());
	}

	// Find out the test timeout
	if (opts.timeout->boolValue())
		timeout = opts.timeout->intValue();

	// Find out the init timeout
	if (opts.inittime->boolValue())
		init_timeout = opts.inittime->intValue();

	// Set autofiltering
	autofilter = opts.autofilter->boolValue();

	// Set initial delay to avoid race conditions
	initdelay = opts.initdelay->intValue();

	// Number of iwscan tries
	if (opts.iwscan_tries->boolValue())
		iwscan_tries = opts.iwscan_tries->intValue();

	// Check user id
	/*
	if (geteuid() != 0)
		fatal_error("You must run this command as root.");
	*/

	// Find out wether we should run in ifupdown mode
	bool ifupdown_mode = opts.ifupdown->boolValue();
	if (!ifupdown_mode)
	{
		const char* pname = strrchr(argv[0], '/');
		pname = pname ? pname + 1 : argv[0];
		if (strcmp(pname, "guessnet-ifupdown") == 0)
			ifupdown_mode = true;
	}

	if (ifupdown_mode)
		init_ifupdown(opts);
	else
		init_standalone(opts);

	util::NetSender::configure(iface);
	util::NetWatcher::configure(iface);
	scanner::IWScan::configure(iface);
	
	if (ifupdown_mode)
		parse_ifupdown_config();
	else
		parse_guessnet_config();
}

void Options::init_standalone(wibble::commandline::GuessnetOptions& opts)
{
	// Nothing to do
}

void Options::init_ifupdown(wibble::commandline::GuessnetOptions& opts)
{
	// We have a default config file name in ifupdown mode
	if (options.config_file.empty())
		options.config_file = "/etc/network/interfaces";

	IfaceParser::parseMapping(stdin);
}

void Options::parse_guessnet_config()
{
	/* Open the specified config file or stdin if not specified */
	FILE* input = stdin;
	if (!config_file.empty())
	{
		input = fopen(config_file.c_str(), "rt");
		if (!input)
			throw wibble::exception::File(config_file, "opening file");
	}

	GuessnetParser::parse(input);

	if (input != stdin)
		fclose(input);
}

void Options::parse_ifupdown_config()
{
	/* Open the specified config file or stdin if not specified */
	FILE* input = fopen(config_file.c_str(), "rt");;
	if (!input)
		throw wibble::exception::File(config_file, "opening file");

	if (iface_filter)
		IfaceParser::parse(input, *iface_filter);
	else
		IfaceParser::parse(input);

	fclose(input);
}

// vim:set ts=4 sw=4:
