/******************************************************************************
 JIndexRange.h

	Copyright © 1998 by John Lindal.  All rights reserved.

 *****************************************************************************/

#ifndef _H_JIndexRange
#define _H_JIndexRange

#include <jTypes.h>
#include <JMinMax.h>
#include <sys/types.h>
#include <regex.h>

class JIndexRange
{
public:

	JIndex	first;
	JIndex	last;

	JIndexRange()
		:
		first(0),
		last(0)
	{ };

	JIndexRange
		(
		const JIndex firstIndex,
		const JIndex lastIndex
		)
		:
		first(firstIndex),
		last(lastIndex)
	{ };

	JBoolean
	Is
		(
		const JIndex firstIndex,
		const JIndex lastIndex
		)
		const
	{
		return JI2B( first == firstIndex && last == lastIndex );
	};

	JBoolean
	IsEmpty() const
	{
		return JI2B( last < first || last == 0 );
	};

	JSize
	GetLength() const
	{
		return ((first <= last && last > 0) ? last-first+1 : 0);
	};

	JBoolean
	Contains
		(
		const JIndex index
		)
		const
	{
		return JI2B( first <= index && index <= last && last > 0 );
	};

	JBoolean
	Contains
		(
		const JIndexRange& range
		)
		const
	{
		const JBoolean e1 = IsEmpty();
		const JBoolean e2 = range.IsEmpty();
		return JI2B((IsNothing() && range.IsNothing()) ||
					( e1 &&  e2 && first == range.first) ||
					(!e1 &&  e2 && first <  range.first && range.first <= last) ||
					(!e1 && !e2 && first <= range.first && range.last <= last));
	};

	void
	Set
		(
		const JIndex firstIndex,
		const JIndex lastIndex
		)
	{
		first = firstIndex;
		last  = lastIndex;
	};

	void
	SetFirstAndLength
		(
		const JIndex	firstIndex,
		const JSize		length
		)
	{
		first = firstIndex;
		last  = firstIndex + length - 1;
	};

	JBoolean
	IsNothing() const
	{
		return JI2B( first == 0 && last == 0 );
	};

	void
	SetToNothing()
	{
		first = last = 0;
	};

	void
	SetToEmptyAt
		(
		const JIndex firstIndex
		)
	{
		first = firstIndex;
		last  = first-1;
	};

	JIndexRange&
	operator+=
		(
		const JIndex offset
		)
	{
		first += offset;
		last  += offset;
		return *this;
	};

	JIndexRange&
	operator-=
		(
		const JIndex offset
		)
	{
		first -= offset;
		last  -= offset;
		return *this;
	};

	JIndexRange& operator+=(const JIndexRange& range);	// covering

	// for JRegex

	JIndexRange
		(
		const regmatch_t& regmatch
		)
		:
		first(regmatch.rm_so+1),
		last(JMax((regoff_t) 0, regmatch.rm_eo))	// Spencer returns {-1,-1} for nothing
	{ };

	operator regmatch_t() const
	{
		regmatch_t regmatch =
			{
			regoff_t(first) - 1,
			(IsNothing() ? -1 : regoff_t(last))
			};
		return regmatch;
	};

//	JBoolean	Complement(const JArray<JIndexRange>& subsetList,
//						   JArray<JIndexRange>* complement);
};

istream& operator>>(istream& input, JIndexRange& range);
ostream& operator<<(ostream& output, const JIndexRange& range);

JBoolean	JIntersection(const JIndexRange& r1, const JIndexRange& r2, JIndexRange* result);
JIndexRange	JCovering(const JIndexRange& r1, const JIndexRange& r2);

inline int
operator==
	(
	const JIndexRange& r1,
	const JIndexRange& r2
	)
{
	return ((r1.IsEmpty() && r2.IsEmpty() && r1.first == r2.first) ||
			(r1.first == r2.first && r1.last == r2.last));
}

inline int
operator!=
	(
	const JIndexRange& r1,
	const JIndexRange& r2
	)
{
	return !(r1 == r2);
}

#endif
