import java.io.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import java.net.URL;
import java.text.*;
import java.util.*;
import java.util.Map;
import java.util.Hashtable;
import java.util.jar.Attributes;

// NOTE: in this "language", can NOT have nested types: e.g. can't have
//   "...*italicize**subscript*<chars>*end-subscript**end-italicize*..."
//  INSTEAD, could do "...*italsubscript*<chars>*end-italsubscript*..."

public class STR {

    public static final String ITAL = "*italicize*";
    public static final String BOLD = "*bold*";
    public static final String BOLDITAL = "*Boldital*";
    public static final String SUP = "*superscript*";
    public static final String SUB = "*subscript*";
    public static final String BOLD_SUP = "*boldsuper*";
    public static final String BOLD_SUB = "*boldsub*";
    public static final String ITAL_SUP = "*italsuper*";
    public static final String ITAL_SUB = "*italsub*";
    public static final String RED = "*red*";
    public static final String BLUE = "*blue*";
    public static final String GREEN = "*green*";
    public static final String YELLOW = "*yellow*";
    public static final String PHIFONT = "*phifont*";
    public static final String SUBPHI = "*subphi*";
    public static final String SERIF14 = "*serif14*";
    public static final String SUBSUB = "*subsubscript*";
    public static final String SUPSUP = "*supsuperscript*";
    public static final String HAT = "*hat*";
    public static final String PHIHAT = "*phihat*";
    public static final String VBAR = "*vbar*";
    public static final String FRACTION = "*fraction*";
    public static final String XHAT = "*xhat*";
    public static final String YHAT = "*yhat*";
    public static final String PLUS2FONT = "*plus2font*";
    public static final String MULT = "*mult*";
    public static final String ZHAT = "*zhat*";

    public static final String ENDITAL = "*end-italicize*";
    public static final String ENDBOLD = "*end-bold*";
    public static final String ENDBOLDITAL = "*end-Boldital*";
    public static final String ENDSUP = "*end-superscript*";
    public static final String ENDSUB = "*end-subscript*";
    public static final String ENDBOLD_SUP = "*end-boldsuper*";
    public static final String ENDBOLD_SUB = "*end-boldsub*";
    public static final String ENDITAL_SUP = "*end-italsuper*";
    public static final String ENDITAL_SUB = "*end-italsub*";
    public static final String ENDRED = "*end-red*";
    public static final String ENDBLUE = "*end-blue*";
    public static final String ENDGREEN = "*end-green*";
    public static final String ENDYELLOW = "*end-yellow*";
    public static final String ENDPHIFONT = "*end-phifont*";
    public static final String ENDSUBPHI = "*end-subphi*";
    public static final String ENDSERIF14 = "*end-serif14*";
    public static final String ENDSUBSUB = "*end-subsubscript*";
    public static final String ENDSUPSUP = "*end-supsuperscript*";
    public static final String ENDHAT = "*end-hat*";
    public static final String ENDPHIHAT = "*end-phihat*";
    public static final String ENDVBAR = "*end-vbar*";
    public static final String ENDFRACTION = "*end-fraction*";
    public static final String ENDXHAT = "*end-xhat*";
    public static final String ENDYHAT = "*end-yhat*";
    public static final String ENDPLUS2FONT = "*end-plus2font*";
    public static final String ENDMULT = "*end-mult*";
    public static final String ENDZHAT = "*end-zhat*";
    
    

