/* ======================================================================
   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;

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 the class name of an {@link org.xml.sax.XMLReader} implementation.
     * This method will try to find a suitable implementation that is available
     * to the runtime.
     * @return the class name of an available {@link org.xml.sax.XMLReader}
     * implementation.
     * @see #XML_READERS
     */
    public static final String getXMLReader()
    	{   
        /*
         * NOTE: currently known values (24/11/04):
         * 
         * [A] org.apache.xerces.parsers.SAXParser
         * [B] com.sun.org.apache.xerces.internal.parsers.SAXParser
         * [C] org.apache.crimson.parser.XMLReaderImpl
         * 
         *          Sun     Blackdown       IBM
         * 1.4.2     C          C            A      
         * 1.5.0     B          ?            ?
         * 
         * If [A] is not present in the JDK, it may will be in the application
         * server, e.g. Tomcat. Plus, it is the parser that users will most
         * wish to override with over time, even the one in JDK 1.5.        
         */
        for (int i = 0; i < XML_READERS.length; i++)
            {   
            try
                {
                return Class.forName( XML_READERS[i] ).getName();
                }
            catch ( ClassNotFoundException e )
                {
                continue;
                }
            }
        return null; // if no match found:
    	}
	}
