/*
 * 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.imagej;

import icy.gui.util.LookAndFeelUtil;
import icy.gui.util.LookAndFeelUtil.WeakSkinChangeListener;
import icy.system.IcyExceptionHandler;
import icy.system.SystemUtil;
import icy.util.ColorUtil;
import icy.util.ReflectionUtil;
import ij.IJ;
import ij.gui.Toolbar;
import ij.plugin.MacroInstaller;

import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.MenuComponent;
import java.awt.PopupMenu;
import java.lang.reflect.Field;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;

import org.pushingpixels.substance.api.skin.SkinChangeListener;

/**
 * ImageJ ToolBar Wrapper class.
 * 
 * @author Stephane
 */
public class ToolbarWrapper extends Toolbar
{
    private class CustomToolBar extends JToolBar
    {
        /**
         * 
         */
        private static final long serialVersionUID = -3278693015639517146L;

        /**
         * @param orientation
         */
        public CustomToolBar(int orientation)
        {
            super(orientation);

            setBorder(BorderFactory.createEmptyBorder());
            setFloatable(false);
        }

        @Override
        protected void paintComponent(Graphics g)
        {
            ToolbarWrapper.this.paint(g);
            
            // try
            // {
            // if (drawButtonsMethod != null)
            // drawButtonsMethod.invoke(ToolbarWrapper.this, g);
            // }
            // catch (Exception e)
            // {
            // IcyExceptionHandler.showErrorMessage(e, false);
            // System.err.println("Cannot redraw toolbar buttons from ImageJ.");
            // }
        }

        @Override
        public void removeNotify()
        {
            try
            {
                // TODO: remove this temporary hack when the "window dispose" bug will be fixed
                // on the OpenJDK / Sun JVM
                if (SystemUtil.isUnix())
                {
                    @SuppressWarnings("rawtypes")
                    Vector pp = (Vector) ReflectionUtil.getFieldObject(this, "popups", true);
                    pp.clear();
                }
            }
            catch (Exception e)
            {
                IcyExceptionHandler.showErrorMessage(e, false);
                System.err.println("Cannot remove toolbar buttons from ImageJ.");
            }

            super.removeNotify();
        }
    }

    /**
     * 
     */
    private static final long serialVersionUID = 6546185720732862969L;

    final CustomToolBar swingComponent;

    private final SkinChangeListener skinChangeListener;

    /**
     * leaked methods and fields
     */
    // Method drawButtonsMethod;
    Field grayField;
    Field brighterField;
    Field darkerField;
    Field evenDarkerField;
    Field toolColorField;

    // private Color gray = ImageJ.backgroundColor;
    // private Color brighter = gray.brighter();
    // private Color darker = new Color(175, 175, 175);
    // private Color evenDarker = new Color(110, 110, 110);

    public ToolbarWrapper(ImageJWrapper ijw)
    {
        super();

        swingComponent = new CustomToolBar(SwingConstants.HORIZONTAL);

        swingComponent.setMinimumSize(getMinimumSize());
        swingComponent.setPreferredSize(getPreferredSize());
        swingComponent.addKeyListener(ijw);
        swingComponent.addMouseListener(this);
        swingComponent.addMouseMotionListener(this);

        try
        {
            @SuppressWarnings("rawtypes")
            final Vector popups = (Vector) ((Vector) ReflectionUtil.getFieldObject(this, "popups", true)).clone();

            // transfer all popup from original toolbar to the swing toolbar
            for (Object obj : popups)
            {
                final PopupMenu popup = (PopupMenu) obj;

                super.remove(popup);
                swingComponent.add(popup);
            }
            
            // get access to private methods
            // drawButtonsMethod = ReflectionUtil.getMethod(this.getClass(), "drawButtons", true,
            // Graphics.class);
            
            // get access to private fields
            grayField = ReflectionUtil.getField(this.getClass(), "gray", true);
            brighterField = ReflectionUtil.getField(this.getClass(), "brighter", true);
            darkerField = ReflectionUtil.getField(this.getClass(), "darker", true);
            evenDarkerField = ReflectionUtil.getField(this.getClass(), "evenDarker", true);
            toolColorField = ReflectionUtil.getField(this.getClass(), "toolColor", true);
        }
        catch (Exception e)
        {
            IcyExceptionHandler.showErrorMessage(e, false);
            System.err.println("Cannot restore toolbar buttons from ImageJ.");
        }

        skinChangeListener = new SkinChangeListener()
        {
            @Override
            public void skinChanged()
            {
                Color bgCol = LookAndFeelUtil.getBackground(swingComponent);
                Color brighterCol;
                Color darkerCol;
                Color evenDarkerCol;

                if (ColorUtil.getLuminance(bgCol) < 64)
                    bgCol = ColorUtil.mix(bgCol, Color.gray);

                brighterCol = ColorUtil.mix(bgCol, Color.white);
                darkerCol = ColorUtil.mix(bgCol, Color.black);
                evenDarkerCol = ColorUtil.mix(darkerCol, Color.black);

                if (ColorUtil.getLuminance(bgCol) < 128)
                    brighterCol = ColorUtil.mix(bgCol, brighterCol);
                else
                {
                    darkerCol = ColorUtil.mix(bgCol, darkerCol);
                    evenDarkerCol = ColorUtil.mix(darkerCol, evenDarkerCol);
                }

                try
                {
                    if (grayField != null)
                        grayField.set(ToolbarWrapper.this, bgCol);
                    if (brighterField != null)
                        brighterField.set(ToolbarWrapper.this, brighterCol);
                    if (darkerField != null)
                        darkerField.set(ToolbarWrapper.this, darkerCol);
                    if (evenDarkerField != null)
                        evenDarkerField.set(ToolbarWrapper.this, evenDarkerCol);
                    if (toolColorField != null)
                        toolColorField.set(ToolbarWrapper.this, LookAndFeelUtil.getForeground(swingComponent));

                    swingComponent.repaint();
                }
                catch (Exception e)
                {
                    IcyExceptionHandler.showErrorMessage(e, false);
                    System.err.println("Cannot hack background color of ImageJ toolbar.");
                }
            }
        };

        // install default tools and macros
        new MacroInstaller().run(IJ.getDirectory("macros") + "StartupMacros.txt");

        LookAndFeelUtil.addSkinChangeListener(new WeakSkinChangeListener(skinChangeListener));
    }
    
    @Override
    public Container getParent()
    {
        return swingComponent.getParent();
    }

    /**
     * @return the swingComponent
     */
    public JToolBar getSwingComponent()
    {
        return swingComponent;
    }

    @Override
    public synchronized void add(PopupMenu popup)
    {
        if (swingComponent == null)
            super.add(popup);
        else
        {
            swingComponent.add(popup);
            swingComponent.repaint();
        }
    }

    @Override
    public synchronized void remove(MenuComponent popup)
    {
        if (swingComponent == null)
            super.remove(popup);
        else
        {
            swingComponent.remove(popup);
            swingComponent.repaint();
        }
    }

    // @Override
    // public void itemStateChanged(ItemEvent e)
    // {
    // super.itemStateChanged(e);
    //
    // swingComponent.repaint();
    // }
    //
    // @Override
    // public void paint(Graphics g)
    // {
    // swingComponent.repaint();
    // }

    @Override
    public Graphics getGraphics()
    {
        return swingComponent.getGraphics();
    }

    // /**
    // * Rebuild swing toolbar component
    // */
    // protected void rebuild()
    // {
    // swingComponent.removeAll();
    // swingComponent.validate();
    // }
}