import java.net.*;
import java.awt.*;
import java.applet.*;
import java.lang.reflect.*;


/**
 * A utility class that contains methods for creating different 
 * kinds of objects from Strings.  All methods are static so it 
 * is not necessary to ever create an instance of this class.
 *
 * <p>
 * Note, these methods are typically convenience wrappers around
 * one or two-line methods that already exist in Java.  To avoid
 * dealing with exceptions early on, all these functions ignore 
 * errors and attempt to return invalid values.  This is not 
 * always reasonable, so use the standard Java functions directly
 * if you want to handle the exceptions smartly.
 *
 * @author Robert C. Duvall
 */
public final class FromString
{
    /**
     * Given a String representing the fully qualified name of a 
     * class, returns an initialized instance of the corresponding 
     * class using default constructor.  Returns null if string 
     * does not name a valid class.
     */
    public static Object toNewInstance (String className)
    {
        try
        {
            return Class.forName(className).newInstance();
        }
        catch (Exception e)
        {
            System.err.println("*** badly named class: " + className);
            return null;
        }
    }


    /**
     * Given String representing fully qualified name of a class and 
     * array of actual parameters, returns initialized instance of 
     * the corresponding class using matching constructor.  Returns 
     * null if string does not name a valid class or arguments do not 
     * match any possible constructors.
     */
    public static Object toNewInstance (String className, Object[] args)
    {
        try
        {
            Class c = Class.forName(className);
            Constructor[] ctors = c.getDeclaredConstructors();
            for (int k = 0; k < ctors.length; k++)
            {
                Class[] params = ctors[k].getParameterTypes();
                if (params.length == args.length && isMatch(params, args))
                {
                    return ctors[k].newInstance(args);
                }
            }
            return null;
        }
        catch (Exception e)
        {
            System.err.println("*** badly named class: " + className);
            return null;
        }
    }

    // are parameters compatible types and in same order?
    private static boolean isMatch (Class[] formals, Object[] actuals)
    {
        for (int k = 0; k < formals.length; k++)
        {
            if (! isMatch(formals[k], actuals[k].getClass()))
            {
                return false;
            }
        }
        return true;
    }

    // is actual derived from formal class?
    private static boolean isMatch (Class formal, Class actual)
    {
        while (actual != null)
        {
            if (formal.getName().equals(actual.getName()))
            {
                return true;
            }
            actual = actual.getSuperclass();
        }
        return false;
    }


    /**
     * Given a String representing an integer value, returns that 
     * value.  Returns 0 if string is not formatted properly.
     */
    public static int toInt (String number)
    {
        try
        {
            return Integer.parseInt(number);
        }
        catch (Exception e)
        {
            System.err.println("*** badly formatted number: " + number);
            return 0;
        }
    }


    /**
     * Given a String representing an double value, returns that 
     * value.  Returns 0 if string is not formatted properly.
     */
    public static double toDouble (String number)
    {
        try
        {
            return Double.parseDouble(number);
        }
        catch (NumberFormatException e)
        {
            System.err.println("*** badly formatted number: " + number);
            return 0;
        }
    }


    /**
     * Given a String representing the name of an image in the context
     * of an application, returns that image.  Returns null if image 
     * cannot be found.
     */
    public static Image toImage (String imageName, Component c)
    {
        Image result = null;
        try
        {
            // try name as url, this will work for file:/xyz and http://xzy
            result = c.getToolkit().getImage(new URL(imageName));
        }
        catch (Exception e)
        {
            try
            {
                // try it as a file name instead of a URL
                result = c.getToolkit().getImage(imageName);
                if (result == null)
                {
                    System.err.println("*** badly named image: " + imageName);
                }
            }
            catch (Exception ee)
            {
                // should never get here
            }
        }
        finally
        {
            return result;
        }
    }


    /**
     * Given a String representing the name of an image in the context 
     * of an applet, returns that image.  Return null if image cannot 
     * be found.
     */
    public static Image toImage (String imageName, Applet a)
    {
        Image result = null;
        try
        {
            // try name as url, this will work for file:/xyz and http://xzy
            result = a.getImage(new URL(imageName));
        }
        catch (Exception e)
        {
            try
            {
                // try url relative to html document base, i.e., user defaults
                result = a.getImage(new URL(a.getDocumentBase(), imageName));
                if (result == null)
                {
                    // try url relative to html document base, i.e., program defaults
                    result = a.getImage(new URL(a.getCodeBase(), imageName));
                    if (result == null)
                    {
                        // try anything
                        result = a.getImage(new URL("file:" + imageName));
                        if (result == null)
                        {
                            // give up
                            System.err.println("*** badly named image: " + imageName);
                            result = a.createImage(25, 25);
                        }
                    }
                }
            }
            catch (Exception ee)
            {
                // should never get here
            }
        }
        finally
        {
            return result;
        }
    }
}