    public static String[] delims = {"*italicize*","*bold*","*Boldital*",
                                     "*superscript*",
                                     "*subscript*","*boldsuper*","*boldsub*",
                                     "*italsuper*","*italsub*","*red*",
                                     "*blue*","*green*","*yellow*",
                                     "*phifont*","*subphi*","*serif14*",
                                     "*subsubscript*","*supsuperscript*",
                                     "*hat*","*phihat*","*vbar*",
                                     "*fraction*","*xhat*","*yhat*",
                                     "*plus2font*","*mult*","*zhat*"};
    public static String[] enddelims = {"*end-italicize*", "*end-bold*",
                                        "*end-Boldital*",
                                        "*end-superscript*","*end-subscript*",
                                        "*end-boldsuper*","*end-boldsub*",
                                        "*end-italsuper*","*end-italsub*",
                                        "*end-red*","*end-blue*","*end-green*",
                                        "*end-yellow*","*end-phifont*",
                                        "*end-subphi*","*end-serif14*",
                                        "*end-subsubscript*",
                                        "*end-supsuperscript*","*end-hat*",
                                        "*end-phihat*","*end-vbar*",
                                        "*end-fraction*",
                                        "*end-xhat*","*end-yhat*",
                                        "*end-plus2font*","*end-mult*",
                                        "*end-zhat*"};

