//Updated 3/22/00, version 1.1.1
//Updated 4/10/00, version 1.1.4

package com.jxml.quick.engine;
import com.jxml.quick.*;
import com.jxml.quick.access.*;
import com.jxml.quick.tf.*;
import java.util.*;

public final class QCMSelFactory extends QCMSeqFactory
{
    protected QFilter newFilter()
	throws QE
    {
	return new QCMSel();
    }

    final class QCMSel extends QCMSeq
    {
	QCMSel()
	    throws QE
	{
	}
	
	public State createState()
	{
	    return new SelState();
	}

	public boolean isOptional()
	{
	    if (tested)
		return optional;
	    tested=true;
	    if (optional)
		return true;
	    int i;
	    int sz=filters.size();
	    for (i=0;i<sz;++i)
		{
		    QCM qcm=(QCM)filters.get(i);
		    if (qcm.isOptional())
			{
			    optional=true;
			    return true;
			}
		}
	    return false;
	}

	public boolean walk(Object object,
			    QTargetFactory parentFactory,
			    QIterator ci,
			    QContext outputContext,
			    boolean opt,
			    boolean isAttribute)
	    throws QPE
	{
	    boolean rs;
	    opt|=isOptional();
	    QIterator g=getIterator(object,parentFactory);
	    if (g!=null)
		ci=g;
	    boolean f=true;
	    int s=filters.size();
	    while (true)
		{
		    boolean none=true;			//1.1.1
		    if (ci!=null)
			{
			    Object o=ci.getCurrent();
			    if (o==null)
				{
				    if (!f)
					rs=true;
				    else
					rs=failWalk(outputContext,opt,object);
				    break;
				}
			}
		    int p;
		    for (p=0;p<s;++p)
			{
			    QCM qcm=(QCM)filters.get(p);
			    boolean trial=qcm.walk(object,
						   parentFactory,
						   ci,
						   outputContext,
						   true,
						   isAttribute);
			    if (trial)
				{
				    p=s;
				    none=false;
				}
			}
		    if (none)
			{
			    if (f)
				rs=failWalk(outputContext,opt,object);
			    else
				rs=true;
			    break;
			}
		    if (!repeating)
			{
			    rs=true;
			    break;
			}
		    f=false;									//1.1.4
		}
	    if (g!=null)
	    {                                                                                 //1.1.1
		if (g.getCurrent()!=null)
		{
		    System.err.println("object="+object);
		    context.throwPE("Unexpressed: "+g.getCurrent().getClass().getName());
		}
		access.releaseIterator(g);
	    }
	    return rs;
	}

	final class SelState extends SeqState
	{
	    public boolean isComplete()
	    {
		if (pos==-1)
		    return !first || isOptional();
		return state.isComplete();
	    }

	    public boolean match(String name, 
				 boolean opt,
				 QAccess mAccess,
				 Object parent,
				 QTargetFactory parentFactory,
				 QIterator cIterator)
		throws QPE
	    {
		QAccess cAccess;
		if (access==null)
		    cAccess=mAccess;
		else
		    cAccess=access;
		if (iterator==null && 
		    (cAccess==null || !cAccess.writeable(parentFactory,context)))
		    {
			iterator=getIterator(parent,parentFactory);
			if (iterator==null)
			    iterator=cIterator;
		    }
		opt|=isOptional();
		if (sz==0)
		    return failMatch(opt,name);
		QCM qcm;
		boolean none=false;
		boolean forceReset=false;
		boolean trial;
		int oldPos=pos;
		if (pos==-1)
		    {
			none=true;
			pos=0;
			forceReset=true;
		    }
		do
		    {
			qcm=(QCM)filters.get(pos);
			state=qcm.getState();
			if (forceReset)
			    state.reset();
			trial=state.match(name,
					  true,
					  cAccess,
					  parent,
					  parentFactory,
					  iterator);
			if (trial)
			    {
				first=false;
				return true;
			    }
			else if (pos==oldPos)
			    {
				if (!first && !repeating)
				    return failMatch(true,name);
				oldPos=-1;
				pos=0;
			    }
			else
			    ++pos;
			forceReset=true;
		    } while (pos<sz);
		return failMatch(opt||isComplete(),name);
	    }
	}
    }
}
