/*
 *
 *  Copyright (C) 1999, Institute for MicroTherapy
 *
 *  This software and supporting documentation were developed by
 *
 *    University of Witten/Herdecke
 *    Department of Radiology and MicroTherapy
 *    Institute for MicroTherapy
 *    Medical computer science
 *    
 *    Universitaetsstrasse 142
 *    44799 Bochum, Germany
 *    
 *    http://www.microtherapy.de/go/cs
 *    mailto:computer.science@microtherapy.de
 *
 *  THIS SOFTWARE IS MADE AVAILABLE,  AS IS,  AND THE INSTITUTE MAKES  NO 
 *  WARRANTY REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY
 *  OR FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES 
 *  OR ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY 
 *  AND PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
 *
 *  Author :      $Author: kleber $
 *  Last update : $Date: 2001/06/06 10:32:30 $
 *  Revision :    $Revision: 1.1.1.1 $
 *  State:        $State: Exp $
*/

package jToolkit.gui;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Vector;

import main.MainContext;

/**
 * TabPanel is a container for a set of tabbed cards, lying atop each other,
 * but with the labelled tabs exposed at the top.  That is, the classic Tab 
 * Folder. Each card is an awt.component of whatever design you wish.  The 
 * topmost card can be selected programmatically (Using first(), last(), 
 * next(), previous(), or show(name)), or by clicking on the tab with the mouse.
 * <P> 
 * Components should be added using add(name,component)); the name is used
 * to label the tab.  If you set the layout manager, it should be a subclass 
 * of CardLayout.
 * You probably want to setBackground() to a color contrasting that of
 * the parent and the components.
 *
 * @author Andreas Schroeter
 * @since 30.03.
*/
public class TabPanel extends Panel implements MouseListener
{
    private int dummy = 0;
    
    public TabPanel()
    {
        margin = 3;
        names = new Vector(10, 10);
        tabN = 12;
        tabLeft = new int[2][tabN];
        tabRight = new int[2][tabN];
        setLayout(new CardLayout());
        setTabFont(new Font("Helvetica", 1, 12));
        
        
        addMouseListener(this);
    }

    int findComponent(Component c)
    {
        for(int i = 0; i < nCards; i++)
            if(getComponent(i) == c)
                return i;

        return -1;
    }

    public Component add(String name, Component component)
    {
        name = name.intern();
        super.add(name, component);

        if(!names.contains(name))
        {
            names.addElement(name);
            nCards++;
        
            if(isShowing())
            {
                computeTabs();
                repaint();
            }
        }
        return component;
    }

    public void remove(Component component)
    {
        int i = findComponent(component);
        
        super.remove(component);
        names.removeElementAt(i);
        nCards--;
        
        if(i < selected) setSelected(selected - 1, true);
        else if(i == selected && nCards > 0) setSelected(selected % nCards, true);
        
        if(isShowing())
        {
            computeTabs();
            repaint();
        }
    }

    public void remove(String name)
    {
        int i = names.indexOf(name.intern());
        
        if(i != -1) remove(getComponent(i));
    }

    public void removeAll()
    {
        super.removeAll();
        names.removeAllElements();
        repaint();
    }

    void setSelected(int i, boolean force)
    {
        if(force || i != selected && i >= 0 && i < nCards)
        {
            if(nCards > 0) selected = i % nCards;
            
            ((CardLayout)getLayout()).show(this, (String)names.elementAt(i));
            
            repaint();
            Component component = getComponent(i);
        }
    }

    public void first()
    {
        setSelected(0, false);
    }

    public void last()
    {
        setSelected(nCards - 1, false);
    }

    public void next()
    {
        setSelected((selected + 1) % nCards, false);
    }

    public void previous()
    {
        setSelected(((selected - 1) + nCards) % nCards, false);
    }

    public void show(String name)
    {
        setSelected(names.indexOf(name.intern()), false);
    }

    public void show(Component component)
    {
        setSelected(findComponent(component), false);
    }

    int cardAt(int x, int y)
    {
        if(y <= tabH)
        {
            x += offset;
            
            for(int i = 0; i < nCards; i++)
                if(pos[i] <= x && x < pos[i + 1]) return i;
        }
        return -1;
    }

    public String documentCard(String name)
    {
        return "Select Tab Card " + name;
    }

    public void mouseClicked(MouseEvent e)
    {
       int i = cardAt(e.getX(), e.getY());
            
       if(i != -1) setSelected(i, false);
    }

    public void mouseEntered(MouseEvent mouseevent)
    {
        // empty
    }

    public void mouseExited(MouseEvent mouseevent)
    {
        // empty
    }

    public void mousePressed(MouseEvent mouseevent)
    {
        // empty
    }

    public void mouseReleased(MouseEvent e)
    {
        int i = cardAt(e.getX(), e.getY());
            
        if(i != -1) setSelected(i, false);
    }

    public Insets getInsets()
    {
        return new Insets(tabH + margin, margin, margin, margin);
    }

