/////////////////////////////////////////////////////////////////////////////
//    License (GPLv2+):
//    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 2 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, write to the Free Software
//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
/////////////////////////////////////////////////////////////////////////////
/** 
 * @file  DiffList.cpp
 *
 * @brief Implementation file for DiffList class
 */
// RCS ID line follows -- this is updated by CVS
// $Id: DiffList.cpp 3619 2006-09-22 15:28:28Z kimmov $

#include "stdafx.h"
#include "DiffList.h"
#include "DiffWrapper.h"
#include "coretools.h"

/**
 * @brief Default constructor, initialises difflist to 64 items.
 */
DiffList::DiffList()
: m_firstSignificant(-1)
, m_lastSignificant(-1)
, m_firstSignificantLeftMiddle(-1)
, m_firstSignificantLeftRight(-1)
, m_firstSignificantMiddleRight(-1)
, m_firstSignificantLeftOnly(-1)
, m_firstSignificantMiddleOnly(-1)
, m_firstSignificantRightOnly(-1)
, m_lastSignificantLeftMiddle(-1)
, m_lastSignificantLeftRight(-1)
, m_lastSignificantMiddleRight(-1)
, m_lastSignificantLeftOnly(-1)
, m_lastSignificantMiddleOnly(-1)
, m_lastSignificantRightOnly(-1)
{
	m_diffs.SetSize(64);
}

/**
 * @brief Removes all diffs from list.
 */
void DiffList::Clear()
{
	m_diffs.RemoveAll();
	m_firstSignificant = -1;
	m_lastSignificant = -1;
	m_firstSignificantLeftMiddle = -1;
	m_firstSignificantLeftRight = -1;
	m_firstSignificantMiddleRight = -1;
	m_firstSignificantLeftOnly = -1;
	m_firstSignificantMiddleOnly = -1;
	m_firstSignificantRightOnly = -1;
	m_lastSignificantLeftMiddle = -1;
	m_lastSignificantLeftRight = -1;
	m_lastSignificantMiddleRight = -1;
	m_lastSignificantLeftOnly = -1;
	m_lastSignificantMiddleOnly = -1;
	m_lastSignificantRightOnly = -1;
}

/**
 * @brief Returns count of items in diff list.
 * This function returns total amount of items (diffs) in list. So returned
 * count includes significant and non-significant diffs.
 * @note Use GetSignificantDiffs() to get count of non-ignored diffs.
 */
int DiffList::GetSize() const
{
	return (int) m_diffs.GetSize();
}

/**
 * @brief Returns count of significant diffs in the list.
 * This function returns total count of significant diffs in list. So returned
 * count doesn't include non-significant diffs.
 * @return Count of significant differences.
 */
int DiffList::GetSignificantDiffs() const
{
	int nSignificants = 0;
	const int nDiffCount = (int) m_diffs.GetSize();

	for (int i = 0; i < nDiffCount; i++)
	{
		const DIFFRANGE * dfi = DiffRangeAt(i);
		if (dfi->op != OP_TRIVIAL)
		{
			++nSignificants;
		}
	}
	return nSignificants;
}

/**
 * @brief Adds given diff to end of the list.
 * Adds given difference to end of the list (append).
 * @param [in] di Difference to add.
 */
void DiffList::AddDiff(const DIFFRANGE & di)
{
	DiffRangeInfo dri(di);
	m_diffs.Add(dri);
}

/**
 * @brief Checks if diff in given list index is significant or not.
 * @param [in] nDiff Index of DIFFRANGE to check.
 * @return TRUE if diff is significant, FALSE if not.
 */
BOOL DiffList::IsDiffSignificant(int nDiff) const
{
	const DIFFRANGE * dfi = DiffRangeAt(nDiff);
	if (dfi->op != OP_TRIVIAL)
		return TRUE;
	else
		return FALSE;
}

/**
 * @brief Returns copy of DIFFRANGE from diff-list.
 * @param [in] nDiff Index of DIFFRANGE to return.
 * @param [out] di DIFFRANGE returned (empty if error)
 * @return TRUE if DIFFRANGE found from given index.
 */
