/**
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 *
 * Copyright (C)
 * <a href="http://www.inab.org">Spanish National Institute of Bioinformatics (INB)</a>
 * <a href="http://www.bsc.es">Barcelona Supercomputing Center (BSC)</a>
 * <a href="http://inb.bsc.es">Computational Node 6</a>
 */

package org.inb.biomoby.client.gui.swing;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;

/**
 * @author Dmitry Repchevsky
 */

public class CollapsablePanel<T extends JComponent> extends JPanel implements ActionListener, MouseListener
{
    private final static byte[] COLLAPSE = {
      (byte)0x47, (byte)0x49, (byte)0x46, (byte)0x38, (byte)0x39, (byte)0x61, (byte)0x09, (byte)0x00, (byte)0x09, (byte)0x00, (byte)0xE3, (byte)0x0C, (byte)0x00, (byte)0x04, (byte)0x02, (byte)0x04,
      (byte)0xAC, (byte)0xAA, (byte)0x9C, (byte)0xD4, (byte)0xD2, (byte)0xD4, (byte)0xE4, (byte)0xE6, (byte)0xE4, (byte)0xF4, (byte)0xF6, (byte)0xF4, (byte)0xDC, (byte)0xDE, (byte)0xDC, (byte)0xEC,
      (byte)0xEE, (byte)0xEC, (byte)0xFC, (byte)0xFE, (byte)0xFC, (byte)0x8C, (byte)0x8A, (byte)0xD4, (byte)0xC4, (byte)0xC6, (byte)0xEC, (byte)0xFC, (byte)0xFA, (byte)0xFC, (byte)0xF4, (byte)0xF2,
      (byte)0xF4, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x21, (byte)0xF9, (byte)0x04,
      (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0F, (byte)0x00, (byte)0x2C, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x09, (byte)0x00, (byte)0x09, (byte)0x00, (byte)0x00, (byte)0x04,
      (byte)0x25, (byte)0x30, (byte)0xA1, (byte)0x49, (byte)0x91, (byte)0x7C, (byte)0x38, (byte)0xBF, (byte)0xF9, (byte)0x94, (byte)0x57, (byte)0xC4, (byte)0x86, (byte)0x3C, (byte)0xC6, (byte)0x62,
      (byte)0x94, (byte)0xE2, (byte)0x03, (byte)0xAC, (byte)0xAB, (byte)0xB8, (byte)0x14, (byte)0x30, (byte)0xBC, (byte)0x4C, (byte)0x8B, (byte)0x60, (byte)0xDB, (byte)0xC6, (byte)0x34, (byte)0xEC,
      (byte)0xFC, (byte)0x60, (byte)0x55, (byte)0x94, (byte)0x44, (byte)0x04, (byte)0x00, (byte)0x3B
    };

    private final static byte[] EXPAND = {
      (byte)0x47, (byte)0x49, (byte)0x46, (byte)0x38, (byte)0x39, (byte)0x61, (byte)0x09, (byte)0x00, (byte)0x09, (byte)0x00, (byte)0xE3, (byte)0x0C, (byte)0x00, (byte)0x04, (byte)0x02, (byte)0x04,
      (byte)0xAC, (byte)0xAA, (byte)0x9C, (byte)0xD4, (byte)0xD2, (byte)0xD4, (byte)0xE4, (byte)0xE6, (byte)0xE4, (byte)0xF4, (byte)0xF6, (byte)0xF4, (byte)0xDC, (byte)0xDE, (byte)0xDC, (byte)0xEC,
      (byte)0xEE, (byte)0xEC, (byte)0xFC, (byte)0xFE, (byte)0xFC, (byte)0x8C, (byte)0x8A, (byte)0xD4, (byte)0xC4, (byte)0xC6, (byte)0xEC, (byte)0xFC, (byte)0xFA, (byte)0xFC, (byte)0xF4, (byte)0xF2,
      (byte)0xF4, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x21, (byte)0xF9, (byte)0x04,
      (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0F, (byte)0x00, (byte)0x2C, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x09, (byte)0x00, (byte)0x09, (byte)0x00, (byte)0x00, (byte)0x04,
      (byte)0x29, (byte)0x30, (byte)0xA1, (byte)0x49, (byte)0x91, (byte)0x7C, (byte)0x38, (byte)0xBF, (byte)0xF9, (byte)0x14, (byte)0x01, (byte)0x84, (byte)0xB2, (byte)0x21, (byte)0xCF, (byte)0x62,
      (byte)0x00, (byte)0xC6, (byte)0x32, (byte)0x3E, (byte)0x40, (byte)0xDB, (byte)0x8E, (byte)0x4B, (byte)0x51, (byte)0x00, (byte)0xF2, (byte)0x32, (byte)0x2D, (byte)0x82, (byte)0x00, (byte)0xE4,
      (byte)0xC6, (byte)0x34, (byte)0xFC, (byte)0xC0, (byte)0x81, (byte)0xA5, (byte)0x42, (byte)0x49, (byte)0x44, (byte)0x00, (byte)0x00, (byte)0x3B
    };

    private Icon collapse;
    private Icon expand;
    
    private JButton button;
    private JComponent header;
    
    protected T panel;
    
    public CollapsablePanel(T panel)
    {
        this(panel, null, true);
    }
    
    public CollapsablePanel(T panel, String title, boolean expanded)
    {
        super(new GridBagLayout());

        this.panel = panel;
        
        try
        {
            collapse = new ImageIcon(ImageIO.read(new ByteArrayInputStream(COLLAPSE)));
            expand = new ImageIcon(ImageIO.read(new ByteArrayInputStream(EXPAND)));
        }
        catch(IOException ex)
        {
            ex.printStackTrace();
        }
        
        GridBagConstraints c = new GridBagConstraints();
        
        button = new JButton(expanded ? collapse : expand);
        button.setOpaque(false);
        button.setContentAreaFilled(false);
        button.setFocusPainted(false);
        button.setBorderPainted(false);
        button.addActionListener(this);

        c.gridx = 0;
        c.gridy = 0;
        add(button, c);
        
        c.gridx = 1;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        
        header = title != null ? new JLabel(title) : new JSeparator();
        header.addMouseListener(this);
        add(header, c);
        
        c.gridx = 0;
        c.gridy = 1;
        c.gridwidth = 2;
        c.weighty = 1;
        c.fill = GridBagConstraints.BOTH;

        panel.setVisible(expanded);
        add(panel, c);
    }

    @Override
    public Dimension getMaximumSize()
    {
        Dimension prf = this.getPreferredSize();
        Dimension max = super.getMaximumSize();

        return new Dimension(max.width, prf.height);
    }

    private void doClick()
    {
        boolean v = panel.isVisible();
        panel.setVisible(!v);
        
        button.setIcon(v ? expand : collapse);

        //doLayout();
        //invalidate();
        revalidate();
    }
    
    @Override
    public void actionPerformed(ActionEvent e)
    {
        doClick();
    }
    
    @Override public void mouseClicked(MouseEvent e)
    {
        doClick();
    }
    
    @Override public void mousePressed(MouseEvent e) {}
    @Override public void mouseReleased(MouseEvent e) {}

    @Override
    public void mouseEntered(MouseEvent e)
    {
        header.setForeground(Color.BLUE);
    }

    @Override
    public void mouseExited(MouseEvent e)
    {
        header.setForeground(Color.BLACK);
    }
}
