import java.applet.*;
import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;

public class NavApplet extends Applet {
    private final static String DIRS = "/\\:";

    private final static String ABOUT = "about.gif";
    private final static int ABOUT_X = 5;
    private final static int ABOUT_Y = 5;    
    
    private final static String ITEMS = "navwind.txt";
    private final static int WIDTH  = 400;
    private final static int HEIGHT = 405;

    private final static int OUTPUT_WIDTH  = 380;
    private final static int OUTPUT_HEIGHT = 380;

    Lay lay_;

    List list_;
    Checkbox bold1_, bold2_, italic1_, italic2_;
    Label selected_, other_;
    Choice size1_, size2_;
    TextField title_, url_, sep_;
    Button up_, down_, remove_, new_, breakUp_, breakDown_, export_;

    TextWindow output_ = null;

    Image about_ = null;
    
    Image image_ = null;
    Graphics offscreen_;

    private static String newline_ = null;
    private int lineBreak_ = 0;
    
    public void init() {
        setBackground(Color.lightGray);
        lay_ = new Lay(this, 400, 380);

        try {
	    URL u = new URL(getCodeBase(), ITEMS);
            lay_.add(new DataInputStream(u.openStream()));
//            lay_.add(new DataInputStream(new FileInputStream(ITEMS)));
        } catch (IOException e) {
            System.out.println("Could not read items: " + e);
            return;
        }

        bold1_    = (Checkbox)lay_.get("Bold1");
        bold2_    = (Checkbox)lay_.get("Bold2");
        italic1_  = (Checkbox)lay_.get("Italic1");
        italic2_  = (Checkbox)lay_.get("Italic2");
        selected_ = (Label)lay_.get("Selected");
        other_    = (Label)lay_.get("Other");

        list_   = (List)lay_.get("List");
        title_  = (TextField)lay_.get("Title");
        url_    = (TextField)lay_.get("URL");

        up_     = (Button)lay_.get("Up");
        down_   = (Button)lay_.get("Down");
        remove_ = (Button)lay_.get("Remove");
        new_    = (Button)lay_.get("New");

        sep_ = (TextField)lay_.get("Sep");

        size1_ = (Choice)lay_.get("Size1");
        size2_ = (Choice)lay_.get("Size2");        

        breakUp_   = (Button)lay_.get("BreakUp");
        breakDown_ = (Button)lay_.get("BreakDown");
        export_ = (Button)lay_.get("Export");
        export_.move((WIDTH - export_.size().width) / 2,
                     export_.location().y);

        fixBreak();
        updateDisplays();
        synchList();
        repaint();
    }

    public void drawPreview(Graphics g) {
        Vector v = new Vector();
        
        int highlight = list_.getSelectedIndex();
        if (highlight == -1)
            highlight = 0;
        
        String sep = sep_.getText();
        int max = list_.countItems();

        Font selFont   = selected_.getFont();
        Font otherFont = other_.getFont();        

        FontMetrics selMetrics = getFontMetrics(selFont);
        FontMetrics otherMetrics = getFontMetrics(otherFont);        
        
        v.addElement(otherFont);
        v.addElement(Color.blue);
        
        for (int loop = 0; loop < max; ++loop) {
            v.addElement(Color.black);
            if (loop != 0 && loop != lineBreak_ + 1)
                v.addElement(sep);

            if (loop == highlight)
                v.addElement(selFont);
            else
                v.addElement(Color.blue);                

            String item = list_.getItem(loop);
            String title = item.substring(1, item.indexOf('"', 1));
            
            v.addElement(title);

            if (loop == lineBreak_)
                v.addElement(new Character('\n'));
            
            if (loop == highlight)
                v.addElement(otherFont);
        }

        int x = 0;
        int x1 = 0;

        FontMetrics metrics = null;
        for (int loop = 0; loop < v.size(); ++loop) {
            Object o = v.elementAt(loop);
            if (o instanceof Font) {
                if (o == selFont)
                    metrics = selMetrics;
                else
                    metrics = otherMetrics;
            }
            else if (o instanceof String)
                x += metrics.stringWidth((String)o);
            else if (o instanceof Character) {
                x1 = x;
                x = 0;
            }
        }

        int y = 10;
        int y2 = y + Math.max(selMetrics.getHeight(),
                              otherMetrics.getHeight());
            
        int x2 = (WIDTH - x ) / 2;
            x  = (WIDTH - x1) / 2;
        
        for (int loop = 0; loop < v.size(); ++loop) {
            Object o = v.elementAt(loop);
            if (o instanceof Font) {
                if (o == selFont)
                    metrics = selMetrics;
                else
                    metrics = otherMetrics;
                g.setFont((Font)o);
            }
            else if (o instanceof Color)
                g.setColor((Color)o);
            else if (o instanceof Character) {
                x = x2;
                y = y2;
            }
            else {
                String s = (String)o;
                g.drawString(s, x, y);
                x += metrics.stringWidth(s);
            }
        }
    }

