/*
 * $Id$
 *
 * Copyright 1996-2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 */
package com.sun.javatest.agent;

import java.awt.AWTEventMulticaster;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.ItemSelectable;
import java.awt.Panel;
import java.awt.Polygon;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Vector;

/**
 * Folder is a panel with a layout based on CardLayout that also provides GUI controls
 * to allow a user-selected component to be displayed.
 */

class Folder extends Panel implements ItemSelectable
{
    private class Entry
    {
        Entry(Component comp, String name, Color color, boolean visibleTab) {
            this.comp = comp;
            this.name = name;
            this.color = color;
            this.visibleTab = visibleTab;
        }

        Component comp;
        String name;
        Color color;
        boolean visibleTab;
    }

    private class Layout extends CardLayout
    {
        public Dimension minimumLayoutSize(Container parent) {
            Dimension size = super.minimumLayoutSize(parent);
            int width = Math.max(size.width, ((Folder)parent).getMinimumWidth());
            return new Dimension(width, size.height);
        }

        public Dimension preferredLayoutSize(Container parent) {
            Dimension size = super.preferredLayoutSize(parent);
            int width = Math.max(size.width, ((Folder)parent).getMinimumWidth());
            return new Dimension(width, size.height);
        }
    }

    public Folder() {
        this(0, 0);
    }

    public Folder(int hgap, int vgap) {
        this(hgap, vgap, 10, 5, 5);
    }

