#include <stdio.h>
#include <getopt.h>
#include <errno.h>
#include "common.h"

static void yyoutput(ostream & out)
{
	vector<CRcsFile>::const_iterator i;
	for(i = gRcsFiles.begin(); i != gRcsFiles.end(); ++i)
	{
		const CRcsFile & rcs = *i;
		rcs.print(out);
	}
}

extern "C" {
	static int sortRevFile(const void *r1, const void *r2);
}

static int sortRevFile(const void *r1, const void *r2)
{
	const CRevNumber & rev1 = ((CRevFile *)r1)->RevNum();
	const CRevNumber & rev2 = ((CRevFile *)r2)->RevNum();

	return rev1.cmp(rev2);
}

static void yygraph(const CRcsFile & rcs)
{
	const vector<CRevFile> & allrevs = rcs.AllRevs();
	qsort((CRevFile *)allrevs.begin(), allrevs.size(), sizeof(CRevFile), sortRevFile);
	vector<CRevFile>::const_iterator i;
	for(i = allrevs.begin(); i != allrevs.end(); ++i)
	{
		const CRevNumber & rev = i->RevNum();
		cout << '\t' << rev.str() << '\n';
	}

}

static void yygraph(void)
{
	vector<CRcsFile>::const_iterator i;
	for(i = gRcsFiles.begin(); i != gRcsFiles.end(); ++i)
	{
		const CRcsFile & rcs = *i;
		yygraph(rcs);
	}
}

static const char *const cmd_usage[] =
{
	"CVSTREE synopsis is: cvs [cvsoptions] log [logoptions] | cvstree [cvstree options]\n",
	"CVSTREE options are:\n",
	"        -v           Verbose the output similar to cvs log (default)\n",
	"        -o output    Output in a file\n",
	"        -g           Output a graph of the revisions\n",
	"        -1           Debug the lexer (flex output)\n",
	"        -2           Debug the parser (bison output)\n",
	"        -3           Debug both the parser and the lexer\n",
	"        --help,-h    Print this help\n",
	"        --version    Print the version number\n",
	NULL
};

static struct option long_options[] =
{
	{"help", 0, NULL, 'h'},
	{"version", 0, NULL, '*'},
	{0, 0, 0, 0}
};

static void usage (const char *const *cpp)
{
	for (; *cpp; cpp++)
		fprintf (stderr, *cpp);
	exit(1);
}

int main(int argc, char **argv)
{
	int c;
	int option_index = 0;
	bool outGraph = false;
	CLogStr output;
	CLogStr input;

#if qCvsDebug
	yydebug = 0;
	yy_flex_debug = 0;
#endif

	while ((c = getopt_long
			(argc, argv, "+o:f:g123vh", long_options, &option_index))
		   != EOF)
	{
		switch (c)
		{
		case '1':
#if qCvsDebug
			yy_flex_debug = 1;
#endif
			break;
		case '2':
#if qCvsDebug
			yydebug = 1;
#endif
			break;
		case '3':
#if qCvsDebug
			yydebug = 1;
			yy_flex_debug = 1;
#endif
			break;
		case 'h':
			usage (cmd_usage);
			break;
		case 'g':
			outGraph = true;
			break;
		case 'v':
			outGraph = false;
			break;
		case 'o':
			output = optarg;
			break;
		case 'f':
			input = optarg;
			break;
		case '*':
			cerr << "Version of " << argv[0] << " is $Revision: 1.2 $\n";
			exit(1);
			break;
		case '?':
		default:
			usage (cmd_usage);
		}
	}

	argc -= optind;
	argv += optind;
	if (argc != 0)
		usage (cmd_usage);

	if(!input.empty())
	{
		yyin = fopen(input, "r");
		if(yyin == 0L)
		{
			cerr << "Error while opening '" << input << "'\n";
			exit(errno);
		}
	}
	else
		yyin = stdin;
	yyreset();
	yyrestart(yyin);
	yyparse();

	if(outGraph)
	{
		yygraph();
	}
	else
	{
 		filebuf fbuf;
 		streambuf *buf = 0L;
	
 		if(!output.empty())
 		{
 			buf = fbuf.open(output, "w");
 			if(buf == 0L)
 			{
 				cerr << "Error while opening '" << output << "'\n";
 				exit(errno);
			}
 			ostream out(buf);
 			yyoutput(out);
 			fbuf.close();
 		}
 		else
			yyoutput(cout);
	}
	if(!input.empty())
		fclose(yyin);
}
