/*
 * Copyright (c) 2006-2006 Endace Technology Ltd, Hamilton, New Zealand.
 * All rights reserved.
 *
 * This source code is proprietary to Endace Technology and no part
 * of it may be redistributed, published or disclosed except as outlined in
 * the written contract supplied with this product.
 *
 * $Id: dagsnap_cli.c 4038 2006-04-03 05:14:25Z koryn $
 */

/* dagsnap headers. */
#include "dagsnap_model.h"
#include "dagsnap_view.h"

/* Endace headers. */
#include "dagapi.h"
#include "dagutil.h"
#include "dagclarg.h"


/* CVS Header. */
static const char* const kCvsHeader __attribute__ ((unused)) = "$Id: dagsnap_cli.c 4038 2006-04-03 05:14:25Z koryn $";
static const char* const kRevisionString = "$Revision: 4038 $";


#define OPTBUFSIZE ONE_KIBI
#define BUFSIZE 256


/* Commandline argument codes. */
enum
{
#if defined(__FreeBSD__) || defined(__linux__) || defined (__NetBSD__) || (defined(__SVR4) && defined(__sun)) || (defined(__APPLE__) && defined(__ppc__))
	CLA_PERFORMANCE,
#endif
	CLA_DEVICE,
	CLA_HELP,
	CLA_VERBOSE,
	CLA_VERSION,
	CLA_MAXDATA_MEBIBYTES,
	CLA_OUTFILE_NAME,
	CLA_RUNTIME_SECONDS
};


/* Internal routines. */
static void print_version(void);
static void print_usage(ClArgPtr clarg);
static void anysig(int sig);


/* Implementation of internal routines. */
static void
print_version(void)
{
	printf("dagsnap (DAG %s) %s\n", kDagReleaseVersion, kRevisionString);
}


static void
print_usage(ClArgPtr clarg)
{
	print_version();
	printf("dagsnap - Endace DAG card capture utility.\n");
	printf("Usage: dagsnap [options]\n");
	dagclarg_display_usage(clarg, stdout);
	printf("\nWith -v three columns are printed per second.\n");
	printf("    1. The cumulative total of data written out.\n");
	printf("    2. The buffer occupancy. Small values indicate no packet loss.\n");
	printf("    3. The rate at which data is currently being written.\n");
}


static void
anysig(int sig)
{
	_exit(EXIT_SUCCESS);
}