    Folder(int hgap, int vgap, int border, int slant, int tabSpace) {
        this.hgap = hgap;
        this.vgap = vgap;
        this.border = border;
        this.slant = slant;
        this.tabSpace = tabSpace;
        this.tabpad = 10;
        //setLayout(new Layout());
        setLayout(new CardLayout());

        MouseListener mouseListener = new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                Folder.this.mousePressed(e.getX(), e.getY());
            }
        };

        addMouseListener(mouseListener);
    }

    public Insets getInsets() {
        FontMetrics fm = getFontMetrics(getFont());
        int left_right = border + hgap;
        int top = border + (fm == null ? 0 : fm.getHeight()) + tabpad + vgap;
        int bottom = border + vgap;
        return new Insets(top, left_right, bottom, left_right);
    }

    public Component add(String name, Component comp) {
        entries.addElement(new Entry(comp, name, null, true));
        return super.add(name, comp);
    }

    public Component add(String name, Component comp, Color color) {
        entries.addElement(new Entry(comp, name, color, true));
        return super.add(name, comp);
    }

    public Component add(String name, Component comp, Color color, boolean visibleTab) {
        entries.addElement(new Entry(comp, name, color, visibleTab));
        return super.add(name, comp);
    }


    public void showTab(String name) {
        showTab(name, true);
    }

    public void hideTab(String name) {
        showTab(name, false);
    }

    public void showTab(String name, boolean visible) {
        for (int i = 0; i < entries.size(); i++) {
            Entry e = (Entry)entries.elementAt(i);
            if (e.name.equals(name)) {
                if (e.visibleTab != visible) {
                    e.visibleTab = visible;
                    repaint();
                }
                return;
            }
        }
    }

    public String getNextVisibleTab() {
        int currentIndex = Math.max(0, getCurrentIndex());
        for (int i = currentIndex + 1; i < entries.size(); i++) {
            Entry e = (Entry)entries.elementAt(i);
            if (e.visibleTab)
                return e.name;
        }
        return null;
    }

    public String getPrevVisibleTab() {
        int currentIndex = getCurrentIndex();
        for (int i = currentIndex - 1; i >= 0; i--) {
            Entry e = (Entry)entries.elementAt(i);
            if (e.visibleTab)
                return e.name;
        }
        return null;
    }

    public Component current() {
        for (int i = 0; i < entries.size(); i++) {
            Entry e = (Entry)entries.elementAt(i);
            if (e.comp.isVisible())
                return e.comp;
        }
        return null;
    }

    public void show(Component comp) {
        for (int i = 0; i < entries.size(); i++) {
            Entry e = (Entry)entries.elementAt(i);
            if (e.comp == comp) {
                show(e);
                return;
            }
        }
    }

    public void show(String name) {
        for (int i = 0; i < entries.size(); i++) {
            Entry e = (Entry)entries.elementAt(i);
            if (e.name.equals(name)) {
                show(e);
                return;
            }
        }
    }

    public void paint(Graphics g) {
        Dimension dims = getSize();

        FontMetrics fm = g.getFontMetrics();
        int tabHeight = fm.getHeight() + tabpad;
        Entry selected = null;
        for (int i = 0; i < entries.size(); i++) {
            Entry e = (Entry)entries.elementAt(i);
            if (e.comp.isVisible()) {
                selected = e;
                break;
            }
        }
        g.setColor(selected.color != null ? selected.color : getBackground());
        g.fillRoundRect(hgap, tabHeight + vgap,
            dims.width - 2*hgap - 1, dims.height - tabHeight - 2*vgap - 1,
            border, border);
        g.setColor(getForeground());
        g.drawRoundRect(hgap, tabHeight + vgap,
              dims.width - 2*hgap - 1, dims.height - tabHeight - 2*vgap - 1,
              border, border);
        int x = border + hgap;
        int baseLine = tabHeight + vgap;
        for (int i = 0; i < entries.size(); i++) {
            Entry e = (Entry)entries.elementAt(i);
            int tabH = (e.visibleTab || e.comp.isVisible() ? tabHeight : tabHeight / 3);
            int w = fm.stringWidth(e.name);
            Polygon tab = new Polygon();
            tab.addPoint(x, baseLine);
            tab.addPoint(x + slant, baseLine - tabH);
            tab.addPoint(x + slant + w, baseLine - tabH);
            tab.addPoint(x + slant + w + slant, baseLine);
            if (e.color != null) {
                g.setColor(e.color);
                g.fillPolygon(tab);
            }
            g.setColor(getForeground());
            g.drawLine(tab.xpoints[0], tab.ypoints[0], tab.xpoints[1], tab.ypoints[1]);
            g.drawLine(tab.xpoints[1], tab.ypoints[1], tab.xpoints[2], tab.ypoints[2]);
            g.drawLine(tab.xpoints[2], tab.ypoints[2], tab.xpoints[3], tab.ypoints[3]);
            if (e.visibleTab || e.comp.isVisible())
                g.drawString(e.name, x + slant, baseLine - tabpad/2 - fm.getDescent());
            if (e.comp.isVisible()) {
                g.setColor(e.color != null ? e.color : getBackground());
                g.drawLine(tab.xpoints[0], tab.ypoints[0], tab.xpoints[3], tab.ypoints[3]);
            }
            x = tab.xpoints[3] + tabSpace;
        }

        super.paint(g);
    }

    public void addItemListener(ItemListener l) {
        itemListener = AWTEventMulticaster.add(itemListener, l);
    }

    public void removeItemListener(ItemListener l) {
        itemListener = AWTEventMulticaster.remove(itemListener, l);
    }

    public Object[] getSelectedObjects() {
        Entry ce = getCurrentEntry();
        if (ce == null)
            return null;
        else
            return new Object[] { ce.comp };
    }

    int getMinimumWidth() {
        FontMetrics fm = getFontMetrics(getFont());
        int w = border + 2 * hgap + tabSpace;
        for (int i = 0; i < entries.size(); i++) {
          Entry e = (Entry)entries.elementAt(i);
          w += slant + (fm == null ? 0 : fm.stringWidth(e.name)) + slant + tabSpace;
        }
        return w;
    }

    private void show(Entry e) {
        Entry prevEntry = getCurrentEntry();
        Component prevComp = (prevEntry == null ? null : prevEntry.comp);

        ((CardLayout)getLayout()).show(this, e.name);
        repaint(); // needed to repaint the tab area

        if (itemListener != null) {
            ItemEvent ev1 =
                new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
                              prevComp, ItemEvent.DESELECTED);
            ItemEvent ev2 =
                new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
                              e.comp, ItemEvent.SELECTED);
            itemListener.itemStateChanged(ev1);
            itemListener.itemStateChanged(ev2);
        }
    }

    private int getCurrentIndex() {
        for (int i = 0; i < entries.size(); i++) {
            Entry e = (Entry)entries.elementAt(i);
            if (e.comp.isVisible())
                return i;
        }
        return -1;
    }

    private Entry getCurrentEntry() {
        int i = getCurrentIndex();
        return (i == -1 ? null : (Entry)(entries.elementAt(i)) );
    }

    void mousePressed(int mouseX, int mouseY) {
        FontMetrics fm = getFontMetrics(getFont());
        if (vgap < mouseY  &&  mouseY < border + fm.getHeight() + vgap) {
            int x = border + hgap;
            for (int i = 0; i < entries.size(); i++) {
                Entry e = (Entry)entries.elementAt(i);
                int w = fm.stringWidth(e.name);
                x += slant + w + slant + tabSpace;
                if (mouseX < x) {
                    show(e);
                    break;
                }
            }
        }
    }


    private ItemListener itemListener;
    private Vector entries = new Vector();
    private int border;
    private int slant;
    private int tabSpace;
    private int hgap;
    private int vgap;
    private int tabpad;
}
