/* Web Polygraph       http://www.web-polygraph.org/
 * (C) 2003-2006 The Measurement Factory
 * Licensed under the Apache License, Version 2.0 */

#include "base/polygraph.h"

#include "xstd/h/iostream.h"
#include <fstream>
#include "xstd/h/sstream.h"
#include "xstd/h/iomanip.h"

#include "xstd/gadgets.h"
#include "base/BStream.h"
#include "base/polyVersion.h"
#include "base/AnyToString.h"
#include "csm/ContentDbase.h"
#include "csm/cdbEntries.h"
#include "csm/cdbBuilders.h"
#include "csm/XmlParser.h"

static String ThePrgName = "";
static enum { fmtVerbatim, fmtMarkup, fmtLinkOnly } TheFormat = fmtMarkup;
static int TheTotalLinkCount = 0;

static
bool readCont(ContentDbase *cdb, const String &fname) {
	CdbBuilder::TheLinkCount = 0;

	const String hname = fname == "-" ? String("stdin") : fname;
	clog << ThePrgName << ": adding "
		<< (TheFormat == fmtMarkup ? "objects from " : "entire ")
		<< "'" << hname << "' ... ";

	const int savedCount = cdb->count();
	CdbBuilder *b = TheFormat == fmtMarkup ? (CdbBuilder*) new MarkupParser :
		(TheFormat == fmtLinkOnly ? (CdbBuilder*) new LinkOnlyParser :
		(CdbBuilder*) new VerbatimParser);

	istream *is = fname == "-" ? 
		(istream*)&cin : (istream*)new ifstream(fname.cstr());
	b->db(cdb);

	ostringstream buf;
	char c;
	while (is->get(c))
		buf << c;
	const char *str = buf.str().c_str();
	b->configure(fname, str, str + buf.tellp());
	const bool res = b->parse();
	if (is != &cin)
		delete is;

	delete b;
	streamFreeze(buf, false);

	if (res) {
		TheTotalLinkCount += CdbBuilder::TheLinkCount;
		clog << "\t " << setw(6) << (cdb->count() - savedCount) <<
			" object(s) and " << CdbBuilder::TheLinkCount << " link(s)";
	}
	clog << endl;
	return res;
}

static
int doShow(const String &dbName) {
	ContentDbase *cdb = new ContentDbase;
	ifstream f(dbName.cstr());
	IBStream is;
	is.configure(&f, dbName);
	cdb->load(is);
	if (is.good()) {
		cdb->print(cout);
		return 0;
	}

	cerr << ThePrgName << ": error loading db from `" << dbName << "'" << endl;
	return -2;
}

static
int doAdd(const String &dbName, int fcount, char *fnames[]) {
	ContentDbase *cdb = new ContentDbase;
	fstream f(dbName.cstr(), ios::in|ios::out);

	{
		clog << ThePrgName << ": loading db from " << dbName << " ... ";
		IBStream is;
		is.configure(&f, dbName);
		cdb->load(is);
		clog << "\t " << setw(6) << cdb->count() << " objects" << endl;
	}

	if (fcount) {
		for (int i = 0; i < fcount; ++i)
			Must(readCont(cdb, fnames[i]));
	} else {
		Must(readCont(cdb, "-"));
	}

	clog << ThePrgName << ": got " << fcount << " files and " <<
		TheTotalLinkCount << " links" << endl;

	{
		clog << ThePrgName << ": storing db in " << dbName << " ... ";
		f.clear();
		f.seekg(0);
		OBStream os;
		os.configure(&f, dbName);
		cdb->store(os);
		if (os.good())
			clog << "\t " << setw(6) << cdb->count() << " objects" << endl;
		else
			clog << "error: " << Error::Last() << endl;
	}
	f.close();
	return 0;
}

static
int usage() {
	(void)PolyVersion();
	cerr << "usage: " << ThePrgName << " <database.cdb> <command> [--option] [filename ...]" << endl
		<< "commands: " << endl
		<< "\tshow - " << " dump database contents to stdout" << endl
		<< "\tadd  - " << " add file(s) contents to the database" << endl
		<< "options: " << endl
		<< "\tformat <markup|linkonly|verbatim|> " << "split each file into markup tags, adjust links, or add as is" << endl
		;
	return 0;
}

int main(int argc, char *argv[]) {
	ThePrgName = argv[0];

	if (argc < 3)
		return usage();

	int argOff = 1;
	const String dbName = argv[argOff++];
	const String cmd = argv[argOff++];

	if (cmd != "show" && cmd != "add") {
		usage();
		cerr << "unknown command `" << cmd << "', expected `show' or `add'" << endl;
		return -1;
	}

	if (argOff < argc && strstr(argv[argOff], "--") == argv[argOff]) {
		const String option = argv[argOff++];
		if (option != "--format") {
			usage();
			cerr << "unknown option '" << option << "', expected 'format'" << endl;
			return -1;
		}
			
		const String format = argv[argOff++];
		if (format == "markup")
			TheFormat = fmtMarkup;
		else
		if (format == "linkonly")
			TheFormat = fmtLinkOnly;
		else
		if (format == "verbatim")
			TheFormat = fmtVerbatim;
		else {
			usage();
			cerr << "unknown format '" << format << "', expected 'markup' or 'verbatim'" << endl;
			return -1;
		}
	}

	if (cmd == "show")
		return doShow(dbName);
	else
	if (cmd == "add")
		return doAdd(dbName, argc-argOff, argv+argOff);

	usage();
	cerr << "unknown command `" << cmd << "', expected `show' or `add'" << endl;
	return -1;
}


syntax highlighted by Code2HTML, v. 0.9.1