/**
    bambam
    Copyright (C) 2019 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 <config.h>

#include <libmaus2/vcf/VCFParser.hpp>
#include <libmaus2/util/ArgInfo.hpp>
#include <libmaus2/util/ArgParser.hpp>
#include <libmaus2/lz/BgzfDeflate.hpp>
#include <libmaus2/fastx/FastAReader.hpp>

#include <biobambam2/Licensing.hpp>

static int getDefaultVerbose() { return 0; }
static int getDefaultGZ() { return 0; }

int vcfreplacecontigsmap(libmaus2::util::ArgParser const & arg, std::istream & in, std::ostream & out)
{
	bool const gz = arg.argPresent("gz");

	libmaus2::lz::BgzfOutputStream::unique_ptr_type pBOS;

	if ( gz )
	{
		libmaus2::lz::BgzfOutputStream::unique_ptr_type tBOS(new libmaus2::lz::BgzfOutputStream(out));
		pBOS = std::move(tBOS);
	}

	std::ostream & vout = gz ? *pBOS : out;

	libmaus2::vcf::VCFParser vcf(in);

	if ( ! ( 1 < arg.size() ) )
	{
		std::cerr << "[E] usage: " << arg.progname << " <in.fa> <in.map> <in.vcf" << std::endl;
		return EXIT_FAILURE;
	}

	std::string const fafn = arg[0];
	std::string const mapfn = arg[1];
	std::vector<libmaus2::bambam::Chromosome> V;
	std::set<std::string> S;
	{
		libmaus2::fastx::FastAReader FA(fafn);
		libmaus2::fastx::FastAReader::pattern_type pat;
		while ( FA.getNextPatternUnlocked(pat) )
		{
			std::string const name = pat.getShortStringId();
			V.push_back(libmaus2::bambam::Chromosome(name,pat.spattern.size()));
			S.insert(name);
			std::cerr << "[V] pushed " << name << "[" << pat.spattern.size() << "]" << std::endl;
		}
	}
	std::map<std::string,std::string> Vmap;
	{
		libmaus2::aio::InputStreamInstance ISI(mapfn);
		libmaus2::lz::PlainOrGzipStream POS(ISI);
		std::string line;
		libmaus2::util::TabEntry<> TE;
		while ( std::getline(POS,line) )
			if ( line.size() )
			{
				char const * ca = line.c_str();
				char const * ce = ca + line.size();
				TE.parse(ca,ca,ce);
				if ( TE.size() >= 2 )
				{
					std::string const & from = TE.getString(0,ca);
					std::string const & to = TE.getString(1,ca);
					Vmap[from] = to;
				}
			}
	}

	vcf.setChromosomeVector(V);
	vcf.printText(vout);

	std::pair<
        	libmaus2::util::TabEntry<> const *,
                char const *
	> P;

	std::pair<
		std::vector<std::string>,
		::libmaus2::trie::LinearHashTrie<char,uint32_t>::shared_ptr_type
	> const Pcontig = vcf.getContigNamesAndTrie();

	uint64_t line = 0;
	while ( (P = vcf.readEntry()).first )
	{
		if ( P.first->size() )
		{
			std::string Schr = P.first->getString(0,P.second);

			if ( Vmap.find(Schr) != Vmap.end() )
				Schr = Vmap.find(Schr)->second;

			if ( Pcontig.second->searchCompleteNoFailure(Schr.c_str(),Schr.c_str()+Schr.size()) != -1 )
			{
				vout.write(Schr.c_str(),Schr.size());

				for ( uint64_t i = 1; i < P.first->size(); ++i )
				{
					vout.put('\t');
					vout << P.first->getString(i,P.second);
				}

				vout.put('\n');

				line += 1;

				if ( line % (1024*1024) == 0 )
					std::cerr << "[V] " << line << std::endl;
			}
			else
			{
				std::cerr << "[E] sequence " << Schr << " does not appear in FastA file provided" << std::endl;
			}
		}
	}

	if ( gz )
	{
		pBOS->flush();
		pBOS->addEOFBlock();
		pBOS.reset();
	}

	return EXIT_SUCCESS;
}

int main(int argc, char * argv[])
{
	try
	{
		std::vector<libmaus2::util::ArgParser::ArgumentDefinition> Vformat;
		Vformat.push_back(libmaus2::util::ArgParser::ArgumentDefinition("","version",true));
		Vformat.push_back(libmaus2::util::ArgParser::ArgumentDefinition("v","verbose",true));
		Vformat.push_back(libmaus2::util::ArgParser::ArgumentDefinition("h","help",true));
		Vformat.push_back(libmaus2::util::ArgParser::ArgumentDefinition("","gz",false));

		::libmaus2::util::ArgParser const arg(argc,argv,Vformat);

		if ( arg.uniqueArgPresent("version") )
		{
			std::cerr << ::biobambam2::Licensing::license();
			return EXIT_SUCCESS;
		}
		else if ( arg.uniqueArgPresent("help") )
		{
			std::cerr << ::biobambam2::Licensing::license();
			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/--verbose <["+::biobambam2::Licensing::formatNumber(getDefaultVerbose())+"]>", "print progress report (default: 1)" ) );

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

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

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