    public static int displayString(String info, Graphics g, int x, int y) {
        Color oldColor = g.getColor();
        // *** NOTE: assume g.setFont(<font>) already done for desired font ***
        //System.out.println("total string: "+info);
        String s = info;
        FontMetrics fm = g.getFontMetrics();
        Font font = g.getFont();
        int fsize = font.getSize();
        while (s.length() > 0) {
            PARSEinfo pi = parseString(s);
            //pi.displayStuff();
            switch (pi.delimType) {
            case PARSEinfo.ITAL:  
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(TheFonts.italic16.deriveFont((float)fsize));
                else {
                    //g.setFont(font.deriveFont(Font.ITALIC,(float)fsize));
                    //g.setFont(new Font("Serif",Font.ITALIC,fsize+2));
                    g.setFont(new Font("Serif",Font.ITALIC,fsize+1));
                }
		fm = g.getFontMetrics();
                g.drawString(pi.str2,x,y);
                x = x + fm.stringWidth(pi.str2) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font);
                else 
                    g.setFont(font.deriveFont(Font.PLAIN,(float)fsize));
		fm = g.getFontMetrics();
                break;
            case PARSEinfo.BOLD:  
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(TheFonts.bold16.deriveFont((float)fsize));
                else 
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize));
		fm = g.getFontMetrics();
                g.drawString(pi.str2,x,y);
                x = x + fm.stringWidth(pi.str2) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font);
                else 
                    g.setFont(font.deriveFont(Font.PLAIN,(float)fsize));
		fm = g.getFontMetrics();
                break;
            case PARSEinfo.BOLDITAL:  
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(TheFonts.bolditalic16.deriveFont((float)fsize));
                else 
                    g.setFont(new Font("Serif",Font.ITALIC | Font.BOLD,fsize));
		fm = g.getFontMetrics();
                g.drawString(pi.str2,x,y);
                x = x + fm.stringWidth(pi.str2) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font);
                else 
                    g.setFont(font.deriveFont(Font.PLAIN,(float)fsize));
		fm = g.getFontMetrics();
                break;
            case PARSEinfo.SUP:  
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font.deriveFont((float)fsize-3));
                else
                    g.setFont(font.deriveFont((float)fsize-3));
		fm = g.getFontMetrics();
		y = y - fm.getHeight()/3;
		g.drawString(pi.str2,x,y);
		y = y + fm.getHeight()/3;
		x = x + fm.stringWidth(pi.str2) + 1;
                g.setFont(font.deriveFont((float)fsize));
		fm = g.getFontMetrics();
                break;
            case PARSEinfo.SUB:  
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font.deriveFont((float)fsize-4));
                else
                    g.setFont(font.deriveFont((float)fsize-2));
		fm = g.getFontMetrics();
		y = y + fm.getHeight()/3;
		g.drawString(pi.str2,x,y);
		y = y - fm.getHeight()/3;
		x = x + fm.stringWidth(pi.str2) + 1;
                g.setFont(font.deriveFont((float)fsize));
		fm = g.getFontMetrics();
                break;
            case PARSEinfo.BOLD_SUP:  
                //System.out.println("bold-superscript");
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(TheFonts.bold16.deriveFont((float)fsize-3));
                else 
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize-3));

                //if (TheFonts.useTTFonts)
                //    g.setFont(font.deriveFont((float)fsize-3));
                //else
                //    g.setFont(font.deriveFont((float)fsize-3));
		fm = g.getFontMetrics();
		y = y - fm.getHeight()/3;
		g.drawString(pi.str2,x,y);
		y = y + fm.getHeight()/3;
		x = x + fm.stringWidth(pi.str2) + 1;
                g.setFont(font.deriveFont((float)fsize));
		fm = g.getFontMetrics();
                break;
            case PARSEinfo.BOLD_SUB:  
                System.out.println("bold-subscript");
                break;
            case PARSEinfo.ITAL_SUP:  
                System.out.println("ital-superscript");
                break;
            case PARSEinfo.ITAL_SUB:  
                System.out.println("ital-subscript");
                break;
            case PARSEinfo.RED:
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                g.setColor(Color.red.brighter().brighter());
		g.drawString(pi.str2,x,y);
                x = x + fm.stringWidth(pi.str2) + 1;
                g.setColor(oldColor);
                break;
            case PARSEinfo.BLUE:
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                g.setColor(Color.blue.brighter().brighter());
		g.drawString(pi.str2,x,y);
                x = x + fm.stringWidth(pi.str2) + 1;
                g.setColor(oldColor);
                break;
            case PARSEinfo.GREEN:
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                g.setColor(Color.green.darker().darker());
		g.drawString(pi.str2,x,y);
                x = x + fm.stringWidth(pi.str2) + 1;
                g.setColor(oldColor);
                break;
            case PARSEinfo.YELLOW:
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                g.setColor(Color.yellow);
		g.drawString(pi.str2,x,y);
                x = x + fm.stringWidth(pi.str2) + 1;
                g.setColor(oldColor);
                break;
            case PARSEinfo.PHIFONT:
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    //g.setFont(TheFonts.symbol15.deriveFont((float)fsize));
                    g.setFont(TheFonts.symbol14);
                else {
                    //g.setFont(TheFonts.symbol15.deriveFont((float)fsize));
                    g.setFont(TheFonts.symbol14);
                }
		fm = g.getFontMetrics();

                if (pi.str2.equals(Character.toString((char)0x03c6)) &&
                    !TheFonts.useTTFonts) {
                    g.setFont(new Font("SanSerif",Font.ITALIC,12));
                    fm = g.getFontMetrics();
                    int charwidth = fm.charWidth('O');
                    g.drawString("O",x,y);
                    g.setFont(new Font("Serif",Font.PLAIN,16));
                    if (!TheFonts.MAC_OS_X && !TheFonts.PC_OS)
                        g.drawString("/",x+1,y+1);
                    else
                        g.drawString("/",x+3,y+1);
                    x += fm.stringWidth("O") + 1;
                } else {
                    g.drawString(pi.str2,x,y);
                    x += fm.stringWidth(pi.str2) + 1;
                }
                if (TheFonts.useTTFonts)
                    g.setFont(font);
                else 
                    g.setFont(font.deriveFont(Font.PLAIN,(float)fsize));
		fm = g.getFontMetrics();
                break;
            case PARSEinfo.SUBPHI:
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font.deriveFont((float)fsize-4));
                else
                    g.setFont(font.deriveFont((float)fsize-2));
		fm = g.getFontMetrics();
		y = y + fm.getHeight()/3;
		g.drawString("o",x,y);

                // NEED TO TEST THIS ON ALL PLATFORMS

                if (!TheFonts.MAC_OS_X && !TheFonts.PC_OS)
                    g.drawString("/",x,y+1);
                else {
                    if (TheFonts.MAC_OS_X)
                        g.drawString("/",x,y+1);
                    else
                        g.drawString("/",x+2,y+1);  // PC
                }
		y = y - fm.getHeight()/3;
		x = x + fm.stringWidth(pi.str2) + 1;
                g.setFont(font.deriveFont((float)fsize));
		fm = g.getFontMetrics();
                
                break;
            case PARSEinfo.SERIF14:  
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(TheFonts.serif14);
                else 
                    g.setFont(new Font("Serif",Font.PLAIN,14));
		fm = g.getFontMetrics();
                g.drawString(pi.str2,x,y);
                x = x + fm.stringWidth(pi.str2) + 1;
                //if (TheFonts.useTTFonts)
                //    g.setFont(font);
                //else 
                //    g.setFont(font.deriveFont(Font.PLAIN,(float)fsize));
                g.setFont(font);
		fm = g.getFontMetrics();
                break;
            case PARSEinfo.SUBSUB:  
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font.deriveFont((float)fsize-6));
                else
                    g.setFont(font.deriveFont((float)fsize-4));
		fm = g.getFontMetrics();
		y = y + (int)(fm.getHeight()/1.5);
		g.drawString(pi.str2,x,y);
		y = y - (int)(fm.getHeight()/1.5);
		x = x + fm.stringWidth(pi.str2) + 1;
                g.setFont(font.deriveFont((float)fsize));
		fm = g.getFontMetrics();
                break;
            case PARSEinfo.SUPSUP:  
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font.deriveFont((float)fsize-4));
                else
                    g.setFont(font.deriveFont((float)fsize-4));
		fm = g.getFontMetrics();
		y = y - (int)(fm.getHeight()/1.5);
		g.drawString(pi.str2,x,y);
		y = y + (int)(fm.getHeight()/1.5);
		x = x + fm.stringWidth(pi.str2) + 1;
                g.setFont(font.deriveFont((float)fsize));
		fm = g.getFontMetrics();
                break;
            case PARSEinfo.HAT:
                g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(TheFonts.bold16.deriveFont((float)fsize));
                else 
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize));
		fm = g.getFontMetrics();
                g.drawString(pi.str2,x,y);

                if (TheFonts.useTTFonts)
                    g.setFont(font.deriveFont((float)fsize+2));
                else
                    g.setFont(font.deriveFont((float)fsize+2));

                if (pi.str2.equals("R")) 
                    g.drawString("\u02c6",x,y-2); // draw the hat
                else
                    g.drawString("\u02c6",x,y); // draw the hat
                x = x + fm.stringWidth(pi.str2) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font);
                else 
                    g.setFont(font.deriveFont(Font.PLAIN,(float)fsize));
		fm = g.getFontMetrics();
                break;

            case PARSEinfo.PHIHAT:
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    //g.setFont(TheFonts.symbol14);
                    g.setFont(TheFonts.bold16.deriveFont((float)fsize));
                else {
                    //g.setFont(TheFonts.symbol14);
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize));
                }
		fm = g.getFontMetrics();

                if (pi.str2.equals(Character.toString((char)0x03c6)) &&
                    !TheFonts.useTTFonts) {
                    //g.setFont(new Font("SanSerif",Font.ITALIC,12));
                    g.setFont(new Font("SanSerif",Font.ITALIC | Font.BOLD,12));
                    fm = g.getFontMetrics();
                    int charwidth = fm.charWidth('O');
                    g.drawString("O",x,y);
                    g.setFont(new Font("Serif",Font.PLAIN,16));
                    if (!TheFonts.MAC_OS_X && !TheFonts.PC_OS)
                        g.drawString("/",x+1,y+1);
                    else
                        g.drawString("/",x+3,y+1);
                    g.drawString("\u02c6",x+1,y); // draw the hat
                    x += fm.stringWidth("O") + 1;
                } else {
                    g.drawString(pi.str2,x,y);
                    x += fm.stringWidth(pi.str2) + 1;
                }


                if (TheFonts.useTTFonts)
                    g.setFont(font.deriveFont((float)fsize+2));
                else
                    g.setFont(font.deriveFont((float)fsize+2));


                //g.drawString("\u02c6",x,y); // draw the hat
                //x = x + fm.stringWidth(pi.str2) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font);
                else 
                    g.setFont(font.deriveFont(Font.PLAIN,(float)fsize));
		fm = g.getFontMetrics();
                break;

            case PARSEinfo.VBAR:

                /*
                g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font.deriveFont((float)fsize));
                else
                    g.setFont(font.deriveFont((float)fsize));
		fm = g.getFontMetrics();

                g.drawString(pi.str2,x,y);

                // draw bar on top
                int newY = y - fm.getHeight()+6;
                g.drawLine(x,newY,x+fm.stringWidth(pi.str2)-1,newY);
                x = x + fm.stringWidth(pi.str2) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font);
                else 
                    g.setFont(font.deriveFont(Font.PLAIN,(float)fsize));
		fm = g.getFontMetrics();
                break;
                */

                // Draw bold instead
                g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize));
                else
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize));
		fm = g.getFontMetrics();

                g.drawString(pi.str2,x,y);

                x = x + fm.stringWidth(pi.str2) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font);
                else 
                    g.setFont(font.deriveFont(Font.PLAIN,(float)fsize));
		fm = g.getFontMetrics();
                break;

            case PARSEinfo.FRACTION:
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
		fm = g.getFontMetrics();
                char divide = (char)0x00f7;
                //int index = pi.str2.indexOf("/");
                int index = pi.str2.indexOf(divide);
                int iN[], iD[], wN, wD, tab, n, w;
                String expN[], expD[];
                FontMetrics fm2;

                if (index != -1) {
                    String numer = pi.str2.substring(0,index);
                    String denom = pi.str2.substring(index+1);

                    iN = new int[3];
                    iD = new int[3];
                    expN = new String[3];
                    expD = new String[3];

                    // Assign exponents, if any, for numerator and denominator:
                    n = 0;
                    for (int i = 0; i < iN.length; i++) {
                        iN[i] = numer.indexOf("**",n);
                        if (iN[i] == -1) break;
                        else {
                            expN[i] = numer.substring(iN[i]+2,iN[i]+3);
                            n = iN[i] + 3;
                        }
                    }
                    n = 0;
                    for (int i = 0; i < iD.length; i++) {
                        iD[i] = denom.indexOf("**",n);
                        if (iD[i] == -1) break;
                        else {
                            expD[i] = denom.substring(iD[i]+2,iD[i]+3);
                            n = iD[i] + 3;
                        }
                    }

                    // Get actual widths of both numerator and denominator:
                    g.setFont(font.deriveFont((float)fsize-4));
                    fm2 = g.getFontMetrics();
                    g.setFont(font.deriveFont((float)fsize));
                    n = 0;
                    wN = 0;
                    for (int i = 0; i < iN.length; i++) {
                        if (iN[i] == -1) break;
                        wN += fm.stringWidth(numer.substring(n,iN[i]));
                        wN += fm2.stringWidth(expN[i]);
                        n = iN[i]+3;
                    }
                    wN += fm.stringWidth(numer.substring(n));
                    n = 0;
                    wD = 0;
                    for (int i = 0; i < iD.length; i++) {
                        if (iD[i] == -1) break;
                        wD += fm.stringWidth(denom.substring(n,iD[i]));
                        wD += fm2.stringWidth(expD[i]);
                        n = iD[i]+3;
                    }
                    wD += fm.stringWidth(denom.substring(n));

                    tab = (int) Math.abs(wN-wD)/2;

                    // DRAW:
                    //case where numerator wider than denominator:
                    if (wN > wD) {
                        w = 0;
                        n = 0;
                        for (int i = 0; i < iN.length; i++) {
                            if (iN[i] == -1) break;
                            g.drawString(numer.substring(n,iN[i]),x+w,y-7);
                            w += fm.stringWidth(numer.substring(n,iN[i]));
                            g.setFont(font.deriveFont((float)fsize-4));
                            y -= fm.getHeight()/4;
                            g.drawString(expN[i],x+w+1,y-7);
                            y += fm.getHeight()/4;
                            w += fm2.stringWidth(expN[i]) + 1;
                            g.setFont(font.deriveFont((float)fsize));
                            n = iN[i]+3;
                        }
                        g.drawString(numer.substring(n),x+w,y-7);

                        w = 0;
                        n = 0;
                        for (int i = 0; i < iD.length; i++) {
                            if (iD[i] == -1) break;
                            g.drawString(denom.substring(n,iD[i]),x+tab+w,y+7);
                            w += fm.stringWidth(denom.substring(n,iD[i]));
                            g.setFont(font.deriveFont((float)fsize-4));
                            y -= fm.getHeight()/4;
                            g.drawString(expD[i],x+tab+w+1,y+7);
                            y += fm.getHeight()/4;
                            w += fm2.stringWidth(expD[i]) + 1;
                            g.setFont(font.deriveFont((float)fsize));
                            n = iD[i]+3;
                        }
                        g.drawString(denom.substring(n),x+tab+w,y+7);
                        g.drawLine(x,y-5,x+wN,y-5);
                        x = x + wN + 1;

                    // case where denominator wider than numerator:
                    } else {
                        w = 0;
                        n = 0;
                        for (int i = 0; i < iN.length; i++) {
                            if (iN[i] == -1) break;
                            g.drawString(numer.substring(n,iN[i]),x+tab+w,y-7);
                            w += fm.stringWidth(numer.substring(n,iN[i]));
                            g.setFont(font.deriveFont((float)fsize-4));
                            y -= fm.getHeight()/4;
                            g.drawString(expN[i],x+tab+w+1,y-7);
                            y += fm.getHeight()/4;
                            w += fm2.stringWidth(expN[i]) + 1;
                            g.setFont(font.deriveFont((float)fsize));
                            n += iN[i]+3;
                        }
                        if (n <= numer.length())
                            g.drawString(numer.substring(n),x+tab+w,y-7);

                        w = 0;
                        n = 0;
                        for (int i = 0; i < iD.length; i++) {
                            if (iD[i] == -1) break;
                            g.drawString(denom.substring(n,iD[i]),x+w,y+7);
                            w += fm.stringWidth(denom.substring(n,iD[i]));
                            g.setFont(font.deriveFont((float)fsize-4));
                            y -= fm.getHeight()/4;
                            g.drawString(expD[i],x+w+1,y+7);
                            y += fm.getHeight()/4;
                            w += fm2.stringWidth(expD[i]) + 1;
                            g.setFont(font.deriveFont((float)fsize));
                            n += iD[i]+3;
                        }
                        if (n <= denom.length())
                            g.drawString(denom.substring(n),x+w,y+7);
                        
                        g.drawLine(x,y-5,x+wD,y-5);
                        x = x + wD + 1;
                    }

                } // endif a real fraction with a divide character
                break;


            case PARSEinfo.XHAT:
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    //g.setFont(TheFonts.symbol14);
                    g.setFont(TheFonts.bold16.deriveFont((float)fsize));
                else {
                    //g.setFont(TheFonts.symbol14);
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize));
                }
		fm = g.getFontMetrics();

                if (pi.str2.equals("x") && !TheFonts.useTTFonts) {
                    //g.setFont(new Font("SanSerif",Font.ITALIC,12));
                    //g.setFont(new Font("SanSerif",Font.ITALIC | Font.BOLD,12));
                    g.setFont(new Font("SanSerif",Font.BOLD,12));
                    fm = g.getFontMetrics();
                    int charwidth = fm.charWidth('x');
                    g.drawString("x",x,y);
                    g.setFont(new Font("Serif",Font.PLAIN,16));
                    g.drawString("\u02c6",x-1,y); // draw the hat
                    x += fm.stringWidth("x") + 1;
                } else {
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize));
                    g.drawString(pi.str2,x,y); // str2 should be x
                    g.setFont(new Font("Serif",Font.PLAIN,16));
                    g.drawString("\u02c6",x-1,y); // draw the hat
                    //x += fm.stringWidth("x") + 1;                    
                    x += fm.stringWidth(pi.str2) + 1;
                }

                //if (TheFonts.useTTFonts)
                //    g.setFont(font.deriveFont((float)fsize+2));
                //else
                //    g.setFont(font.deriveFont((float)fsize+2));

                //g.drawString("\u02c6",x,y); // draw the hat
                //x = x + fm.stringWidth(pi.str2) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font);
                else 
                    g.setFont(font.deriveFont(Font.PLAIN,(float)fsize));
		fm = g.getFontMetrics();
                break;


            case PARSEinfo.YHAT:
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    //g.setFont(TheFonts.symbol14);
                    g.setFont(TheFonts.bold16.deriveFont((float)fsize));
                else {
                    //g.setFont(TheFonts.symbol14);
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize));
                }
		fm = g.getFontMetrics();

                if (pi.str2.equals("y") && !TheFonts.useTTFonts) {
                    //g.setFont(new Font("SanSerif",Font.ITALIC,12));
                    //g.setFont(new Font("SanSerif",Font.ITALIC | Font.BOLD,12));
                    g.setFont(new Font("SanSerif",Font.BOLD,12));
                    fm = g.getFontMetrics();
                    int charwidth = fm.charWidth('y');
                    g.drawString("y",x,y);
                    g.setFont(new Font("Serif",Font.PLAIN,16));
                    g.drawString("\u02c6",x-1,y); // draw the hat
                    x += fm.stringWidth("y") + 1;
                } else {
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize));
                    g.drawString(pi.str2,x,y); // str2 should be y
                    g.setFont(new Font("Serif",Font.PLAIN,16));
                    g.drawString("\u02c6",x-1,y); // draw the hat
                    //x += fm.stringWidth("y") + 1;                    
                    x += fm.stringWidth(pi.str2) + 1;
                }

                //if (TheFonts.useTTFonts)
                //    g.setFont(font.deriveFont((float)fsize+2));
                //else
                //    g.setFont(font.deriveFont((float)fsize+2));

                //g.drawString("\u02c6",x,y); // draw the hat
                //x = x + fm.stringWidth(pi.str2) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font);
                else 
                    g.setFont(font.deriveFont(Font.PLAIN,(float)fsize));
		fm = g.getFontMetrics();
                break;

            case PARSEinfo.PLUS2FONT:  
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(TheFonts.bold14.deriveFont(Font.BOLD,(float)fsize+2));
                else 
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize+2));
		fm = g.getFontMetrics();
                g.drawString(pi.str2,x,y);
                x = x + fm.stringWidth(pi.str2) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font);
                else 
                    g.setFont(font.deriveFont((float)fsize));
		fm = g.getFontMetrics();
                break;

            case PARSEinfo.MULT:
                g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                fm = g.getFontMetrics();
                g.drawString(pi.str2,x,y);
                g.drawString(pi.str2,x+1,y);
                x = x + fm.stringWidth(pi.str2) + 2;
                //fm = g.getFontMetrics();
                break;


            case PARSEinfo.ZHAT:
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    //g.setFont(TheFonts.symbol14);
                    g.setFont(TheFonts.bold16.deriveFont((float)fsize));
                else {
                    //g.setFont(TheFonts.symbol14);
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize));
                }
		fm = g.getFontMetrics();

                if (pi.str2.equals("z") && !TheFonts.useTTFonts) {
                    //g.setFont(new Font("SanSerif",Font.ITALIC,12));
                    //g.setFont(new Font("SanSerif",Font.ITALIC | Font.BOLD,12));
                    g.setFont(new Font("SanSerif",Font.BOLD,12));
                    fm = g.getFontMetrics();
                    int charwidth = fm.charWidth('z');
                    g.drawString("z",x,y);
                    g.setFont(new Font("Serif",Font.PLAIN,16));
                    g.drawString("\u02c6",x-1,y); // draw the hat
                    x += fm.stringWidth("z") + 1;
                } else {
                    g.setFont(font.deriveFont(Font.BOLD,(float)fsize));
                    g.drawString(pi.str2,x,y); // str2 should be z
                    g.setFont(new Font("Serif",Font.PLAIN,16));
                    g.drawString("\u02c6",x-1,y); // draw the hat
                    //x += fm.stringWidth("x") + 1;                    
                    x += fm.stringWidth(pi.str2) + 1;
                }

                //if (TheFonts.useTTFonts)
                //    g.setFont(font.deriveFont((float)fsize+2));
                //else
                //    g.setFont(font.deriveFont((float)fsize+2));

                //g.drawString("\u02c6",x,y); // draw the hat
                //x = x + fm.stringWidth(pi.str2) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font);
                else 
                    g.setFont(font.deriveFont(Font.PLAIN,(float)fsize));
		fm = g.getFontMetrics();
                break;

            case PARSEinfo.NO_DELIMITER:
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                break;
            }

            if (pi.nextIndex >= s.length()) return x;
            s=s.substring(pi.nextIndex);
        }
        return x;
    }

        
    public static PARSEinfo parseString(String s) {
        int[] index =  new int[PARSEinfo.numDelimTypes];
        int start, end;
        int nextIndex;   // index of char beyond any found delimiters.
        PARSEinfo pi;
        for (int i=0; i<PARSEinfo.numDelimTypes; i++)
            index[i] = s.indexOf(delims[i]);

        int delimType = getMinNonZeroIndex(index);
        //System.out.println(" *delimType = "+String.valueOf(delimType));
        if (delimType == PARSEinfo.NO_DELIMITER)
            pi = new PARSEinfo(PARSEinfo.NO_DELIMITER,s,"",s.length());
        else {
            start = index[delimType];
            start += delims[delimType].length();
            end = s.indexOf(enddelims[delimType]);
            nextIndex = end + enddelims[delimType].length();
            if (end < 0) end = s.length();
            //System.out.println(" *s = "+s);
            //System.out.println(" *start = "+String.valueOf(start)+" end = "+
            //                   String.valueOf(end));
            pi = new PARSEinfo(delimType,s.substring(0,index[delimType]),
                               s.substring(start,end),nextIndex);
        }
        return pi;
    }


    private static int getMinNonZeroIndex(int[] list) {
        int min = PARSEinfo.NO_DELIMITER;
        int index = PARSEinfo.NO_DELIMITER;
        for (int i=0; i<list.length; i++) {
            if (list[i] < min && list[i] >= 0) {
                min = list[i];
                index = i;
            }
        }
        return index;
    }


}