BOOL DiffList::GetDiff(int nDiff, DIFFRANGE & di) const
{
	const DIFFRANGE * dfi = DiffRangeAt(nDiff);
	if (!dfi)
	{
		DIFFRANGE empty;
		di = empty;
		return FALSE;
	}
	di = *dfi;
	return TRUE;
}

/**
 * @brief Return constant pointer to requested diff.
 * This function returns constant pointer to DIFFRANGE at given index.
 * @param [in] nDiff Index of DIFFRANGE to return.
 * @return Constant pointer to DIFFRANGE.
 */
const DIFFRANGE * DiffList::DiffRangeAt(int nDiff) const
{
	if (nDiff>=0 && nDiff < m_diffs.GetSize())
	{
		DiffList * pThis = const_cast<DiffList *>(this);
		return &pThis->m_diffs.ElementAt(nDiff).diffrange;
	}
	else
	{
		ASSERT(0);
		return NULL;
	}
}

/**
 * @brief Replaces diff in list in given index with given diff.
 * @param [in] nDiff Index (0-based) of diff to be replaced
 * @param [in] di Diff to put in list.
 * @return TRUE if index was valid and diff put to list.
 */
BOOL DiffList::SetDiff(int nDiff, const DIFFRANGE & di)
{
	if (nDiff < m_diffs.GetSize())
	{
		m_diffs[nDiff] = di;
		return TRUE;
	}
	else
		return FALSE;
}

/**
 * @brief Checks if line is before, inside or after diff
 * @param [in] nLine Linenumber to text buffer (not "real" number)
 * @param [in] nDiff Index to diff table
 * @return -1 if line is before diff, 0 if line is in diff and
 * 1 if line is after diff.
 */
int DiffList::LineRelDiff(UINT nLine, UINT nDiff) const
{
	const DIFFRANGE * dfi = DiffRangeAt(nDiff);
	if (nLine < dfi->dbegin[0])
		return -1;
	else if (nLine > dfi->dend[0])
		return 1;
	else
		return 0;
}

/**
 * @brief Checks if line is inside given diff
 * @param [in] nLine Linenumber to text buffer (not "real" number)
 * @param [in] nDiff Index to diff table
 * @return TRUE if line is inside given difference.
 */
BOOL DiffList::LineInDiff(UINT nLine, UINT nDiff) const
{
	const DIFFRANGE * dfi = DiffRangeAt(nDiff);
	if (nLine >= dfi->dbegin[0] && nLine <= dfi->dend[0])
		return TRUE;
	else
		return FALSE;
}

/**
 * @brief Returns diff index for given line.
 * @param [in] nLine Linenumber, 0-based.
 * @return Index to diff table, -1 if line is not inside any diff.
 */
int DiffList::LineToDiff(UINT nLine) const
{
	const int nDiffCount = (int) m_diffs.GetSize();
	if (nDiffCount == 0)
		return -1;

	// First check line is not before first or after last diff
	if (nLine < DiffRangeAt(0)->dbegin[0])
		return -1;
	if (nLine > DiffRangeAt(nDiffCount-1)->dend[0])
		return -1;

	// Use binary search to search for a diff.
	int left = 0; // Left limit
	int middle = 0; // Compared item
	int right = nDiffCount - 1; // Right limit

	while (left <= right)
	{
		middle = (left + right) / 2;
		int result = LineRelDiff(nLine, middle);
		switch (result)
		{
		case -1: // Line is before diff in file
			right = middle - 1;
			break;
		case 0: // Line is in diff
			return middle;
			break;
		case 1: // Line is after diff in file
			left = middle + 1;
			break;
		default:
			_RPTF1(_CRT_ERROR, "Invalid return value %d from LineRelDiff(): "
				"-1, 0 or 1 expected!", result); 
			break;
		}
	}
	return -1;
}

/**
 * @brief Return previous diff from given line.
 * @param [in] nLine First line searched.
 * @param [out] nDiff Index of diff found.
 * @return TRUE if line is inside diff, FALSE otherwise.
 */
