/*
    biobambam2
    Copyright (C) 2020 German Tischler

    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 <iostream>
#include <libmaus2/util/ArgParser.hpp>
#include <libmaus2/fastx/StreamFastAReader.hpp>
#include <libmaus2/lz/PlainOrGzipStream.hpp>

#include <biobambam2/BamBamConfig.hpp>
#include <biobambam2/Licensing.hpp>

#include <regex>

#include <libmaus2/lz/GzipOutputStream.hpp>

static uint64_t getDefaultLineLength()
{
	return 80;
}

/**
 * read a FastA file (possibly gziped) from stdin, select sequences with (short)
 * names matching a given regular expression (argument, Posix extended regex)
 * and output selected sequences on stdout (gziped if -g or --gzip is set).
 *
 * Options:
 * - singleline: output a single line of sequence data per record (i.e. do not wrap)
 * - longname: do not shorten the sequence name line
 * - dataonly: output data only, drop FastA headers (lines starting with >)
 * - up: transform all sequence symbols to upper case
 * - gzip: compress output using gzip
 * - verbose: print which sequences are kept and which are discarded
 * - l<len>: wrap sequence lines after this number of symbols (default 80)
 **/
int fastaselectreg(libmaus2::util::ArgParser const & arg)
{
	libmaus2::lz::PlainOrGzipStream POS(std::cin);
	libmaus2::fastx::StreamFastAReaderWrapper SFA(POS);
	libmaus2::fastx::StreamFastAReaderWrapper::pattern_type pattern;
	uint64_t const linelength = arg.uniqueArgPresent("l") ? arg.getUnsignedNumericArg<uint64_t>("l") : getDefaultLineLength();
	std::regex reg(arg[0],std::regex_constants::extended);

	bool const singleline = arg.argPresent("s") || arg.argPresent("singleline");
	bool const longname = arg.argPresent("L") || arg.argPresent("longname");
	bool const dataonly = arg.argPresent("d") || arg.argPresent("dataonly");
	bool const up = arg.argPresent("u") || arg.argPresent("toupper");
	bool const gzip = arg.argPresent("g") || arg.argPresent("gzip");
	bool const verbose = arg.argPresent("verbose");

	libmaus2::lz::GzipOutputStream::unique_ptr_type gzptr;
	std::ostream & ostr = std::cout;
	if ( gzip )
	{
		libmaus2::lz::GzipOutputStream::unique_ptr_type tgzptr(new libmaus2::lz::GzipOutputStream(ostr));
		gzptr = std::move(tgzptr);
	}
	std::ostream & OSI = gzptr ? *gzptr : ostr;
	while ( SFA.getNextPatternUnlocked(pattern) )
	{
		std::string & spat = pattern.spattern;

		if ( up )
			for ( uint64_t i = 0; i < spat.size(); ++i )
				spat[i] = toupper(spat[i]);

		std::string const shortname = pattern.getShortStringId();

		if ( std::regex_match(shortname,reg) )
		{
			if ( verbose )
				std::cerr << "[K] keeping " << shortname << std::endl;

			if ( !longname )
				pattern.sid = shortname;

			if ( dataonly )
				OSI.write(pattern.spattern.c_str(),pattern.spattern.size());
			else if ( singleline )
				OSI << pattern;
			else
				pattern.printMultiLine(OSI,linelength);
		}
		else if ( verbose )
		{
			std::cerr << "[K] discarding " << shortname << std::endl;
		}
	}

	return EXIT_SUCCESS;
}

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

		if (
			arg.uniqueArgPresent("v") || arg.uniqueArgPresent("version")
		)
		{
			std::cerr << ::biobambam2::Licensing::license();
			return EXIT_SUCCESS;
		}
		else if (
			arg.uniqueArgPresent("h") || arg.uniqueArgPresent("help") || arg.size() < 1
		)
		{
			std::cerr << ::biobambam2::Licensing::license();
			std::cerr << std::endl;
			std::cerr << "usage: " << arg.progname << " <regex> <in.fasta > out.fasta" << std::endl;
			std::cerr << std::endl;
			std::cerr << "options:" << std::endl;
			std::cerr << std::endl;

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

			V.push_back ( std::pair<std::string,std::string> ( "-v/--version", "print version number and quit" ) );
			V.push_back ( std::pair<std::string,std::string> ( "-h/--help", "print help message and quit" ) );
			V.push_back ( std::pair<std::string,std::string> ( "-l<cols>", "line length (default: "+libmaus2::util::NumberSerialisation::formatNumber(getDefaultLineLength(),0)+")" ) );
			V.push_back ( std::pair<std::string,std::string> ( "-s/--singleline", "do not wrap sequence data lines" ) );
			V.push_back ( std::pair<std::string,std::string> ( "-L/--longname", "do not shorten name" ) );
			V.push_back ( std::pair<std::string,std::string> ( "-d/--dataonly", "do not print FastA header (data only)" ) );
			V.push_back ( std::pair<std::string,std::string> ( "-u/--toupper", "convert sequence symbols to upper case" ) );
			V.push_back ( std::pair<std::string,std::string> ( "-g/--gzip", "compress output" ) );

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

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

		}

		return fastaselectreg(arg);
	}
	catch(std::exception const & ex)
	{
		std::cerr << ex.what() << std::endl;
		return EXIT_FAILURE;
	}
}