class PARSEinfo {

    public static final int ITAL = 0;
    public static final int BOLD = 1;
    public static final int BOLDITAL = 2;
    public static final int SUP = 3;
    public static final int SUB = 4;
    public static final int BOLD_SUP = 5;
    public static final int BOLD_SUB = 6;
    public static final int ITAL_SUP = 7;
    public static final int ITAL_SUB = 8;
    public static final int RED = 9;
    public static final int BLUE = 10;
    public static final int GREEN = 11;
    public static final int YELLOW = 12;
    public static final int PHIFONT = 13;
    public static final int SUBPHI = 14;
    public static final int SERIF14 = 15;
    public static final int SUBSUB = 16;
    public static final int SUPSUP = 17;
    public static final int HAT = 18;
    public static final int PHIHAT = 19;
    public static final int VBAR = 20;
    public static final int FRACTION = 21;
    public static final int XHAT = 22;
    public static final int YHAT = 23;
    public static final int PLUS2FONT = 24;
    public static final int MULT = 25;
    public static final int ZHAT = 26;

    public static final int NO_DELIMITER = 99;

    public static final int numDelimTypes = 27;

    public int delimType;
    public String str1, str2;
    public int nextIndex;

    public PARSEinfo() {
        super();
        delimType = 0;
        str1 = "";
        str2 = "";
        nextIndex = -1;
    }

    public PARSEinfo(int type, String str1, String str2, int nextIndex) {
        this.delimType = type;
        this.str1 = str1;
        this.str2 = str2;
        this.nextIndex = nextIndex;
    }

    public void displayStuff() {
        System.out.println("type: "+String.valueOf(delimType)+
                           " string 1: "+str1+" string 2: "+str2+
                           " next index: "+String.valueOf(nextIndex));
    }
}
