/**
    bambam
    Copyright (C) 2009-2013 German Tischler
    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 <iostream>
#include <queue>

#include <libmaus2/aio/OutputStreamInstance.hpp>

#include <libmaus2/bambam/AdapterFilter.hpp>
#include <libmaus2/bambam/BamAlignment.hpp>
#include <libmaus2/bambam/BamBlockWriterBaseFactory.hpp>
#include <libmaus2/bambam/BamMultiAlignmentDecoderFactory.hpp>
#include <libmaus2/bambam/BamWriter.hpp>
#include <libmaus2/bambam/ProgramHeaderLineSet.hpp>
#include <libmaus2/fastx/acgtnMap.hpp>
#include <libmaus2/rank/popcnt.hpp>
#include <libmaus2/util/ArgInfo.hpp>
#include <libmaus2/util/Histogram.hpp>
#include <libmaus2/bambam/BamDefaultAdapters.hpp>
#include <biobambam2/Licensing.hpp>

static int getDefaultVerbose() { return 1; }

int bamadapterhistogram(::libmaus2::util::ArgInfo const & arginfo)
{
	{
		std::istringstream istr(libmaus2::bambam::BamDefaultAdapters::getDefaultAdapters());
		libmaus2::bambam::BamDecoder bamdec(istr);
		libmaus2::bambam::BamAlignment const & algn = bamdec.getAlignment();

		while ( bamdec.readAlignment() )
			std::cout << algn.getName() << "\t" << algn.getRead() << "\n";
	}

	if ( isatty(STDIN_FILENO) )
	{
		::libmaus2::exception::LibMausException se;
		se.getStream() << "Refusing to read binary data from terminal, please redirect standard input to pipe or file." << std::endl;
		se.finish();
		throw se;
	}

	int const verbose = arginfo.getValue<int>("verbose",getDefaultVerbose());

	libmaus2::bambam::BamAlignmentDecoderWrapper::unique_ptr_type decwrapper(
		libmaus2::bambam::BamMultiAlignmentDecoderFactory::construct(
			arginfo
		)
	);
	libmaus2::bambam::BamAlignmentDecoder & bamdec = decwrapper->getDecoder();
	libmaus2::bambam::BamAlignment const & algn = bamdec.getAlignment();

	uint64_t alcnt = 0;
	uint64_t lastalcnt = 0;
	uint64_t numadpt = 0;
	unsigned int const bshift = 20;
	std::vector<uint64_t> RLhist;
	std::vector<uint64_t> Ahist;
	std::map<std::string,uint64_t> M;

	while ( bamdec.readAlignment() )
	{
		if ( verbose && ( (alcnt >> bshift) != (lastalcnt >> bshift) ) )
		{
			std::cerr << "[V]\t" << alcnt << "\t" << numadpt << std::endl;
			lastalcnt = alcnt;
		}

		uint64_t const lseq = algn.getLseq();

		while ( ! (lseq < RLhist.size() ) )
			RLhist.push_back(0);

		RLhist[lseq]++;

		if ( algn.hasAux("qs") )
		{
			numadpt++;
		}

		if ( algn.hasAux("aa") )
		{
			numadpt++;
			std::string const qs = algn.getAuxAsString("aa");

			auto it = M.find(qs);

			if ( it == M.end() )
			{
				uint64_t const id = M.size();
				M[qs] = id;
				it = M.find(qs);
			}

			assert ( it != M.end() );

			while ( !(it->second < Ahist.size()) )
				Ahist.push_back(0);
			Ahist[it->second] += 1;
		}

		alcnt++;
	}

	std::cout << "[V] processed " << alcnt << "\t" << numadpt << std::endl;

	for ( uint64_t i = 0; i < RLhist.size(); ++i )
		if ( RLhist[i] )
			std::cout << "RLhist[" << i << "]=" << RLhist[i] << std::endl;

	for ( auto P : M )
	{
		std::cout << "Ahist[" << P.first << "]=" << Ahist[P.second] << std::endl;
	}

	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" ) );

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

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

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