    public void fixBreak() {
        // a-0 | b-1 | c-2
        int max = list_.countItems() - 1;
        if (lineBreak_ < 0)
            lineBreak_ = 0;
        if (lineBreak_ > max)
            lineBreak_ = max;
        breakUp_.enable(lineBreak_ > 0);
        breakDown_.enable(lineBreak_ < max);
    }
    
    public void updateDisplays() {
        Font f = selected_.getFont();
        int style = Font.PLAIN;
        if (bold1_.getState())
            style += Font.BOLD;
        if (italic1_.getState())
            style += Font.ITALIC;
        int size = 12;
        char c = size1_.getSelectedItem().charAt(0);
        switch (c) {
            case 's': size = 10; break;
            case 'm': size = 12; break;
            case 'l': size = 14; break;                
        }
        
        selected_.setFont(new Font(f.getName(), style, size));

        f = other_.getFont();
        style = Font.PLAIN;
        if (bold2_.getState())
            style += Font.BOLD;
        if (italic2_.getState())
            style += Font.ITALIC;
        c = size2_.getSelectedItem().charAt(0);
        switch (c) {
            case 's': size = 10; break;
            case 'm': size = 12; break;
            case 'l': size = 14; break;                
        }
        
        other_.setFont(new Font(f.getName(), style, size));
    }

    private int lastSet_ = -1;

    public void updateCurrentItem() {
        String title = title_.getText();
        String url = url_.getText();        
        String item = "\"" + title + "\"=" + url;

        boolean fix = false;
        int current = list_.getSelectedIndex();
        int tStart = 0, tEnd = 0, uStart = 0, uEnd = 0;
        if (current == -1) {

            tStart = title_.getSelectionStart();
            tEnd   = title_.getSelectionEnd();            
            uStart = url_.getSelectionStart();
            uEnd   = url_.getSelectionEnd();

            fix = true;
            list_.addItem(item);
            current = list_.countItems() - 1;

            fixBreak();
        }
        else
            list_.replaceItem(item, current);

        list_.select(current);

        synchList();
        
        if (fix) {
             title_.select(tStart, tEnd);
             url_.select(uStart, uEnd);
        }
    }

    public void swap(int index1, int index2) {
        String t = list_.getItem(index1);
        list_.replaceItem(list_.getItem(index2), index1);
        list_.replaceItem(t, index2);
        list_.select(index2);
        synchList();
    }

    public void synchList() {
        int current = list_.getSelectedIndex();
        if (current == -1) {
            up_.disable();
            down_.disable();
            remove_.disable();
            export_.disable();
            title_.setText("");
            url_.setText("");
        }
        else {
            up_.enable(current > 0);
            down_.enable(current < list_.countItems() - 1);
            remove_.enable();
            export_.enable();
            
            if (current != lastSet_) {
                String item = list_.getSelectedItem();
                int quote2 = item.indexOf('"', 1);
                String title = item.substring(1, quote2);
                String url = item.substring(quote2 + 2, item.length());
                title_.setText(title);
                url_.setText(url);
                lastSet_ = current;
            }
        }
    }
    
