/**
    libmaus2
    Copyright (C) 2009-2021 German Tischler-Höhle
    Copyright (C) 2011-2014 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/>.
**/
#if ! defined(LIBMAUS2_SUFFIXSORT_BWTB3M_GAPARRAYWRAPPER_HPP)
#define LIBMAUS2_SUFFIXSORT_BWTB3M_GAPARRAYWRAPPER_HPP

#include <libmaus2/util/AtomicArray.hpp>
#include <libmaus2/gamma/GammaGapEncoder.hpp>
#include <libmaus2/timing/RealTimeClock.hpp>

namespace libmaus2
{
	namespace suffixsort
	{
		namespace bwtb3m
		{
			struct GapArrayWrapper
			{
				std::shared_ptr<libmaus2::util::AtomicArray<uint32_t> > G;

				GapArrayWrapper()
				{}
				GapArrayWrapper(
					std::shared_ptr<libmaus2::util::AtomicArray<uint32_t> > rG
				) : G(rG)
				{

				}

				std::atomic<uint32_t> * get()
				{
					return G->get();
				}

				std::atomic<uint32_t> const * get() const
				{
					return G->get();
				}

				std::atomic<uint32_t> & operator[](uint64_t const i)
				{
					return (*G)[i];
				}

				std::atomic<uint32_t> const & operator[](uint64_t const i) const
				{
					return (*G)[i];
				}

				struct Sequence
				{
					std::atomic<uint32_t> const * p;

					Sequence(std::atomic<uint32_t> const * rp = nullptr)
					: p(rp) {}

					uint32_t get()
					{
						return *(p++);
					}
				};

				typedef Sequence sequence_type;

				sequence_type getOffsetSequence(uint64_t const offset) const
				{
					return Sequence(get() + offset);
				}

				void saveGapFile(
					uint64_t const Gsize,
					std::string const & gapfile,
					std::ostream * logstr
				) const
				{
					::libmaus2::timing::RealTimeClock rtc;

					if ( logstr )
						(*logstr) << "[V] saving gap file...";
					rtc.start();
					#if defined(LIBMAUS2_SUFFIXSORT_BWTB3M_HUFGAP)
					::libmaus2::util::Histogram gaphist;
					for ( uint64_t i = 0; i < Gsize; ++i )
						gaphist ( G[i].load() );
					::libmaus2::huffman::GapEncoder GE(gapfile,gaphist,G.size());
					GE.encode(G.begin(),G.end());
					GE.flush();
					#else
					::libmaus2::gamma::GammaGapEncoder GE(gapfile);
					GE.encode(get(),get()+Gsize);
					#endif
					if ( logstr )
						(*logstr) << "done in time " << rtc.getElapsedSeconds() << std::endl;
				}

			};
		}
	}
}
#endif