BOOL DiffList::GetPrevDiff(int nLine, int & nDiff) const
{
	BOOL bInDiff = TRUE;
	int numDiff = LineToDiff(nLine);

	// Line not inside diff
	if (nDiff == -1)
	{
		bInDiff = FALSE;
		for (int i = (int) m_diffs.GetSize() - 1; i >= 0 ; i--)
		{
			if ((int)DiffRangeAt(i)->dend[0] <= nLine)
			{
				numDiff = i;
				break;
			}
		}
	}
	nDiff = numDiff;
	return bInDiff;
}

/**
 * @brief Return next difference from given line.
 * This function finds next difference from given line. If line is inside
 * difference, that difference is returned. If next difference is not found
 * param @p nDiff is set to -1.
 * @param [in] nLine First line searched.
 * @param [out] nDiff Index of diff found.
 * @return TRUE if line is inside diff, FALSE otherwise.
 */
BOOL DiffList::GetNextDiff(int nLine, int & nDiff) const
{
	BOOL bInDiff = TRUE;
	int numDiff = LineToDiff(nLine);

	// Line not inside diff
	if (numDiff == -1)
	{
		bInDiff = FALSE;
		const int nDiffCount = (int) m_diffs.GetSize();
		for (int i = 0; i < nDiffCount; i++)
		{
			if ((int)DiffRangeAt(i)->dbegin[0] >= nLine)
			{
				numDiff = i;
				break;
			}
		}
	}
	nDiff = numDiff;
	return bInDiff;
}

/**
 * @brief Check if diff-list contains significant diffs.
 * @return TRUE if list has significant diffs, FALSE otherwise.
 */
BOOL DiffList::HasSignificantDiffs() const
{
	if (m_firstSignificant == -1)
		return FALSE;
	return TRUE;
}

/**
 * @brief Return previous diff index from given line.
 * @param [in] nLine First line searched.
 * @return Index for next difference or -1 if no difference is found.
 */
int DiffList::PrevSignificantDiffFromLine(UINT nLine) const
{
	int nDiff = -1;

	for (int i = (int) m_diffs.GetSize() - 1; i >= 0 ; i--)
	{
		const DIFFRANGE * dfi = DiffRangeAt(i);
		if (dfi->op != OP_TRIVIAL && dfi->dend[0] <= nLine)
		{
			nDiff = i;
			break;
		}
	}
	return nDiff;
}

/**
 * @brief Return next diff index from given line.
 * @param [in] nLine First line searched.
 * @return Index for previous difference or -1 if no difference is found.
 */
int DiffList::NextSignificantDiffFromLine(UINT nLine) const
{
	int nDiff = -1;
	const int nDiffCount = (int) m_diffs.GetSize();

	for (int i = 0; i < nDiffCount; i++)
	{
		const DIFFRANGE * dfi = DiffRangeAt(i);
		if (dfi->op != OP_TRIVIAL && dfi->dbegin[0] >= nLine)
		{
			nDiff = i;
			break;
		}
	}
	return nDiff;
}

/**
 * @brief Construct the doubly-linked chain of significant differences
 */
