/**
    bambam
    Copyright (C) 2009-2019 German Tischler-Höhle
    Copyright (C) 2011-2013 Genome Research Limited

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**/
#include <config.h>

#include <libmaus2/bambam/BamNumericalIndexGenerator.hpp>
#include <libmaus2/lz/BgzfInflate.hpp>
#include <libmaus2/util/ArgInfo.hpp>
#include <libmaus2/util/Concat.hpp>
#include <libmaus2/util/MemUsage.hpp>

#include <biobambam2/Licensing.hpp>

bool getDefaultVerbose() { return true; }
bool getDefaultDisableValidation() { return false; }

int bamnumericalindex(libmaus2::util::ArgInfo const & arginfo, std::istream & in)
{
	bool const debug = arginfo.getValue<unsigned int>("debug",0);
	unsigned int const verbose = arginfo.getValue<unsigned int>("verbose",getDefaultVerbose());
	bool const validate = !(arginfo.getValue<unsigned int>("disablevalidation",getDefaultDisableValidation()));
	std::string const tmpfileprefix = arginfo.getValue<std::string>("tmpfile",arginfo.getDefaultTmpFileName());
	std::string const numfn = arginfo.getUnparsedValue("numerical",std::string());
	uint64_t const nummod = arginfo.getValueUnsignedNumeric<uint64_t>("nummod",1024);

	std::string prodfn;

	if ( numfn.size() )
	{
		prodfn = numfn;
	}
	else
	{
		prodfn = tmpfileprefix + "_numtmp";
		libmaus2::util::TempFileRemovalContainer::addTempFile(prodfn);
	}

	libmaus2::lz::BgzfInflate<std::istream> rec(in);
	libmaus2::bambam::BamNumericalIndexGenerator::unique_ptr_type Pnum(
		new libmaus2::bambam::BamNumericalIndexGenerator(prodfn,nummod,verbose,validate,debug)
	);

	libmaus2::autoarray::AutoArray<uint8_t> B(libmaus2::lz::BgzfConstants::getBgzfMaxBlockSize());
	libmaus2::lz::BgzfInflateInfo rinfo;
	while ( ! (rinfo=rec.readAndInfo(reinterpret_cast<char *>(B.begin()),B.size())).streameof )
		Pnum->addBlock(B.begin(),rinfo.compressed,rinfo.uncompressed);

	Pnum.reset();

	if ( ! numfn.size() )
	{
		libmaus2::aio::InputStreamInstance::unique_ptr_type ISI(new libmaus2::aio::InputStreamInstance(prodfn));
		libmaus2::util::Concat::concat(*ISI,std::cout);
		ISI.reset();
		libmaus2::aio::FileRemoval::removeFile(prodfn);
	}

	return EXIT_SUCCESS;
}

int main(int argc, char * argv[])
{
	try
	{
		::libmaus2::util::ArgInfo const arginfo(argc,argv);

		for ( uint64_t i = 0; i < arginfo.restargs.size(); ++i )
			if (
				arginfo.restargs[i] == "-v"
				||
				arginfo.restargs[i] == "--version"
			)
			{
				std::cerr << ::biobambam2::Licensing::license();
				return EXIT_SUCCESS;
			}
			else if (
				arginfo.restargs[i] == "-h"
				||
				arginfo.restargs[i] == "--help"
			)
			{
				std::cerr << ::biobambam2::Licensing::license();
				std::cerr << std::endl;
				std::cerr << "Key=Value pairs:" << std::endl;
				std::cerr << std::endl;

				std::vector< std::pair<std::string,std::string> > V;

				V.push_back ( std::pair<std::string,std::string> ( "verbose=<["+::biobambam2::Licensing::formatNumber(getDefaultVerbose())+"]>", "print progress report (default: 1)" ) );
				V.push_back ( std::pair<std::string,std::string> ( "disablevalidation=<["+::biobambam2::Licensing::formatNumber(getDefaultDisableValidation())+"]>", "disable alignment validation (default: 0)" ) );
				V.push_back ( std::pair<std::string,std::string> ( "tmpfile=<["+arginfo.getDefaultTmpFileName()+"]>", "temporary file prefix (default: create in current directory)" ) );

				::biobambam2::Licensing::printMap(std::cerr,V);

				std::cerr << std::endl;
				return EXIT_SUCCESS;
			}

		return bamnumericalindex(arginfo,std::cin);
	}
	catch(std::exception const & ex)
	{
		std::cerr << ex.what() << std::endl;
		return EXIT_FAILURE;
	}
}
