/* ======================================================================
   Parts Copyright 2006 University of Leeds, Oxford University, University of the Highlands and Islands.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

====================================================================== */

package org.bodington.xml;

import org.bodington.server.BuildingContext;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

public class XMLUtils
	{
	public static char[] illegalPCDataChars = 
		{ '<', '>', '&',  };
		
	public static String[] pcDataEscapes = 
		{ "&lt;", "&gt;", "&amp;",  };
		
	public static char[] illegalAttributeChars = 
		{ '<', '>', '&', '\'', '"' };

	public static String[] attributeEscapes = 
		{ "&lt;", "&gt;", "&amp;", "&apos;", "&quot;" };
		

	private static boolean needsEscaping( String str, char[] illegalChars )
		{
		for ( int j=0; j< illegalChars.length; j++ )
			if ( str.indexOf( illegalChars[j] ) >=0 )
				return true;
				
		return false;
		}

	private static String escapeString( String str, char[] illegalChars, String[] escapes )
		{
		if ( !needsEscaping( str, illegalChars ) )
			return str;
		
		StringBuffer output = new StringBuffer( ((str.length() * 10) / 16)+1 );
		int i, j;
		
		for ( i = 0; i<str.length(); i++ )
			{
			for ( j=0; j< illegalChars.length; j++ )
				{
				if ( illegalChars[j] == str.charAt( i ) )
					break;
				}
				
			if ( j<illegalChars.length )
				output.append( escapes[j] );
			else
				output.append( str.charAt( i ) );
			}
			
		return output.toString();
		}
		

	public static String toPCData( String str )
		{
		return escapeString( str, illegalPCDataChars, pcDataEscapes );
		}
		
	public static String toAttribute( String str )
		{
		return escapeString( str, illegalAttributeChars, attributeEscapes );
		}
    
    /**
     * Ordered list of {@link org.xml.sax.XMLReader} implementations. This list
     * is used by the method {@link #getXMLReader()}. The order is as follows:
     * <ol>
     * <li><code>org.apache.xerces.parsers.SAXParser</code></li>
     * <li><code>com.sun.org.apache.xerces.internal.parsers.SAXParser</code></li>
     * <li><code>org.apache.crimson.parser.XMLReaderImpl</code></li>
     * </ol>
     * @see #getXMLReader()
     */
    static final String[] XML_READERS = {"org.apache.xerces.parsers.SAXParser",
        "com.sun.org.apache.xerces.internal.parsers.SAXParser",
        "org.apache.crimson.parser.XMLReaderImpl"};

    /**
     * Get an {@link org.xml.sax.XMLReader} implementation.
     * This method will try to find a suitable implementation that is available
     * to the runtime.
     * @return an {@link org.xml.sax.XMLReader} or null if we can't get one.
     * implementation.
     */
    public static final XMLReader getXMLReader()
    	{   
        String xmlReaderName = null;
        // NOTE: the following "de-couples" us from the requirement of having
        // BuildingContext available (bodington properties + log4j dependencies)
        // This is the situation when we are running in an applet.
        try
            {
            Class.forName( "org.bodington.server.BuildingContext" );
            xmlReaderName = BuildingContext.getProperty( "xmlrepository.driver");
            }
        catch (ClassNotFoundException e)
            { 
            }
        XMLReader xmlReader = null;
        
        // Allow for our overrides.
        if (xmlReaderName != null) 
            {
            try
                {
                xmlReader = XMLReaderFactory.createXMLReader( xmlReaderName );
                }
            catch (SAXException se)
                {
                }
            }
        // Doesn't work out the box on 1.4.2, should work on 1.5
        if (xmlReader == null) 
            {
            try
                {
                xmlReader = XMLReaderFactory.createXMLReader();
                }
            catch (SAXException e)
                {
                }
            }
        // Should work on 1.4.2 and screwy other platforms.
        for (int i = 0; xmlReader == null && i < XML_READERS.length; i++)
        {   
            try
            {
                xmlReader = XMLReaderFactory.createXMLReader(XML_READERS[i]);
            }
            catch ( SAXException se)
            {
            }
        }
    	        
        return xmlReader;
    	}
	}