void DiffList::ConstructSignificantChain()
{
	m_firstSignificant = -1;
	m_lastSignificant = -1;
	m_firstSignificantLeftMiddle = -1;
	m_firstSignificantLeftRight = -1;
	m_firstSignificantMiddleRight = -1;
	m_lastSignificantLeftMiddle = -1;
	m_lastSignificantLeftRight = -1;
	m_lastSignificantMiddleRight = -1;
	int prev = -1;
	// must be called after diff list is entirely populated
	for (int i = 0; i < m_diffs.GetSize(); ++i)
	{
		if (m_diffs[i].diffrange.op == OP_TRIVIAL)
		{
			m_diffs[i].prev = -1;
			m_diffs[i].next = -1;
		}
		else
		{
			m_diffs[i].prev = prev;
			if (prev != -1)
				m_diffs[prev].next = i;
			prev = i;
			if (m_firstSignificant == -1)
				m_firstSignificant = i;
			m_lastSignificant = i;
			if (m_diffs[i].diffrange.op != OP_TRIVIAL && m_diffs[i].diffrange.op != OP_3RDONLY)
			{
				if (m_firstSignificantLeftMiddle == -1)
					m_firstSignificantLeftMiddle = i;
				m_lastSignificantLeftMiddle = i;
			}
			if (m_diffs[i].diffrange.op != OP_TRIVIAL && m_diffs[i].diffrange.op != OP_2NDONLY)
			{
				if (m_firstSignificantLeftRight == -1)
					m_firstSignificantLeftRight = i;
				m_lastSignificantLeftRight = i;
			}
			if (m_diffs[i].diffrange.op != OP_TRIVIAL && m_diffs[i].diffrange.op != OP_1STONLY)
			{
				if (m_firstSignificantMiddleRight == -1)
					m_firstSignificantMiddleRight = i;
				m_lastSignificantMiddleRight = i;
			}
			if (m_diffs[i].diffrange.op == OP_1STONLY)
			{
				if (m_firstSignificantLeftOnly == -1)
					m_firstSignificantLeftOnly = i;
				m_lastSignificantLeftOnly = i;
			}
			if (m_diffs[i].diffrange.op == OP_2NDONLY)
			{
				if (m_firstSignificantMiddleOnly == -1)
					m_firstSignificantMiddleOnly = i;
				m_lastSignificantMiddleOnly = i;
			}
			if (m_diffs[i].diffrange.op == OP_3RDONLY)
			{
				if (m_firstSignificantRightOnly == -1)
					m_firstSignificantRightOnly = i;
				m_lastSignificantRightOnly = i;
			}
		}
	}
}

/**
 * @brief Return index to first significant difference.
 * @return Index of first significant difference.
 */
int DiffList::FirstSignificantDiff() const
{
	return m_firstSignificant;
}

/**
 * @brief Return index of next significant diff.
 * @param [in] nDiff Index to start looking for next diff.
 * @return Index of next significant difference.
 */
int DiffList::NextSignificantDiff(int nDiff) const
{
	return m_diffs[nDiff].next;
}

/**
 * @brief Return index of previous significant diff.
 * @param [in] nDiff Index to start looking for previous diff.
 * @return Index of previous significant difference.
 */
int DiffList::PrevSignificantDiff(int nDiff) const
{
	return m_diffs[nDiff].prev;
}

/**
 * @brief Return index to last significant diff.
 * @return Index of last significant difference.
 */
int DiffList::LastSignificantDiff() const
{
	return m_lastSignificant;
}

/**
 * @brief Return pointer to first significant diff.
 * @return Constant pointer to first significant difference.
 */
const DIFFRANGE * DiffList::FirstSignificantDiffRange() const
{
	if (m_firstSignificant == -1) return NULL;
	return DiffRangeAt(m_firstSignificant);
}

/**
 * @brief Return pointer to last significant diff.
 * @return Constant pointer to last significant difference.
 */
const DIFFRANGE * DiffList::LastSignificantDiffRange() const
{
	if (m_lastSignificant == -1) return NULL;
	return DiffRangeAt(m_lastSignificant);
}

/**
 * @brief Return previous diff index from given line.
 * @param [in] nLine First line searched.
 * @return Index for next difference or -1 if no difference is found.
 */
int DiffList::PrevSignificant3wayDiffFromLine(UINT nLine, int nDiffType) const
{
	for (int i = m_diffs.GetSize() - 1; i >= 0 ; i--)
	{
		const DIFFRANGE * dfi = DiffRangeAt(i);
		switch (nDiffType)
		{
		case THREEWAYDIFFTYPE_LEFTMIDDLE:
			if (dfi->op != OP_TRIVIAL && dfi->op != OP_3RDONLY && dfi->dend[0] <= nLine)
				return i;
			break;
		case THREEWAYDIFFTYPE_LEFTRIGHT:
			if (dfi->op != OP_TRIVIAL && dfi->op != OP_2NDONLY && dfi->dend[0] <= nLine)
				return i;
			break;
		case THREEWAYDIFFTYPE_MIDDLERIGHT:
			if (dfi->op != OP_TRIVIAL && dfi->op != OP_1STONLY && dfi->dend[0] <= nLine)
				return i;
			break;
		case THREEWAYDIFFTYPE_LEFTONLY:
			if (dfi->op == OP_1STONLY && dfi->dend[0] <= nLine)
				return i;
			break;
		case THREEWAYDIFFTYPE_MIDDLEONLY:
			if (dfi->op == OP_2NDONLY && dfi->dend[0] <= nLine)
				return i;
			break;
		case THREEWAYDIFFTYPE_RIGHTONLY:
			if (dfi->op == OP_3RDONLY && dfi->dend[0] <= nLine)
				return i;
			break;
		}
	}
	return -1;
}