    public boolean handleEvent(Event evt) {
        if (evt.id == Event.LIST_SELECT) {
            synchList();
            repaint();
            return true;
        }
        return super.handleEvent(evt);
    }
    
    public boolean action(Event evt, Object what) {
        if (evt.target instanceof Checkbox ||
            evt.target instanceof Choice) {
            updateDisplays();
            if (output_ != null)
                output_.hide();
            repaint();
            return true;
        }
        else if (evt.target instanceof Button) {
            if (evt.target == up_) {
                int current = list_.getSelectedIndex();
                if (current > 0)
                    swap(current, current - 1);
            }
            else if (evt.target == down_) {
                int current = list_.getSelectedIndex();
                if (current < list_.countItems() - 1)
                    swap(current, current + 1);
            }
            else if (evt.target == remove_) {
                int current = list_.getSelectedIndex();
                list_.delItem(current);
                fixBreak();
                synchList();
            }
            else if (evt.target == new_) {
                list_.addItem("\"untitled\"=unknown");
                list_.select(list_.countItems() - 1);
                fixBreak();
                synchList();
            }
             else if (evt.target == breakUp_) {
                --lineBreak_;
                fixBreak();
            }
            else if (evt.target == breakDown_) {
                ++lineBreak_;
                fixBreak();
            }
             else if (evt.target == export_) {
                String text = generateAll();
                if (output_ == null)
                    output_ = new TextWindow("NavBar - HTML", text,
                                             OUTPUT_WIDTH, OUTPUT_HEIGHT);
                else
                    output_.setText(text);
            }

            if (evt.target != export_ && output_ != null)
                output_.hide();
            repaint();
        }
        else if (evt.target instanceof TextField) {
            if (evt.target == title_ || evt.target == url_) {
                int current = list_.getSelectedIndex();
                if (current != -1) {
                    list_.deselect(current);
                    synchList();
                    title_.requestFocus();
                }
            }
            if (output_ != null)
                output_.hide();
        }
        return false;
    }

    public boolean keyUp(Event evt, int key) {
        if (evt.target instanceof TextField) {
            if (evt.target == title_ || evt.target == url_)
                updateCurrentItem();
            if (output_ != null)
                output_.hide();
            repaint();
            return true;
        }
        return false;
    }
    
    
    public void update(Graphics g) {
        paint(g);
    }

    public void paint (Graphics g) {
        if (image_ == null) {
            image_ = createImage(WIDTH, 50);
            offscreen_ = image_.getGraphics();
        }

        if (about_ == null)
            about_ = getImage(getCodeBase(), ABOUT);
	
        offscreen_.setColor(getBackground());
        offscreen_.fillRect(0, 0, WIDTH, 50);
        
        drawPreview(offscreen_);
        g.drawImage(image_, 0, sep_.location().y + 34, null);
	g.drawImage(about_, ABOUT_X, ABOUT_Y, this);
//        lay_.circle(g);
    }

    public String generateAll() {
        if (newline_ == null)
            newline_ = System.getProperty("line.separator");
        
        String selOpen  = "";
        String selClose = "";
        char c = size1_.getSelectedItem().charAt(0);
        if (c == 's') {
            selOpen  = "<FONT SIZE=1>";
            selClose = "</FONT>";            
        }
        else if (c == 'l') {
            selOpen  = "<FONT SIZE=3>";
            selClose = "</FONT>";            
        }
        if (bold1_.getState()) {
            selOpen  = "<B>" + selOpen;
            selClose = selClose + "</B>";
        }

        if (italic1_.getState()) {
            selOpen  = "<I>" + selOpen;
            selClose = selClose + "</I>";
        }

        String otherOpen  = "";
        String otherClose = "";
        c = size2_.getSelectedItem().charAt(0);
        if (c == 's') {
            otherOpen  = "<FONT SIZE=1>";
            otherClose = "</FONT>";            
        }
        else if (c == 'l') {
            otherOpen  = "<FONT SIZE=3>";
            otherClose = "</FONT>";            
        }
        if (bold2_.getState()) {
            otherOpen  = "<B>" + otherOpen;
            otherClose = otherClose + "</B>";
        }
        if (italic2_.getState()) {
            otherOpen  = "<I>" + otherOpen;
            otherClose = otherClose + "</I>";
        }

        int max = list_.countItems();
        String titles[] = new String[max];
        String urls[] = new String[max];
        for (int loop = 0; loop < max; ++loop) {
            String item = list_.getItem(loop);
            int quote2 = item.indexOf('"', 1);
            titles[loop] = item.substring(1, quote2).trim();
            urls[loop]   = item.substring(quote2 + 2, item.length()).trim();
        }

        String separator = sep_.getText();
        String result = "";
        for (int loop = 0; loop < max; ++loop) {
            result += "---- Cut here and paste into \"" +
                titles[loop] + "\" ----" + newline_;
            result += generateHTML(loop, titles, urls, selOpen, selClose,
                                   otherOpen, otherClose, separator);
            result += newline_ + newline_;
        }
        
        return result;
    }

