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 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 ENDITAL = "*end-italicize*";
    public static final String ENDBOLD = "*end-bold*";
    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 String[] delims = {"*italicize*","*bold*","*superscript*",
                                     "*subscript*","*boldsuper*","*boldsub*",
                                     "*italsuper*","*italsub*","*red*",
                                     "*blue*","*green*","*yellow*",
                                     "*phifont*","*subphi*","*serif14*",
                                     "*subsubscript*"};
    public static String[] enddelims = {"*end-italicize*", "*end-bold*",
                                        "*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*"};

    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.SUP:  
		g.drawString(pi.str1,x,y);
		x = x + fm.stringWidth(pi.str1) + 1;
                if (TheFonts.useTTFonts)
                    g.setFont(font.deriveFont((float)fsize-2));
                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.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");
                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.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 SUP = 2;
    public static final int SUB = 3;
    public static final int BOLD_SUP = 4;
    public static final int BOLD_SUB = 5;
    public static final int ITAL_SUP = 6;
    public static final int ITAL_SUB = 7;
    public static final int RED = 8;
    public static final int BLUE = 9;
    public static final int GREEN = 10;
    public static final int YELLOW = 11;
    public static final int PHIFONT = 12;
    public static final int SUBPHI = 13;
    public static final int SERIF14 = 14;
    public static final int SUBSUB = 15;


    public static final int NO_DELIMITER = 99;

    public static final int numDelimTypes = 16;

    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));
    }
}
