// copyright => http://www.jxml.com/mdsax/License.txt

package com.jxml.quick;

/**
 * <p>updated by Pavel Curtis to add line breaks in attribute lists--Quick 1.1a1
 * <p>now aware of NLs in text--Quick 1.1a2
 */
public class QExpressFactory extends QFilterFactory
{
    public static final String EV="\n\r&<>\"'";
    public static final String[] E=
    {"\n", "", "&amp;", "&lt;", "&gt;", "&quot;", "&apos;"};

    protected QFilter newFilter()
	throws QE
    {
	return new QExpress();
    }

    public class QExpress extends QFilter
    {
	StringBuffer b=new StringBuffer();
	boolean atts=false;
	boolean startTag=false;
	boolean eal=false;
	int depth=0;

	public QExpress()
	    throws QE
	{
	}

	public void startDocument()
	    throws QPE
	{
	    b.setLength(0);
	    atts=false;
	    startTag=false;
	    eal=false;
	    depth=0;
	}
	
	public void endDocument()
	    throws QPE
	{
	    context.doc.setRoot(b.toString());
	}
	
	public void startElement(String name)
	    throws QPE
	{
	    if (atts)
		{
		}
	    else if (name.equals(QConvert.ATTRIBUTES))
		{
		    atts=true;
		    eal=false;
		}
	    else
		{
		    if (startTag)
			b.append(">");
		    newline();
		    for (int i=0;i<depth;++i)
			b.append("    ");
		    ++depth;
		    b.append("<");
		    b.append(name);
		    attrIndent = currentColumn();
		    startTag=true;
		    eal=true;
		}
	}

	private int curLinePos, attrIndent;

	private int currentColumn() 
	{
	    return b.length() - curLinePos;
	}

	public void newline() 
	{
	    b.append(NL.LS);
	    curLinePos = b.length();
	}

	public void add(String t, boolean cdata)
	{
	    int i;
	    int l=t.length();
	    if (cdata)
	    {
		int j=0;
		while (j<l)
		{
		    while (t.startsWith("]]>",j))
		    {
			b.append("]]>");
			t+=3;
		    }
		    if (j<l)
		    {
			b.append("<![CDATA[");
			i=t.indexOf("]]>",j);
			if (i==-1)
			    i=l;
			b.append(t.substring(j,i));
			b.append("]]>");
			j=i;
		    }
		}
	    }
	    else for (i=0;i<l;++i)
	    {
		String s=t.substring(i,i+1);
		int k=EV.indexOf(s);
		if (k==-1)
		    b.append(s);
		else if (k==0)
		    newline();
		else
		    b.append(E[k]);
	    }
	}
	
	public void endElement(String name, String text, boolean cdata)
	    throws QPE
	{
	    if (name.equals(QConvert.ATTRIBUTES))
		{
		    atts=false;
		}
	    else if (atts)
		{
		    int len = 1 + name.length() + 2 + text.length() + 1;

		    if (currentColumn() + len > 80) {
			newline();
			for (int i = 0; i < attrIndent; i++)
			    b.append(' ');
		    }

		    b.append(" ");
		    b.append(name);
		    b.append("=\"");
		    add(text,cdata);
		    b.append("\"");
		}
	    else if (eal)
		{
		    context.throwPE("missing attribute list");
		}
	    else
		{
		    --depth;
		    if (startTag)
			{
			    startTag=false;
			    if (text == null || text.equals(""))
				{
				    b.append("/>");
				}
			    else
				{
				    b.append(">");
				    add(text,cdata);
				    b.append("</");
				    b.append(name);
				    b.append(">");
				}
			}
		    else 
			{
			    if (text == null || text.equals(""))
				{
				    b.append(NL.LS);
				    for (int i=0;i<depth;++i)
					b.append("    ");
				}
			    else
				add(text,cdata);
			    b.append("</");
			    b.append(name);
			    b.append(">");
			}
		}
	}
    }
}
