// 
// AndQuery.cc
//
// AndQuery: an operator query that does 'and' combination
//           
// Part of the ht://Dig package   <http://www.htdig.org/>
// Copyright (c) 1995-2004 The ht://Dig Group
// For copyright details, see the file COPYING in your distribution
// or the GNU Library General Public License (LGPL) version 2 or later
// <http://www.gnu.org/copyleft/lgpl.html> 
// 
// $Id: AndQuery.cc,v 1.4 2004/05/28 13:15:24 lha Exp $
// 


#include "AndQuery.h"
//
//	l	r	and
//	----------------------
//	0	0	0
//	0	b	0
//	0	x	0
//	a	0	0
//	a	b	intersect(a,b)
//	a	x	a
//	x	0	0
//	x	b	b
//	x	x	x
//
//	i.e. some 0 => 0
//	ignores can be left out of intersection
// the shorter of the result lists is put apart for intersection
// this optimises the intersection process
//

ResultList *
AndQuery::Evaluate()
{
	ResultList *result = 0;
	ResultList *shorter = 0;

	operands.Start_Get();
	Query *operand = (Query *) operands.Get_Next();
	while(operand && !shorter)
	{
		result = operand->GetResults();
		if(!result)
		{
			break;
		}
		if(!result->IsIgnore())
		{
			shorter = result;
		}
		operand = (Query *) operands.Get_Next();
	}
	if(shorter)
	{
		List longer;
		while(operand && result)
		{
			result = operand->GetResults();
			if(result && !result->IsIgnore())
			{
				if(result->Count() < shorter->Count())
				{
					longer.Add(shorter);
					shorter = result;
				}
				else
				{
					longer.Add(result);
				}
			}
			operand = (Query *) operands.Get_Next();
		}
		if(longer.Count())
		{
			result = Intersection(*shorter, longer);
			longer.Release();
		}
		else
		{
			result = new ResultList(*shorter);
		}
	}
	return result;
}

//
// return a result list containing only the matches common to
// all input parameters.
//
// l is iterated, matches from l are searched in all elements of rs
//
//
//	foreach match in shorter
//		confirm the match in each lists
//		if confirmed
//			copy all matches in result
//
// the shorter of the input lists is assumed to be in the first parameter
// this is a modest optimisation in order to minimise iteration
//

ResultList *
AndQuery::Intersection(const ResultList &shorter, const List &lists)
{
	ResultList *result = 0;
	DictionaryCursor c;
	shorter.Start_Get(c);
	DocMatch *match = (DocMatch *)shorter.Get_NextElement(c);
	while(match)
	{
		List confirms;
	
		ListCursor lc;	
		lists.Start_Get(lc);
		ResultList *list = (ResultList *)lists.Get_Next(lc);
		while(list)
		{
			DocMatch *confirm = list->find(match->GetId());
			if(confirm)
			{
				confirms.Add(confirm);
			}
			list = (ResultList *)lists.Get_Next(lc);
		}
		if(confirms.Count() == lists.Count())
		{
			if(!result)
			{
				result = new ResultList;
			}
			DocMatch *copy = new DocMatch(*match);
			confirms.Start_Get();
			DocMatch *confirm = (DocMatch *)confirms.Get_Next();
			while(confirm)
			{
				copy->Merge(*confirm);
				confirm = (DocMatch *)confirms.Get_Next();
			}
			result->add(copy);
		}
		confirms.Release();
		match = (DocMatch *)shorter.Get_NextElement(c);
	}
	return result;
}

