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

public abstract class QCMFactory extends QSeqFactory
{
    QCMFactory(){}

    public boolean repeating=false;
    public boolean optional=false;
    public QAccess access=null;
    
    public Object instantiate(Class targetClass)
	throws QE
    {
	Object object=null;
	try
	    {
		object=targetClass.newInstance();
	    }
	catch (InstantiationException ie)
	    {
		throw new QE(ie.toString());
	    }
	catch (IllegalAccessException iae)
	    {
		throw new QE(iae.toString());
	    }
	return object;
    }

    abstract class QCM extends QSeq
    {
	ArrayList states=null;

	QCM()
	    throws QE
	{
	}
	
	public abstract State createState();
	
	public State getState()
	{
	    State state;
	    int i=((QContextImpl)context).ndx;
	    if (states==null)
		states=new ArrayList(i+1);
	    while (states.size()<(i+1))
		states.add(null);
	    state=(State)states.get(i);
	    if (state==null)
		{
		    state=createState();
		    state.reset();
		    states.set(i,state);
		}
	    return state;
	}

	public boolean failMatch(boolean opt, String nam)
	    throws QPE
	{
	    if (!opt)
		context.throwPE("no match: "+nam);
	    return false;
	}

	public boolean failWalk(QContext outputContext, boolean opt, Object obj)
	    throws QPE
	{
	    if (!opt)
		if (obj==null)
		    outputContext.throwPE("no match: null");
		else
		    outputContext.throwPE("no match: "+obj.getClass().getName());
	    return false;
	}

	public boolean isRepeating()
	{
	    return repeating;
	}
	
	public boolean isOptional()
	{
	    return optional;
	}
		
	public void startElement(String name)
	    throws QPE
	{
	    if (((QContextImpl)context).ndx==0)
		{
		    State state=getState();
		    state.reset();
		    if (!state.match(name,true,null,null,null,null))
		    {
			System.err.println("this="+this);
			context.throwPE("unrecognized root element: "+name);
		    }
		}
	    else
		{
		    QEI entry=((QContextImpl)context).getParentEntry();
		    entry.processElement(name);
		}
	}
	
	public void endElement(String name, String text, boolean cdata)
	    throws QPE
	{
	    ((QContextImpl)context).getCurrentEntry().processEnd(text);
	}

	public QIterator getIterator(Object object, 
				     QTargetFactory parentFactory)
	    throws QPE
	{
	    if (access==null || !access.readable(parentFactory,context))			//bug!
		return null;
	    QIterator it=access.allocateIterator(object,parentFactory,context);
	    return it;
	}

	public void walk(Object object, 
			 QContext outputContext)
	    throws QPE
	{
	    QIterator ci=new QSimpleIterator(object);
	    if (!walk(null,null,ci,outputContext,false,false) || !ci.isComplete())
		outputContext.throwPE("unrecognized root object");
	}

	public abstract boolean walk(Object object,
				     QTargetFactory parentFactory,
				     QIterator ci,
				     QContext outputContext,
				     boolean opt,
				     boolean isAttribute)
	    throws QPE;

	abstract class State
	{
	    boolean first=true;
	    QIterator iterator=null;

	    public void reset()
	    {
		first=true;
		iterator=null;
	    }

	    public abstract boolean match(String name, 
					  boolean opt, 
					  QAccess access,
					  Object parent,
					  QTargetFactory parentFactory,
					  QIterator cIterator)
		throws QPE;

	    public boolean isComplete()
	    {
		return isOptional()||!first;
	    }
	}
    }
}