    public static String diff(String url1, String url2) {
        String result = "";
        
        StringTokenizer tokens1 = new StringTokenizer(url1, DIRS);
        StringTokenizer tokens2 = new StringTokenizer(url2, DIRS);

        String last1 = "", last2 = "";

        /* find matching parts */
        while (tokens1.hasMoreTokens() && tokens2.hasMoreTokens()) {
            last1 = tokens1.nextToken().trim();
            last2 = tokens2.nextToken().trim();
            if (last1.equals("..") || last2.equals(".."))
                throw new IllegalArgumentException(
                    "URLs cannot contain \"..\"!");
            
            if (!last1.equals(last2))
                break;

            last1 = null;
            last2 = null;
        }

        /* step out of stray directories */
        while (tokens1.hasMoreTokens()) {
            last1 = tokens1.nextToken().trim();
            if (last1.equals(".."))
                throw new IllegalArgumentException(
                    "URLs cannot contain \"..\"!");            
            if (!last1.equals("."))
                result += "../";
        }

        if (DIRS.indexOf(url1.charAt(url1.length() - 1)) != -1)
            result += "../";
        


        /* step into leftover b directories */
        if (last2 != null && !last2.equals(".")) {
            result += last2;
            if (tokens2.hasMoreTokens())
                result += "/";
        }
        
        while (tokens2.hasMoreTokens()) {
            last2 = tokens2.nextToken().trim();
            if (last2.equals(".."))
                throw new IllegalArgumentException(
                    "URLs cannot contain \"..\"!");                        
            if (!last2.equals(".")) {
                result += last2;
                if (tokens2.hasMoreTokens())
                    result += "/";
            }
        }

        if (DIRS.indexOf(url2.charAt(url2.length() - 1)) != -1)
            result += "/";

        return result;
    }
    
    public String generateHTML(int highlight, String titles[], String urls[],
                               String selOpen, String selClose,
                               String otherOpen, String otherClose,
                               String separator) {
        
        String result = "<CENTER>" + newline_ + "   ";

        if (highlight != 0)
            result += otherOpen;

        int max = titles.length - 1;
        for (int loop = 0; loop <= max; ++loop) {
            if (loop == highlight) {
                if (loop != 0)
                    result += otherClose;
                
                result += selOpen;
                result += titles[loop];
                result += selClose;
                
                if (loop != max)
                    result += otherOpen;
            }
            else {
                result += ("<A HREF=\"" +
                           diff(urls[highlight], urls[loop]) +
                           "\">" + titles[loop] + "</A>");
            }

            if (loop != max) {
                if (loop == lineBreak_)
                    result += "<BR>" + newline_ + "   ";
                else
                    result += separator + newline_ + "   ";
            }
        }

        if (highlight != max)
            result += otherClose;

        result += "<P>" + newline_ + "</CENTER>";
        
        return result;
    }
    
    public static void main (String args[]) {
        Frame f = new Frame("NavBar");
        Applet a = new NavApplet();

        f.resize(10, 10);
        f.show();
        f.add(a);

        a.init();
        a.move(f.insets().left, f.insets().top);

        f.resize(a.size().width, a.size().height);
    }
}
