/**
    biobambam
    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/>.
**/
#if ! defined(BIOBAMBAM2_DEPTHINTERVAL_HPP)
#define BIOBAMBAM2_DEPTHINTERVAL_HPP

#include <libmaus2/util/NumberSerialisation.hpp>
#include <libmaus2/math/IntegerInterval.hpp>
#include <libmaus2/bambam/BamHeader.hpp>
#include <libmaus2/aio/BufferedOutput.hpp>

namespace biobambam2
{
	struct DepthInterval
	{
		uint64_t refid;
		uint64_t from;
		uint64_t to;
		uint64_t depth;

		DepthInterval() : refid(0), from(0), to(0), depth(0) {}
		DepthInterval(
			uint64_t const rrefid,
			uint64_t const rfrom,
			uint64_t const rto,
			uint64_t const rdepth
		) : refid(rrefid), from(rfrom), to(rto), depth(rdepth) {}

		libmaus2::math::IntegerInterval<int64_t> getInterval() const
		{
			return libmaus2::math::IntegerInterval<int64_t>(from,static_cast<int64_t>(to)-1);
		}

		std::ostream & serialise(std::ostream & out) const
		{
			out.write(
				reinterpret_cast<char const *>(this),
				sizeof(DepthInterval)
			);
			return out;
		}

		std::string print(libmaus2::bambam::BamHeader const &) const;

		std::istream & deserialise(std::istream & in)
		{
			in.read(
				reinterpret_cast<char *>(this),
				sizeof(DepthInterval)
			);
			return in;
		}

		bool operator<(DepthInterval const & O) const
		{
			if ( refid != O.refid )
				return refid < O.refid;
			else if ( from != O.from )
				return from < O.from;
			else
				return to > O.to;
		}
	};

	struct DepthIntervalOrder : public libmaus2::aio::MemorySerialisedOrder
	{
		bool operator()(
			DepthInterval const & A,
			DepthInterval const & B
		) const
		{
			return A < B;
		}

		bool operator()(
			char const * aa, char const * /* ae */,
			char const * ba, char const * /* be */
		) const
		{
			DepthInterval const & A = *reinterpret_cast<DepthInterval const *>(aa);
			DepthInterval const & B = *reinterpret_cast<DepthInterval const *>(ba);
			return (*this)(A,B);
		}
	};

	struct DepthIntervalDepthOrder : public libmaus2::aio::MemorySerialisedOrder
	{
		bool operator()(
			DepthInterval const & A,
			DepthInterval const & B
		) const
		{
			if ( A.depth != B.depth )
				return A.depth < B.depth;
			else
				return A < B;
		}

		bool operator()(
			char const * aa, char const * /* ae */,
			char const * ba, char const * /* be */
		) const
		{
			DepthInterval const & A = *reinterpret_cast<DepthInterval const *>(aa);
			DepthInterval const & B = *reinterpret_cast<DepthInterval const *>(ba);
			return (*this)(A,B);
		}
	};
}

std::ostream & operator<<(std::ostream & out, biobambam2::DepthInterval const & D);
#endif