/* Public routines. */
int
dagsnap_main(int argc, const char * argv[])
{
	DagsnapConfigPtr config = NULL;
	DagsnapPtr dagsnap_ptr = NULL;
	FILE* errorfile = NULL;
	ClArgPtr clarg = NULL;
	int code;
	int result;
	int argindex;
	int index;
	uint32_t runtime_seconds = 0;
	int dagstream;
	uint32_t max_bytes = 0;
	int mebibytes;
	int max_performance = 0;
	char dagname_buffer[DAGNAME_BUFSIZE] = "dag0";
	char dagname[DAGNAME_BUFSIZE];
	char outfile_buffer[BUFSIZE];
	
	dagutil_set_progname("dagsnap");
	dagutil_set_signal_handler(anysig);

	/* Set up default DAG device. */
	if (-1 == dag_parse_name(dagname_buffer, dagname, DAGNAME_BUFSIZE, &dagstream))
	{
		dagutil_panic("dag_parse_name(%s): %s\n", dagname_buffer, strerror(errno));
	}

	/* Set up the command line options. */
	clarg = dagclarg_init(argc, (const char * const *)argv);

	dagclarg_add(clarg, "This page.", "--help", 'h', CLA_HELP);
	dagclarg_add_long_option(clarg, CLA_HELP, "--usage");
	dagclarg_add_short_option(clarg, CLA_HELP, '?');
	dagclarg_add_string(clarg, "DAG device to use.", "--device", 'd', "device", dagname_buffer, DAGNAME_BUFSIZE, CLA_DEVICE);
	dagclarg_add(clarg, "Increase verbosity.", "--verbose", 'v', CLA_VERBOSE);
	dagclarg_add(clarg, "Display version information.", "--version", 'V', CLA_VERSION);
#if defined(__FreeBSD__) || defined(__linux__) || defined (__NetBSD__) || (defined(__SVR4) && defined(__sun)) || (defined(__APPLE__) && defined(__ppc__))	
	dagclarg_add(clarg, "Maximize disk write performance - will only write in chunks.", "--maxwrite", 'j', CLA_PERFORMANCE);
#endif
	dagclarg_add_int(clarg, "Maximum amount of data to write per call in MiB (default 4).", "--maxdata", 'm', "mebibytes", &mebibytes, CLA_MAXDATA_MEBIBYTES);
	dagclarg_add_string(clarg, "Output file name (default is stdout).", "--outfile", 'o', "filename", outfile_buffer, BUFSIZE, CLA_OUTFILE_NAME);
	dagclarg_add_uint(clarg, "Runtime in seconds.", "--runtime", 's', "seconds", &runtime_seconds, CLA_RUNTIME_SECONDS);

	/* Parse the command line options. */
	result = dagclarg_parse(clarg, errorfile, &argindex, &code);
	while (1 == result)
	{
		switch (code)
		{
			case CLA_HELP:
				print_usage(clarg);
				return EXIT_SUCCESS;
				break;

			case CLA_DEVICE:
				if (-1 == dag_parse_name(dagname_buffer, dagname, DAGNAME_BUFSIZE, &dagstream))
				{
					dagutil_panic("dag_parse_name(%s): %s\n", dagname_buffer, strerror(errno));
				}
				break;

			case CLA_VERBOSE:
				dagutil_inc_verbosity();
				break;

			case CLA_VERSION:
				print_version();
				return EXIT_SUCCESS;
				break;

#if defined(__FreeBSD__) || defined(__linux__) || defined (__NetBSD__) || (defined(__SVR4) && defined(__sun)) || (defined(__APPLE__) && defined(__ppc__))
			case CLA_PERFORMANCE:
				max_performance = 1;
				break;
#endif

			case CLA_MAXDATA_MEBIBYTES:
				max_bytes = mebibytes * ONE_MEBI;
				break;

			case CLA_OUTFILE_NAME:
				break;

			case CLA_RUNTIME_SECONDS:
				break;

			default:
				/* Unknown option. */
				dagutil_error("unknown option %s\n", argv[argindex]); 
				print_usage(clarg);
				return EXIT_FAILURE;
		}
		result = dagclarg_parse(clarg, errorfile, &argindex, &code);
	}

	if (-1 == result)
	{
		if (argindex < argc)
		{
			dagutil_error("while processing option %s\n", argv[argindex]);
		}
		dagclarg_display_usage(clarg, stderr);
		return EXIT_FAILURE;
	}

	 /* Display unprocessed arguments if verbose flag was given. */
	argv = (const char **) dagclarg_get_unprocessed_args(clarg, &argc);
	if ((NULL != argv) && (0 < argc) && (1 < dagutil_get_verbosity()))
	{
		for (index = 0; index < argc; index++)
		{
			dagutil_verbose_level(2, "unprocessed argument: '%s'\n", argv[index]);
		}
		dagutil_panic("Too many options!\n");
	}

#if defined(_WIN32)
	/* If we don't set stdout to binary mode, redirections will not work correctly */
	_setmode(_fileno (stdout), _O_BINARY);
#endif /* _WIN32 */
	
	/* ClargPtr should no longer be necessary. */
	dagclarg_dispose(clarg);
	
	/* Create a configuration to pass to the main capture loop. */
	config = dagsnap_config_init();

	/* Set up the configuration options. */
	dagsnap_config_set_device(config, dagname);
	dagsnap_config_set_outfile_name(config, (const char*) outfile_buffer);
	dagsnap_config_set_dagstream(config, dagstream);
	dagsnap_config_set_data_bytes(config, max_bytes);
	dagsnap_config_set_run_seconds(config, runtime_seconds);
	dagsnap_config_set_verbosity(config, dagutil_get_verbosity());
#if defined(__FreeBSD__) || defined(__linux__) || defined (__NetBSD__) || (defined(__SVR4) && defined(__sun)) || (defined(__APPLE__) && defined(__ppc__))
	dagsnap_config_set_max_performance(config, max_performance);
#endif

	dagsnap_ptr = dagsnap_create(config);
	if (NULL == dagsnap_ptr)
	{
		return EXIT_FAILURE;
	}

	if (dagutil_get_verbosity())
	{
		dagsnap_view_init(dagsnap_ptr, dagname, dagutil_get_verbosity());
	}

	result = dagsnap_capture(dagsnap_ptr);
	
	dagsnap_dispose(dagsnap_ptr);

	return result;
}


#ifndef ENDACE_UNIT_TEST
int
main(int argc, const char* const * argv)
{
	return dagsnap_main(argc, (const char**) argv);
}
#endif /* ENDACE_UNIT_TEST */
