/*
    InputString class - implements a string of tokens used to feed into the state
    machine. Maintains position within the string, knows how to draw itself on
    the screen and read/write itself from/into file.
*/


class InputString
{
    /*
        CLASS CONSTANTS
    */

    /* number of different tokens recognized */

    final static int    TOKENS = 26;

    /* dictates how to make an ascii character out of the token. tokens are
       value from 0 to TOKENS - 1. adding LABLE_SHIFT will give you the
       ascii character representation */

    final static int    LABEL_SHIFT = 97;

    /* token standing for End Of String */

    final static int    EOS = -1;

    /* token standing for Bad Token */

    final static int    BAD_TOKEN = -2;


    /*
        INSTANCE VARIABLES
    */

    /* the string of character representations of tokens */

    private String      inputString;

    /* index within the input string of the current token */

    private int         index;

    /* color for drawing normal tokens */

    private Color       normalColor;

    /* color for drawing current token */

    private Color       currColor;

    /* 'Input string:' label drawn before token string */

    private String      title;


    /*
        PUBLIC METHODS
    */


    /*
        constructor method for initialization from user input
    */

    public InputString (String str)
    {
        /* initialize instance variables */

        inputString = str;
        index = 0;

        normalColor = new Color (0, 0, 100);
        currColor = new Color (100, 0, 0);

        title = new String ("Input string: ");

    } /* end InputString */


    /*
        constructor method for initialization from file
    */

    public InputString (FileInputStream file)
    {
        /* read data catching I/O error exception */
        try
        {
            /* initialize instance variables */

            index = 0;

            normalColor = new Color (0, 0, 100);
            currColor = new Color (100, 0, 0);

            title = new String ("Input string: ");

            /* read number of tokens in the following string */

            int cnt = file.read () | (file.read () << 8);

            /* construct the array of bytes of that */

            byte [] bytes = new byte [cnt];

            /* fill array from file */

            file.read (bytes);

            /* create new string based on the data in the array of bytes */

            inputString = new String (bytes, 0);
        }
        catch (IOException e)
        {
        }

    } /* end InputString */


    /*
        returns current token or EOS on end of string or BAD_TOKEN if bad
        token encountered.
    */

    public int currentToken ()
    {
        if (index < 0 || index >= inputString.length ())
            return EOS;

        int curr = ((int) (inputString.charAt (index)) - LABEL_SHIFT);

        if (curr < 0 || curr >= TOKENS)
            return BAD_TOKEN;

        return curr;

    } /* end currentToken */


    /*
        advance current token index by 1.
    */

    public void advanceIndex ()
    {
        index ++;

    } /* end advanceIndex */


    /*
        set the current token index to the beginning of string
    */

    public void rewind ()
    {
        index = 0;

    } /* end rewind */


    /*
        draw itself on the specified graphics context offset pixels from the
        top. current token is drawn in different color.
    */

    public void paint (Graphics g, int offset)
    {
        /* remove previous string image */

        remove (g, offset);

        /* get font height and title string width */

        int height = g.getFontMetrics ().getHeight () + offset;
        int titleWidth = g. getFontMetrics ().stringWidth (title);

        /* set normal color and draw the title */

        g.setColor (normalColor);
        g.drawString (title, 0, height);

        /* if index is bad - draw the whole string in normal color */

        if (index < 0 || index >= inputString.length ())
        {
            g.drawString (inputString, titleWidth, height);
        }

        /* draw the string in three parts, so that the current token is drawn
           in different color */

        else
        {
            g.drawString (inputString.substring (0, index), titleWidth, height);

            g.setColor (currColor);
            g.drawString (inputString.substring (index, index + 1),
                            g. getFontMetrics ().stringWidth (
                            inputString.substring (0, index)) + titleWidth,
                            height);

            g.setColor (normalColor);
            g.drawString (inputString.substring (index + 1,
                            inputString.length ()),
                            g. getFontMetrics ().stringWidth (
                            inputString.substring (0, index + 1)) + titleWidth,
                            height);
        }

    } /* end paint */


    /*
        clear the rectangle of entire screen width and input string height on
        the specified context.
    */

    public void remove (Graphics g, int offset)
    {
        /* get font height and title string width */

        int height = g.getFontMetrics ().getHeight () + offset;
        int titleWidth = g. getFontMetrics ().stringWidth (title);

        /* fill the rectangle with background color */

        g.setColor (Color.lightGray);
        g.fillRect (0, 0, g.getFontMetrics ().stringWidth (inputString) +
                      titleWidth, height);

    } /* end remove */


    /*
        write the input string to file.
    */

    public boolean saveFile (FileOutputStream file)
    {
        /* write data catching the I/O error exception */

        try
        {
            /* write string length */

            file.write (inputString.length () & 0xff);
            file.write (inputString.length () >>> 8);

            /* allocate array of bytes to fit the string */

            byte [] bytes = new byte [inputString.length ()];

            /* extract tokens into the byte array */

            inputString.getBytes (0, inputString.length (), bytes, 0);

            /* write entire byte array to file */

            file.write (bytes);
        }
        catch (IOException e)
        {
            return false;
        }

        return true;

    } /* end saveFile */

} /* end InputString */

