/*
    libmaus2
    Copyright (C) 2019 German Tischler-Höhle

    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_FASTX_GCCONTENT_HPP)
#define LIBMAUS2_FASTX_GCCONTENT_HPP

#include <libmaus2/fastx/acgtnMap.hpp>

namespace libmaus2
{
	namespace fastx
	{
		struct GCContent
		{
			// start and end of sequence
			char const * a;
			char const * e;
			// window size
			uint64_t const w;

			// left and right end of current window
			char const * l;
			char const * r;

			// counters for A,C,G,T,N
			uint64_t A[5];

			GCContent(char const * ra, char const * re, uint64_t const rw)
			: a(ra), e(re), w(rw), l(a), r(a)
			{
				std::fill(&A[0],&A[5],0);

				// set up first window
				while ( r != e && r-l < w )
				{
					char const c = *(r++);
					A[libmaus2::fastx::mapChar(c)] += 1;
				}
			}

			// return left end of current window
			uint64_t getPos() const
			{
				return (l - a);
			}

			// sum of counters
			uint64_t sum() const
			{
				return A[0]+A[1]+A[2]+A[3]+A[4];
			}

			// advance to next position
			void nextPos()
			{
				// if right end of window is not yet at the end of the complete sequence
				if ( r != e )
				{
					// if left end is not at end
					if ( l != e )
					{
						// get first symbol in window
						char const c = *(l++);
						// remove it from counters
						A[libmaus2::fastx::mapChar(c)] -= 1;
					}
					// if right end is not at end
					if ( r != e )
					{
						// get next symbol
						char const c = *(r++);
						// add it to counters
						A[libmaus2::fastx::mapChar(c)] += 1;
					}
				}
				// advance to next position (without updating counters)
				else if ( l != e )
				{
					++l;
				}
			}

			// get mid position of current window
			uint64_t midPos() const
			{
				return
					getPos() + (r-l)/2;
			}

			// get GC content fraction
			double getFrac() const
			{
				uint64_t const s = sum();
				if ( s )
				{
					double const c = A[libmaus2::fastx::mapChar('C')];
					double const g = A[libmaus2::fastx::mapChar('G')];
					return (c+g)/s;
				}
				else
				{
					return 0.5;
				}
			}
		};
	}
}
#endif
