package toy;

import java.applet.*;
import java.io.*;
import java.net.*;

/**
 * ToyParameterManager is a class that reads and stores the parameters passed to
 * Visual X-TOY through either the filesystem (param.ini) or the applet.  The
 * parameter manager also loads the example programs through the filesystem or
 * over the internet.
 *
 * @author Brian Tsang
 * @version 7.0
 */

public class ToyParameterManager implements Runnable
{
    /**
     * The filename of the parameter file.
     */
    public  static final String PARAMETER_FILE    = "param.ini";

    /**
     * The names of the parameters that are used.
     */
    private static final String PARAMETER_NAMES[] =
    {
        "fileList",
        "startWidth",
        "startHeight",
        "workspaceDump",
        "autoComment",
        "syntaxHighlighting",
        "compilerWarnings",
        "uninitializedError",
        "overflowError",
        "outOfBoundsError",
        "closeExecutionDialog"
    };

    /**
     * The values of the parameters corresponding to PARAMETER_NAMES
     * @see #PARAMETER_NAMES
     */
    private String parameterValues[];

    /**
     * The titles of the example programs.
     * @see #getExampleTitles()
     */
    private String exampleTitles[];
    /**
     * The text of the example programs.
     * @see #getExamplePrograms()
     */
    private String examplePrograms[];

    /**
     * The base location for the example files.  In the case of the applet, it's
     * parentApplet.getCodeBase().  In the case of the application, it's the
     * location of the toy.jar file.
     */
    private String codeBase;

    /**
     * The thread which will load the files.
     * @see #run()
     */
    private Thread runner;

    /**
     * Constructs a ToyParameterManager which will attempt to load the
     * parameters from the specified applet.
     */
    public ToyParameterManager(Applet parentApplet)
    {
        parameterValues = new String[PARAMETER_NAMES.length];
        for (int ctr = 0; ctr < PARAMETER_NAMES.length; ctr++)
            parameterValues[ctr] = parentApplet.getParameter(PARAMETER_NAMES[ctr]);

        exampleTitles = new String[0];
        examplePrograms = new String[0];

        codeBase = parentApplet.getCodeBase().toString();

        runner = new Thread(this);
        runner.start();
    }

    /**
     * Constructs a ToyParameterManager which will attempt to load the
     * parameters from [the directory of the toy.jar file]\param.ini.
     */
    public ToyParameterManager()
    {
        parameterValues = new String[PARAMETER_NAMES.length];
        for (int ctr = 0; ctr < PARAMETER_NAMES.length; ctr++)
            parameterValues[ctr] = "";

        exampleTitles = new String[0];
        examplePrograms = new String[0];

        try
        {
            codeBase = getClass().getResource("ToyParameterManager.class").toString();

            if (codeBase.startsWith("jar:"))
            {
                //crop off the "jar:" and extraneous jar info
                codeBase = codeBase.substring(
                    4,
                    codeBase.indexOf(".jar!")
                    );
            }
            else {
                //crop off the filename
                codeBase = codeBase.substring(
                    0,
                    codeBase.indexOf("ToyParameterManager.class") - 1
                    );
            }

            //crop off that last word (it should be toy, but, in the future,
            //someone may decide to rename the jar to xtoy.jar or somthing
            int charCtr = codeBase.length() - 1;

            while (charCtr > 0 &&
                   codeBase.charAt(charCtr) != '\\' &&
                   codeBase.charAt(charCtr) != '/')
                charCtr--;

            codeBase = codeBase.substring(0, charCtr + 1);

            //attempt to open up the toy.ini file
            URL url = new URL(codeBase + PARAMETER_FILE);
            URLConnection connection = url.openConnection();
            BufferedReader bufferedReader;

            connection.connect();
            bufferedReader = new BufferedReader(
                new InputStreamReader(connection.getInputStream())
                );

            //dump the text into a string
            String line;
            String text = "";
            while ((line = bufferedReader.readLine()) != null)
                text += line + "\n";

            //read the normal parameters
            for (int ctr = 1; ctr < PARAMETER_NAMES.length; ctr++)
            {
                int previousIndex = -1;

                while ((previousIndex = text.indexOf(PARAMETER_NAMES[ctr], previousIndex + 1)) >= 0)
                {
                    charCtr = previousIndex + PARAMETER_NAMES[ctr].length();

                    while (charCtr < text.length() &&
                           Character.isWhitespace(text.charAt(charCtr)))
                        charCtr++;

                    if (charCtr < text.length() && text.charAt(charCtr) == '=')
                    {
                        int beginCtr = charCtr + 1;

                        while (charCtr < text.length() && text.charAt(charCtr) != ';')
                            charCtr++;

                        parameterValues[ctr] = text.substring(beginCtr, charCtr).trim();
                    }

                    previousIndex++;
                }
            }


            //read the file list
            {
                int previousIndex = -1;

                while ((previousIndex = text.indexOf(PARAMETER_NAMES[0], previousIndex + 1)) >= 0)
                {
                    charCtr = previousIndex + PARAMETER_NAMES[0].length();

                    while (charCtr < text.length() &&
                           Character.isWhitespace(text.charAt(charCtr)))
                        charCtr++;

                    if (charCtr < text.length() && text.charAt(charCtr) == '=')
                    {
                        parameterValues[0] = "";

                        while (charCtr < text.length() && text.charAt(charCtr) != ';')
                        {
                            while (charCtr < text.length() &&
                                   text.charAt(charCtr) != '"' &&
                                   text.charAt(charCtr) != ';')
                                charCtr++;

                            if (charCtr < text.length() && text.charAt(charCtr) == '"')
                            {
                                charCtr++;
                                int beginCtr = charCtr;
                                while (charCtr < text.length() &&
                                       text.charAt(charCtr) != '"')
                                    charCtr++;

                                parameterValues[0] += text.substring(beginCtr, charCtr) + ";";

                                charCtr++;
                            }
                        }
                    }

                    previousIndex++;
                }
            }
        }
        catch (Exception e)
        {
            System.out.println(PARAMETER_FILE + " not found in " + codeBase + ".");
            codeBase = "";
        }

        runner = new Thread(this);
        runner.start();
    }