/**
 * @brief Return next diff index from given line.
 * @param [in] nLine First line searched.
 * @return Index for previous difference or -1 if no difference is found.
 */
int DiffList::NextSignificant3wayDiffFromLine(UINT nLine, int nDiffType) const
{
	const int nDiffCount = m_diffs.GetSize();

	for (int i = 0; i < nDiffCount; i++)
	{
		const DIFFRANGE * dfi = DiffRangeAt(i);
		switch (nDiffType)
		{
		case THREEWAYDIFFTYPE_LEFTMIDDLE:
			if (dfi->op != OP_TRIVIAL && dfi->op != OP_3RDONLY && dfi->dbegin[0] >= nLine)
				return i;
			break;
		case THREEWAYDIFFTYPE_LEFTRIGHT:
			if (dfi->op != OP_TRIVIAL && dfi->op != OP_2NDONLY && dfi->dbegin[0] >= nLine)
				return i;
			break;
		case THREEWAYDIFFTYPE_MIDDLERIGHT:
			if (dfi->op != OP_TRIVIAL && dfi->op != OP_1STONLY && dfi->dbegin[0] >= nLine)
				return i;
			break;
		case THREEWAYDIFFTYPE_LEFTONLY:
			if (dfi->op == OP_1STONLY && dfi->dbegin[0] >= nLine)
				return i;
			break;
		case THREEWAYDIFFTYPE_MIDDLEONLY:
			if (dfi->op == OP_2NDONLY && dfi->dbegin[0] >= nLine)
				return i;
			break;
		case THREEWAYDIFFTYPE_RIGHTONLY:
			if (dfi->op == OP_3RDONLY && dfi->dbegin[0] >= nLine)
				return i;
			break;
		}
	}
	return -1;
}

/**
 * @brief Return index to first significant difference.
 * @return Index of first significant difference.
 */
int DiffList::FirstSignificant3wayDiff(int nDiffType) const
{
	switch (nDiffType)
	{
	case THREEWAYDIFFTYPE_LEFTMIDDLE:
		return m_firstSignificantLeftMiddle;
	case THREEWAYDIFFTYPE_LEFTRIGHT:
		return m_firstSignificantLeftRight;
	case THREEWAYDIFFTYPE_MIDDLERIGHT:
		return m_firstSignificantMiddleRight;
	case THREEWAYDIFFTYPE_LEFTONLY:
		return m_firstSignificantLeftOnly;
	case THREEWAYDIFFTYPE_MIDDLEONLY:
		return m_firstSignificantLeftOnly;
	case THREEWAYDIFFTYPE_RIGHTONLY:
		return m_firstSignificantRightOnly;
	}
	return -1;
}

/**
 * @brief Return index of next significant diff.
 * @param [in] nDiff Index to start looking for next diff.
 * @return Index of next significant difference.
 */