    public void setTabFont(Font font)
    {
        tabFont = font;
        metric = getFontMetrics(font);
        int r = (metric.getHeight() + 1) / 2;
        tabH = 2 * r;
        int nn = (tabN - 2) / 2;
        
        for(int i = 0; i <= nn; i++)
        {
            int c = r - (i*r)/nn;            
            int s = (i*r)/nn;
            
            tabLeft[0][i] = s;
            tabLeft[1][i] = r + c;
            tabLeft[0][i + nn] = tabH - c;
            tabLeft[1][i + nn] = r - s;
        }

        tabLeft[0][2 * nn + 1] = tabH;
        tabLeft[1][2 * nn + 1] = tabH;
        
        for(int i = 0; i < tabN; i++)
        {
            tabRight[0][i] = -tabLeft[0][i];
            tabRight[1][i] = tabLeft[1][i];
        }

    }

    void computeTabs()
    {
        if(pos == null || pos.length <= nCards)
        {
            width = new int[nCards + 1];
            pos = new int[nCards + 1];
        }
        
        int x = tabH / 2;
        
        for(int i = 0; i < nCards; i++)
        {
            pos[i] = x;
            width[i] = tabH + metric.stringWidth((String)names.elementAt(i));
            x += width[i];
        }

        pos[nCards] = x;
    }

    public void doLayout()
    {
        super.doLayout();
        computeTabs();
    }

    void paintTabEdge(Graphics g, int x, int edges[][])
    {
        g.translate(x, 0);
        g.setColor(getBackground());
        g.fillPolygon(edges[0], edges[1], tabN);
        g.setColor(getForeground());
        g.drawPolygon(edges[0], edges[1], tabN - 1);
        g.translate(-x, 0);
    }

    void paintTab(Graphics g, int x, int p)
    {
        int r = tabH / 2;
        int w = width[p];
        paintTabEdge(g, x - r, tabLeft);
        paintTabEdge(g, x + w + r, tabRight);
        g.setColor(getBackground());
        g.fillRect(x + r, 0, w - tabH, tabH);
        g.setColor(getForeground());
        g.drawLine(x + r, 0, (x + w) - r, 0);
        g.setFont(tabFont);
        g.drawString((String)names.elementAt(p), x + r, tabH - metric.getDescent());
    }

    public void paint(Graphics g)
    {
        Dimension sz = getSize();
        int w = sz.width - 1;
        int h = sz.height - 1;
        int r = tabH / 2;
        int s = selected;
        int shadow = 4;
        int nShadows = 3;
        g.setColor(getParent().getBackground());
        g.fillRect(0, 0, w + 1, tabH);
        g.setColor(getForeground());
        
        if(nCards == 0)
        {
            g.drawLine(0, tabH, w, tabH);
        }
        else
        {
            int offmax = pos[s] - r - Math.min(nShadows, s) * shadow;
            int offmin = (pos[s + 1] - w) + r + Math.min(nCards - s, nShadows) * shadow;
            
            if(offset < offmin || offset > offmax)
                offset = Math.min(Math.max(0, (offmin + offmax) / 2), (pos[nCards] + r) - w);
            
            int j = 0;
        
            for(int x = offset + r; j < s && pos[j] <= x; j++) dummy = 1;
            
            if(j > 0)
            {
                int x = 0;
            
                for(int i = Math.max(0, j - nShadows); i < j - 1;)
                {
                    paintTabEdge(g, x, tabLeft);
                    i++;
                    x += shadow;
                }

                paintTab(g, x + r, j - 1);
            }
            
            for(int i = j; i < s; i++) paintTab(g, pos[i] - offset, i);

            j = nCards - 1;
            
            for(int x = (offset + w) - r; j > s && pos[j + 1] >= x; j--) dummy = 2;
            
            if(j < nCards - 1)
            {
                int x = w;
                for(int i = Math.min(nCards - 1, j + nShadows); i > j + 1;)
                {
                    //paintTabEdge(g, x, tabRight);
                    i--;
                    x -= shadow;
                }

                paintTab(g, x - r - width[j + 1], j + 1);
            }
            
            for(int i = j; i > s; i--) paintTab(g, pos[i] - offset, i);

            paintTab(g, pos[s] - offset, s);
            g.drawLine(0, tabH, pos[s] - r - offset, tabH);
            g.clearRect(pos[s] - r - offset, tabH, width[s] + tabH, 1);
            g.drawLine((pos[s + 1] + r) - offset, tabH, w, tabH);
            g.drawLine(w, tabH, w, h);
            g.drawLine(w, h, 0, h);
            g.drawLine(0, h, 0, tabH);
        }
    }
    
    public Font getFont ()
    {
        return tabFont;   
    }
    
    public void setFont (Font f)
    {
        setTabFont (f);
    }

    public int margin;
    Font tabFont;
    FontMetrics metric;
    int nCards;
    Vector names;
    int pos[];
    int width[];
    int selected;
    int offset;
    int tabH;
    int tabN;
    int tabLeft[][];
    int tabRight[][];    
}
/*
 *  CVS Log
 *  $Log: TabPanel.java,v $
 *  Revision 1.1.1.1  2001/06/06 10:32:30  kleber
 *  Init commit for DICOMscope 3.5
 *  Create new CVS
 *
*/
