/*
 * Copyright 2010-2015 Institut Pasteur.
 * 
 * This file is part of Icy.
 * 
 * Icy is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Icy 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 for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
 */
package icy.gui.component;

import icy.gui.component.button.IcyButton;
import icy.resource.ResourceUtil;
import icy.resource.icon.IcyIcon;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventListener;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingConstants;

/**
 * JTabbedPane with close button (configurable) in tab.
 * 
 * @author Stephane
 */
public class CloseableTabbedPane extends JTabbedPane
{
    /**
     * 
     */
    private static final long serialVersionUID = 2105647353561738725L;

    public static interface CloseableTabbedPaneListener extends EventListener
    {
        /**
         * Called when the tab close button has been clicked.<br>
         * This callback is used to do special actions before tab close.<br>
         * You can prevent the close operation by returning false.
         * 
         * @return true if the tab can be closed, false otherwise.
         */
        public boolean tabClosing(int index, String title);

        /**
         * Called when the tab has been closed.
         */
        public void tabClosed(int index, String title);
    }

    private class CloseableTabComponent extends JPanel
    {
        /**
         * 
         */
        private static final long serialVersionUID = 6828288788693627610L;

        final private IcyButton closeButton;
        final private JLabel label;
        final private Component sep;

        public CloseableTabComponent(String title, Icon icon)
        {
            super();

            setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
            setBorder(BorderFactory.createEmptyBorder());
            setOpaque(false);

            label = new JLabel(title, icon, SwingConstants.CENTER);
            label.setOpaque(false);

            sep = Box.createHorizontalStrut(6);

            closeButton = new IcyButton(new IcyIcon(ResourceUtil.ICON_DELETE, 12));
            closeButton.setFlat(true);
            closeButton.setContentAreaFilled(false);
            closeButton.setToolTipText("close");

            closeButton.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent actionevent)
                {
                    final int index = indexOfTabComponent(CloseableTabComponent.this);

                    if (index != -1)
                    {
                        if (CloseableTabbedPane.this.fireTabClosing(index, getTitle()))
                        {
                            CloseableTabbedPane.this.removeTabAt(index);
                            CloseableTabbedPane.this.fireTabClosed(index, getTitle());
                        }
                    }
                }
            });

            add(label);
            add(sep);
            add(closeButton);

            validate();
        }

        public boolean isClosable()
        {
            return closeButton.isVisible();
        }

        public void setClosable(boolean value)
        {
            sep.setVisible(value);
            closeButton.setVisible(value);
        }

        public String getTitle()
        {
            return label.getText();
        }

        public void setTitle(String title)
        {
            label.setText(title);
        }

        public void setIcon(Icon icon)
        {
            label.setIcon(icon);
        }

        public void setDisabledIcon(Icon disabledIcon)
        {
            label.setDisabledIcon(disabledIcon);
        }

        public void setBackgroundAll(Color background)
        {
            label.setBackground(background);
            closeButton.setBackground(background);
        }

        public void setForegroundAll(Color foreground)
        {
            label.setForeground(foreground);
            closeButton.setForeground(foreground);
        }
    }

    /**
     * {@link JTabbedPane}
     */
    public CloseableTabbedPane()
    {
        super();
    }

    /**
     * {@link JTabbedPane}
     */
    public CloseableTabbedPane(int tabPlacement)
    {
        super(tabPlacement);
    }

    /**
     * {@link JTabbedPane}
     */
    public CloseableTabbedPane(int tabPlacement, int tabLayoutPolicy)
    {
        super(tabPlacement, tabLayoutPolicy);
    }

    /**
     * Returns the 'closable' state of tab component at <code>index</code>.
     * 
     * @param index
     *        the tab index where the check state is queried
     * @return true if tab component at <code>index</code> can be closed (close button visible).<br>
     *         Returns false otherwise
     * @exception IndexOutOfBoundsException
     *            if index is out of range (index < 0 || index >= tab count)
     * @see #setTabClosable(int, boolean)
     */
    public boolean isTabClosable(int index)
    {
        return ((CloseableTabComponent) getTabComponentAt(index)).isClosable();
    }

    /**
     * Set the 'closable' state of tab component at <code>index</code>.
     * 
     * @param index
     *        the tab index we want to set the 'closable' state
     * @param value
     *        true if the tab should be 'closable' (close button visible), false otherwise.
     * @exception IndexOutOfBoundsException
     *            if index is out of range (index < 0 || index >= tab count)
     * @see #isTabClosable(int)
     */
    public void setTabClosable(int index, boolean value)
    {
        ((CloseableTabComponent) getTabComponentAt(index)).setClosable(value);
    }

    @Override
    public void setIconAt(int index, Icon icon)
    {
        super.setIconAt(index, icon);

        final CloseableTabComponent comp = (CloseableTabComponent) getTabComponentAt(index);

        if (comp != null)
            comp.setIcon(icon);
    }

    @Override
    public void setDisabledIconAt(int index, Icon disabledIcon)
    {
        super.setDisabledIconAt(index, disabledIcon);

        final CloseableTabComponent comp = (CloseableTabComponent) getTabComponentAt(index);

        if (comp != null)
            comp.setDisabledIcon(disabledIcon);
    }

    @Override
    public void setBackgroundAt(int index, Color background)
    {
        super.setBackgroundAt(index, background);

        final CloseableTabComponent comp = (CloseableTabComponent) getTabComponentAt(index);

        if (comp != null)
            comp.setBackgroundAll(background);
    }

    @Override
    public void setForegroundAt(int index, Color foreground)
    {
        super.setForegroundAt(index, foreground);

        final CloseableTabComponent comp = (CloseableTabComponent) getTabComponentAt(index);

        if (comp != null)
            comp.setForegroundAll(foreground);
    }

    @Override
    public void setTitleAt(int index, String title)
    {
        super.setTitleAt(index, title);

        final CloseableTabComponent comp = (CloseableTabComponent) getTabComponentAt(index);

        if (comp != null)
            comp.setTitle(title);
    }

    @Override
    public void insertTab(String title, Icon icon, Component component, String tip, int index)
    {
        super.insertTab(title, icon, component, tip, index);

        setTabComponentAt(index, new CloseableTabComponent(title, icon));
    }

    protected void fireTabClosed(int index, String text)
    {
        for (CloseableTabbedPaneListener l : listenerList.getListeners(CloseableTabbedPaneListener.class))
            l.tabClosed(index, text);

    }

    protected boolean fireTabClosing(int index, String text)
    {
        for (CloseableTabbedPaneListener l : listenerList.getListeners(CloseableTabbedPaneListener.class))
            if (!l.tabClosing(index, text))
                return false;

        return true;
    }

    public void addCloseableTabbedPaneListener(CloseableTabbedPaneListener l)
    {
        listenerList.add(CloseableTabbedPaneListener.class, l);
    }

    public void removeCloseableTabbedPaneListener(CloseableTabbedPaneListener l)
    {
        listenerList.remove(CloseableTabbedPaneListener.class, l);
    }
}