int DiffList::NextSignificant3wayDiff(int nDiff, int nDiffType) const
{
	while (m_diffs[nDiff].next != -1)
	{
		nDiff = m_diffs[nDiff].next;
		switch (nDiffType)
		{
		case THREEWAYDIFFTYPE_LEFTMIDDLE:
			if (m_diffs[nDiff].diffrange.op != OP_3RDONLY)
				return nDiff;
			break;
		case THREEWAYDIFFTYPE_LEFTRIGHT:
			if (m_diffs[nDiff].diffrange.op != OP_2NDONLY)
				return nDiff;
			break;
		case THREEWAYDIFFTYPE_MIDDLERIGHT:
			if (m_diffs[nDiff].diffrange.op != OP_1STONLY)
				return nDiff;
			break;
		case THREEWAYDIFFTYPE_LEFTONLY:
			if (m_diffs[nDiff].diffrange.op == OP_1STONLY)
				return nDiff;
			break;
		case THREEWAYDIFFTYPE_MIDDLEONLY:
			if (m_diffs[nDiff].diffrange.op == OP_2NDONLY)
				return nDiff;
			break;
		case THREEWAYDIFFTYPE_RIGHTONLY:
			if (m_diffs[nDiff].diffrange.op == OP_3RDONLY)
				return nDiff;
			break;
		}
	}
	return -1;
}

/**
 * @brief Return index of previous significant diff.
 * @param [in] nDiff Index to start looking for previous diff.
 * @return Index of previous significant difference.
 */
int DiffList::PrevSignificant3wayDiff(int nDiff, int nDiffType) const
{
	while (m_diffs[nDiff].prev != -1)
	{
		nDiff = m_diffs[nDiff].prev;
		switch (nDiffType)
		{
		case THREEWAYDIFFTYPE_LEFTMIDDLE:
			if (m_diffs[nDiff].diffrange.op != OP_3RDONLY)
				return nDiff;
			break;
		case THREEWAYDIFFTYPE_LEFTRIGHT:
			if (m_diffs[nDiff].diffrange.op != OP_2NDONLY)
				return nDiff;
			break;
		case THREEWAYDIFFTYPE_MIDDLERIGHT:
			if (m_diffs[nDiff].diffrange.op != OP_1STONLY)
				return nDiff;
			break;
		case THREEWAYDIFFTYPE_LEFTONLY:
			if (m_diffs[nDiff].diffrange.op == OP_1STONLY)
				return nDiff;
			break;
		case THREEWAYDIFFTYPE_MIDDLEONLY:
			if (m_diffs[nDiff].diffrange.op == OP_2NDONLY)
				return nDiff;
			break;
		case THREEWAYDIFFTYPE_RIGHTONLY:
			if (m_diffs[nDiff].diffrange.op == OP_3RDONLY)
				return nDiff;
			break;
		}
	}
	return -1;
}

/**
 * @brief Return index to last significant diff.
 * @return Index of last significant difference.
 */
int DiffList::LastSignificant3wayDiff(int nDiffType) const
{
	switch (nDiffType)
	{
	case THREEWAYDIFFTYPE_LEFTMIDDLE:
		return m_lastSignificantLeftMiddle;
	case THREEWAYDIFFTYPE_LEFTRIGHT:
		return m_lastSignificantLeftRight;
	case THREEWAYDIFFTYPE_MIDDLERIGHT:
		return m_lastSignificantMiddleRight;
	case THREEWAYDIFFTYPE_LEFTONLY:
		return m_lastSignificantLeftOnly;
	case THREEWAYDIFFTYPE_MIDDLEONLY:
		return m_lastSignificantLeftOnly;
	case THREEWAYDIFFTYPE_RIGHTONLY:
		return m_lastSignificantRightOnly;
	}
	return -1;
}

/**
 * @brief Return pointer to first significant diff.
 * @return Constant pointer to first significant difference.
 */
const DIFFRANGE * DiffList::FirstSignificant3wayDiffRange(int nDiffType) const
{
	switch (nDiffType)
	{
	case THREEWAYDIFFTYPE_LEFTMIDDLE:
		if (m_firstSignificantLeftMiddle == -1) return NULL;
		return DiffRangeAt(m_firstSignificantLeftMiddle);
	case THREEWAYDIFFTYPE_LEFTRIGHT:
		if (m_firstSignificantLeftRight == -1) return NULL;
		return DiffRangeAt(m_firstSignificantLeftRight);
	case THREEWAYDIFFTYPE_MIDDLERIGHT:
		if (m_firstSignificantMiddleRight == -1) return NULL;
		return DiffRangeAt(m_firstSignificantMiddleRight);
	case THREEWAYDIFFTYPE_LEFTONLY:
		if (m_firstSignificantLeftOnly == -1) return NULL;
		return DiffRangeAt(m_firstSignificantLeftOnly);
	case THREEWAYDIFFTYPE_MIDDLEONLY:
		if (m_firstSignificantMiddleOnly == -1) return NULL;
		return DiffRangeAt(m_firstSignificantMiddleOnly);
	case THREEWAYDIFFTYPE_RIGHTONLY:
		if (m_firstSignificantRightOnly == -1) return NULL;
		return DiffRangeAt(m_firstSignificantRightOnly);
	}
	return NULL;
}

