package com.jxml.quick.tf;
import com.jxml.quick.*;
import com.jxml.quick.access.*;
import java.beans.*;
import java.lang.reflect.*;

public class QClassWrapper implements QTargetFactory
{
    public Class wClass=null;
    public String wClassName="";
    public PropertyDescriptor[] properties=null;
    public Field[] fields=null;
    public boolean isAware=false;
    public boolean isQName=false;
    public boolean isBiModal=false;

    public static Class aware;
    public static Class qname;
    public static Class bimodal;

    static
    {
	try
	    {
		aware=Class.forName("com.jxml.quick.QAware");
		qname=Class.forName("com.jxml.quick.QName");
		bimodal=Class.forName("com.jxml.quick.QBiModal");
	    }
	catch (Exception e)
	    {
		throw new Error(e.toString());
	    }
    }

    public synchronized void makeClass(QContext context)
	throws QPE
    {
	if (wClass!=null)
	    return;
	wClass=context.forName(wClassName);
	isAware=aware.isAssignableFrom(wClass);
	isQName=qname.isAssignableFrom(wClass);
	isBiModal=bimodal.isAssignableFrom(wClass);
    }

    public Object create(QContext context)
	throws QPE
    {
	makeClass(context);
	try
	    {
		return wClass.newInstance();
	    }
	catch (IllegalAccessException e)
	    {
		context.throwPE(e);
	    }
	catch (InstantiationException e)
	    {
		context.throwPE(e);
	    }
	return null;
    }

    public boolean isInstance(Object object,
			      QContext context)
	throws QPE
    {
	makeClass(context);
	return wClass.isInstance(object);
    }

    public String getName(Object object)
    {
	if (isQName)
	    return ((QName)object).getQName();
	else
	    return "";
    }

    public String getText(Object object, 
			  QContext context)
	throws QPE
    {
	if (isBiModal)
	    return ((QBiModal)object).getQText();
	else
	    return "";
    }

    public void add(Object object, 
		    String name, 
		    String text,
		    QAccess access,
		    Object parent,
		    QTargetFactory parentFactory,
		    QContext context)
	throws QPE
    {
	if (!isInstance(object,context))
	    context.throwPE("Class mismatch: "+object.getClass().getName());
	if (isQName)
	    {
		QName q=(QName)object;
		q.setQName(name);
	    }
	if (isBiModal)
	    {
		QBiModal q=(QBiModal)object;
		q.setQText(text);
	    }
	if (parent==null)
	    context.doc.setRoot(object);
	else
	{
	    access.add(parent,parentFactory,object,context);
	}
	if (isAware)
	    {
		((QAware)object).endElement(name,context);
	    }
    }

    public synchronized PropertyDescriptor[] getPropertyDescriptors(QContext context)
	throws QPE
    {
	if (properties!=null)
	    return properties;
	makeClass(context);
	try
	    {
		BeanInfo info=Introspector.getBeanInfo(wClass);
		properties=info.getPropertyDescriptors();
		return properties;
	    }
	catch (IntrospectionException e)
	    {
		context.throwPE(e);
	    }
	return null;
    }

    public synchronized Field[] getFields(QContext context)
	throws QPE
    {
	if (fields!=null)
	    return fields;
	makeClass(context);
//	try
//	    {
		fields=wClass.getFields();
		return fields;
//	    }
//	catch (Exception e)
//	    {
//		context.throwPE(e);
//	    }
//	return null;
    }
}