    /**
     * Returns true iff all the example programs have either been accounted for.
     * This entails that each text file does not exist or has been loaded and
     * processed.
     * @return true iff all the example programs have either been accounted for.
     */
    public boolean isReady()
    {
        return runner == null;
    }

    /**
     * Returns the value of the requested parameter.
     * @param parameterName the name of the requested parameter; this is
     * case-sensitive.
     * @return the value of the requested parameter
     */
    public String getParameter(String parameterName)
    {
        for (int ctr = 0; ctr < PARAMETER_NAMES.length; ctr++)
            if (PARAMETER_NAMES[ctr].equals(parameterName))
                return parameterValues[ctr];

        return "";
    }

    /**
     * Returns the list of example program titles.
     * @return the list of example program titles.
     */
    public String[] getExampleTitles()
    {
        return exampleTitles;
    }

    /**
     * Returns the list of example program text.
     * @return the list of example program text.
     */
    public String[] getExamplePrograms()
    {
        return examplePrograms;
    }

    /**
     * Implement the Runnable interface to load the example files in a separate
     * thread.
     * @see #exampleTitles
     * @see #examplePrograms
     */
    public void run()
    {
        //get all example programs
        String fileList = getParameter("fileList");

        while (fileList != null && fileList.indexOf(';') >= 0)
        {
            String urlString =
                codeBase +
                fileList.substring(
                    0,
                    fileList.indexOf(';')
                    ).trim();

            fileList = fileList.substring(fileList.indexOf(';') + 1);

            try
            {
                String newExampleProgram = "";
                String line;

                URL url = new URL(urlString);
                URLConnection connection = url.openConnection();
                BufferedReader bufferedReader;

                connection.connect();
                bufferedReader = new BufferedReader(
                    new InputStreamReader(connection.getInputStream())
                    );

                while ((line = bufferedReader.readLine()) != null)
                    newExampleProgram += line + "\n";

                if (newExampleProgram.trim().length() > 0)
                {
                    String oldExampleTitles[] = exampleTitles;
                    String oldExamplePrograms[] = examplePrograms;


                    exampleTitles = new String[exampleTitles.length + 1];
                    examplePrograms = new String[examplePrograms.length + 1];

                    for (int ctr2 = 0; ctr2 < oldExampleTitles.length; ctr2++)
                    {
                        exampleTitles[ctr2] = oldExampleTitles[ctr2];
                        examplePrograms[ctr2] = oldExamplePrograms[ctr2];
                    }

                    //change the name if a new one can be parsed
                    //check for changes to the program name
                    if (newExampleProgram.startsWith("Program "))
                    {
                        int endIndex = newExampleProgram.indexOf('\n');

                        if (endIndex < 0)
                            endIndex = newExampleProgram.length();

                        exampleTitles[exampleTitles.length - 1] = newExampleProgram.substring(
                            "Program ".length(),
                            endIndex
                            ).trim();
                    }
                    else
                        exampleTitles[exampleTitles.length - 1] = "Untitled";

                    examplePrograms[examplePrograms.length - 1] = newExampleProgram;
                }
                else
                    System.out.println("File is empty: " + urlString);
            }
            catch (Exception e)
            {
                System.out.println("Bad URL: " + urlString);
                e.printStackTrace();
            }
        }

        runner = null;
    }
}