/**
 * @brief Return pointer to last significant diff.
 * @return Constant pointer to last significant difference.
 */
const DIFFRANGE * DiffList::LastSignificant3wayDiffRange(int nDiffType) const
{
	switch (nDiffType)
	{
	case THREEWAYDIFFTYPE_LEFTMIDDLE:
		if (m_lastSignificantLeftMiddle == -1) return NULL;
		return DiffRangeAt(m_lastSignificantLeftMiddle);
	case THREEWAYDIFFTYPE_LEFTRIGHT:
		if (m_lastSignificantLeftRight == -1) return NULL;
		return DiffRangeAt(m_lastSignificantLeftRight);
	case THREEWAYDIFFTYPE_MIDDLERIGHT:
		if (m_lastSignificantMiddleRight == -1) return NULL;
		return DiffRangeAt(m_lastSignificantMiddleRight);
	case THREEWAYDIFFTYPE_LEFTONLY:
		if (m_lastSignificantLeftOnly == -1) return NULL;
		return DiffRangeAt(m_lastSignificantLeftOnly);
	case THREEWAYDIFFTYPE_MIDDLEONLY:
		if (m_lastSignificantMiddleOnly == -1) return NULL;
		return DiffRangeAt(m_lastSignificantMiddleOnly);
	case THREEWAYDIFFTYPE_RIGHTONLY:
		if (m_lastSignificantRightOnly == -1) return NULL;
		return DiffRangeAt(m_lastSignificantRightOnly);
	}
	return NULL;
}

/**
 * @brief Swap members of diffrange
 */
void DiffList::Swap(int index1, int index2)
{
	for (int i = 0; i < m_diffs.GetSize(); ++i)
	{
		swap<int>(&m_diffs[i].diffrange.begin[index1], &m_diffs[i].diffrange.begin[index2]);
		swap<int>(&m_diffs[i].diffrange.end[index1], &m_diffs[i].diffrange.end[index2]);
		swap<int>(&m_diffs[i].diffrange.dbegin[index1], &m_diffs[i].diffrange.dbegin[index2]);
		swap<int>(&m_diffs[i].diffrange.dend[index1], &m_diffs[i].diffrange.dend[index2]);
		swap<int>(&m_diffs[i].diffrange.blank[index1], &m_diffs[i].diffrange.blank[index2]);
	}
}

/**
 * @brief Count number of lines to add to sides (because of synch).
 * @param [out] nLeftLines Number of lines to add to left side.
 * @param [out] nRightLines Number of lines to add to right side.
 */
void DiffList::GetExtraLinesCounts(int nFiles, int extras[])
{
	extras[0]=0;
	extras[1]=0;
	extras[2]=0;
	int nDiffCount = GetSize();

	for (int nDiff = 0; nDiff < nDiffCount; ++nDiff)
	{
		DIFFRANGE curDiff;
		VERIFY(GetDiff(nDiff, curDiff));

		// this guarantees that all the diffs are synchronized
		ASSERT(curDiff.begin[0]+extras[0] == curDiff.begin[1]+extras[1]);
		int nline[3];
		int nmaxline = 0;
		int file;
		for (file = 0; file < nFiles; file++)
		{
			nline[file] = curDiff.end[file]-curDiff.begin[file]+1;
			nmaxline = max(nmaxline, nline[file]);
		}
		for (file = 0; file < nFiles; file++)
			extras[file] += nmaxline - nline[file];
	}
}
