//-------------------------------------------------------------------------------------------------
// <copyright file="main.cpp" company="LiquidRobotics">
//  Copyright (c) Liquid Robotics Corporation, confidential and proprietary.  All rights reserved. 
// </copyright>
//
// <summary>
//   Entry point for the Logger process, which reads from standard input and outputs
//   to a FileSet.  The command line options are as follows:
//
//		-a, --archive-dir		Set the directory where archives are stored (defaults to
//								working directory)
//
//		-c, --archive-compression	Set the type of compression used when creating
//									archive files (BZIP2 or GZIP)
//
//		-D, --debug					Set debug mode on or off
//
//		-e, --extension				Set the file extension to use for main output file
//									and archives before compression
//
//		-f, --max-files				Sets the maximum number of files to retain, including
//									archives and the main file
//
//		-g, --purge-strategy		Sets the purge strategy (OLDEST or NONE); if NONE, then
//									archive files are never deleted and the log simply
//									stops when it is full.
//
//		-k, --keep-writes-together	Determines if lines are stored within the same file
//									of if they can span files
//
//		-p, --prefix				Sets the first part of the output file and archive files
//
//		-q, --max-bytes-queued		Sets the number of bytes to store in the interthread
//									queue or 0 for no queue; using a queue allows the
//									caller to return immediately and log writes are
//									performed on a different thread.
//
//		-r, --max-retain-time		Sets the maximum number of seconds to retain archive
//									files; 0=ignore
//
//		-s, --max-file-size			Sets the maximum size of each archive file, or the
//									size of the output file before it is rolled into
//									archives (before compression)
//
//		-w, --work-dir				Sets the directory where the output file is stored
//									(defaults to the starting directory)
//
//  For each setting can be assigned as follows:
//
//	(1) Logger -m new-value-for-m -n new-value-for-n
//		Logger -mn new-value-for-m new-value-for-m
//
//	(2) Logger --setting-name new-value-for-setting
//
//	(3) Logger --setting-name=new-value-for-setting
//
// </summary>
//
// <owner>Mike Cookson</owner>
//-------------------------------------------------------------------------------------------------

#include <iostream>
#include <stdexcept>
#include <typeinfo>
#include <stdio.h>
#include <unistd.h>
#include "LqrSMACFileSet.h"
#include "ArgumentParser.h"

using namespace std;
using namespace LiquidRobotics::SMACFramework;

bool GetBuffer(ByteArray& buffer, istream& istm);

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

	try
	{
		ArgumentParser argParser(argc, argv);

		if (argParser.DebugMode())
			cout << argParser.Settings() << endl;

		FileSet fileSet(argParser.Settings());
		fileSet.Init();

		if (argParser.DebugMode())
		{
			char buffer[4096];
			FILE* fp = popen("find /usr/include -type f -print", "r");

			if (fp)
			{
				fileSet.WriteLine("First line");
				while(fgets(buffer, sizeof(buffer), fp), !ferror(fp) && !feof(fp))
				{
					string line = buffer;
					fileSet.Write(line);
				}

				pclose(fp);
				fileSet.WriteLine("Last line");
				sleep(5);
				fileSet.WriteLine("One more line");
			}
		}
		else
		{
			ByteArray buffer;
			buffer.reserve(4096);

			while(GetBuffer(buffer, cin))
				fileSet.Write(buffer);
		}

		fileSet.Shutdown();
	}
	catch(ArgumentParser::HelpFileOutput& ex)
	{
		cerr << endl
		     << argv[0] << ": " << ex.what() << endl;
	}
	catch(ArgumentParser::ProgramArgError& ex)
	{
		cerr << endl
		     << argv[0] << ": " << ex.what() << endl;
	}
	catch(exception& ex)
	{
		cerr << endl
		     << argv[0] << ": Caught " << typeid(ex).name() << ": " << ex.what() << endl;
		result = 1;
	}

	return result;
}

// GetBuffer blocks input from the stream (istm) into lines within buffer so that the fidelity within
// files can be maintained.  Only up to buffer.capacity() bytes are returned.
bool GetBuffer(ByteArray& buffer, istream& istm)
{
	const ByteArray::size_type cap = buffer.capacity();
	bool exitNow = false;

	buffer.resize(0);

	while((buffer.size() < cap) && !istm.fail() && !istm.eof() && !exitNow)
	{
		const ByteArray::byte b = (ByteArray::byte) istm.get();

		buffer.push_back(b);

		if ((b == '\r') && (buffer.size() < cap))
		{
			if (!istm.fail() && !istm.eof())
			{
				const ByteArray::byte b2 = istm.get();

				if (b2 == '\n')
					buffer.push_back(b2);
				else
					istm.unget();
			}
		}

		exitNow = (b == '\r') || (b == '\n');
	}

	bool result = buffer.size() && !istm.fail();
	return result;
}
