#include "pilercr.h"

void MakeContigMap(const ContigData *Contigs, int ContigCount, int **ptrMap)
	{
	*ptrMap = 0;
	if (ContigCount <= 0)
		return;
	const ContigData &LastContig = Contigs[ContigCount-1];
	const int SeqLength = LastContig.From + LastContig.Length - 1;
	const int BinCount = (SeqLength + CONTIG_MAP_BIN_SIZE - 1)/CONTIG_MAP_BIN_SIZE + 1;
	int *Map = all(int, BinCount);

// Initialize, enables correctness check
	for (int i = 0; i < BinCount; ++i)
		Map[i] = -1;

	for (int ContigIndex = 0; ContigIndex < ContigCount; ++ContigIndex)
		{
		const ContigData &Contig = Contigs[ContigIndex];

	// Contig required to start on bin boundary
		const int From = Contig.From;
		if (From%CONTIG_MAP_BIN_SIZE)
			Quit("MakeContigMap: Contig does not start on bin boundary");

		const int To = From + Contig.Length - 1;
		const int BinFrom = From/CONTIG_MAP_BIN_SIZE;
		const int BinTo = To/CONTIG_MAP_BIN_SIZE;

		for (int Bin = BinFrom; Bin <= BinTo; ++Bin)
			{
			if (-1 != Map[Bin])
				Quit("MakeContigMap logic error 1");
			Map[Bin] = ContigIndex;
			}
		}

	*ptrMap = Map;
	for (int ContigIndex = 0; ContigIndex < ContigCount; ++ContigIndex)
		{
		const ContigData &Contig = Contigs[ContigIndex];
		int ContigIndex2 = GlobalPosToContigIndex(Contig.From);
		if (ContigIndex2 != ContigIndex)
			{
			LogContigs(Contigs, ContigCount);
			Quit("MakeContigMap: start pos %d of contig %d mapped to contig %d",
			  Contig.From, ContigIndex, ContigIndex2);
			}

		int To = Contig.From + Contig.Length - 1;
		int ContigIndex3 = GlobalPosToContigIndex(To);
		if (ContigIndex2 != ContigIndex)
			{
			LogContigs(Contigs, ContigCount);
			Quit("MakeContigMap: end pos %d of contig %d mapped to contig index %d",
			  Contig.From, ContigIndex, ContigIndex3);
			}
		}
	}

const ContigData &GlobalPosToContig(int Pos)
	{
	int ContigIndex = GlobalPosToContigIndex(Pos);
	assert(ContigIndex >= 0 && ContigIndex < ContigCountQ);
	const ContigData &CD = ContigsQ[ContigIndex];
	if (Pos < CD.From || Pos >= CD.From + CD.Length)
		{
		LogContigs(ContigsQ, ContigCountQ);
		Quit("GlobalPosToContig(%d): returned contig %d, out of range",
		  Pos, ContigIndex);
		}
	return CD;
	}

int GlobalPosToContigIndex(int Pos)
	{
	int Bin = Pos/CONTIG_MAP_BIN_SIZE;
	const int BinCount = (SeqLengthQ + CONTIG_MAP_BIN_SIZE - 1)/CONTIG_MAP_BIN_SIZE;

// Hack to avoid crashes
	if (Bin < 0)
		Bin = 0;
	if (Bin >= BinCount)
		Bin = BinCount;

	if (ContigMapQ == 0)
		Quit("ContigMap = 0");

	int ContigIndex = -1;
// Awful hack...
	for (;;)
		{
		ContigIndex = ContigMapQ[Bin];
		if (ContigIndex >= 0)
			break;

		if (Bin == 0)
			Quit("GlobalPosToContigIndex");
		--Bin;
		}

	assert(ContigIndex >= 0 && ContigIndex < ContigCountQ);
	return ContigIndex;
	}

int GlobalToLocal(int Pos, char **ptrLabel)
	{
	int ContigIndex = GlobalPosToContigIndex(Pos);
	assert(ContigIndex >= 0 && ContigIndex < ContigCountQ);
	const ContigData &Contig = ContigsQ[ContigIndex];
	*ptrLabel = Contig.Label;
	return Pos - Contig.From;
	}
