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

import icy.action.IcyAbstractAction;
import icy.common.MenuCallback;
import icy.gui.util.ComponentUtil;
import icy.gui.util.LookAndFeelUtil;
import icy.resource.ResourceUtil;
import icy.resource.icon.IcyIcon;
import icy.system.SystemUtil;
import icy.system.thread.ThreadUtil;

import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JRootPane;

import org.pushingpixels.substance.internal.utils.SubstanceTitlePane;

/**
 * @author Stephane
 */
public class IcyExternalFrame extends JFrame
{
    /**
      * 
      */
    private static final long serialVersionUID = 9130936218505070807L;

    private class CloseAction extends IcyAbstractAction
    {
        /**
         * 
         */
        private static final long serialVersionUID = 4933605299188863452L;

        public CloseAction()
        {
            super("Close", new IcyIcon(ResourceUtil.ICON_CLOSE, 20), "Close window", KeyEvent.VK_F4, SystemUtil
                    .getMenuCtrlMask());
        }

        @Override
        public boolean doAction(ActionEvent e)
        {
            close();
            return true;
        }
    }

    /**
     * internals
     */
    private SubstanceTitlePane titlePane;
    // private JMenuBar systemMenuBar;
    MenuCallback systemMenuCallback;
    private boolean titleBarVisible;
    private boolean closeItemVisible;
    private boolean initialized = false;

    /**
     * @param title
     * @throws HeadlessException
     */
    public IcyExternalFrame(String title) throws HeadlessException
    {
        super(title);

        getRootPane().addPropertyChangeListener("titlePane", new PropertyChangeListener()
        {
            @Override
            public void propertyChange(PropertyChangeEvent evt)
            {
                // invoke later so the titlePane variable is up to date
                ThreadUtil.invokeLater(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        updateTitlePane();
                    }
                });
            }
        });

        addWindowListener(new WindowAdapter()
        {
            @Override
            public void windowClosed(WindowEvent e)
            {
                // release the system menu callback as it can lead to some memory leak
                // (cycling reference)
                systemMenuCallback = null;
            }
        });
        setIconImages(ResourceUtil.getIcyIconImages());
        setVisible(false);

        systemMenuCallback = null;
        closeItemVisible = true;
        updateTitlePane(LookAndFeelUtil.getTitlePane(this));

        titleBarVisible = true;
        initialized = true;
    }

    /**
     * update internals informations linked to title pane with specified pane
     */
    protected void updateTitlePane(final SubstanceTitlePane pane)
    {
        // update pane save
        if (pane != null)
            titlePane = pane;
        // update menu
        // if (titlePane != null)
        // systemMenuBar = titlePane.getMenuBar();
        // refresh system menu whatever
        updateSystemMenu();
    }

    /**
     * update internals informations linked to title pane
     */
    protected void updateTitlePane()
    {
        if (initialized)
        {
            // title pane can have changed
            updateTitlePane(LookAndFeelUtil.getTitlePane(this));

            if (!titleBarVisible)
                setTitleBarVisible(false);
        }
    }

    /**
     * Refresh system menu
     */
    public void updateSystemMenu()
    {
        if (titlePane != null)
        {
            final JMenu menu;

            if (systemMenuCallback != null)
                menu = systemMenuCallback.getMenu();
            else
                menu = getDefaultSystemMenu();

            // ensure compatibility with heavyweight component
            menu.getPopupMenu().setLightWeightPopupEnabled(false);

            // rebuild menu
            titlePane.setSystemMenu(menu);
            // systemMenuBar.removeAll();
            // systemMenuBar.add(menu);
            // systemMenuBar.validate();
        }
    }

    public void setTitleBarVisible(boolean value)
    {
        if (value)
            getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
        else
            getRootPane().setWindowDecorationStyle(JRootPane.NONE);

        validate();
    }

    /**
     * close frame
     */
    public void close()
    {
        dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
    }

    /**
     * Implement isMinimized method
     */
    public boolean isMinimized()
    {
        return ComponentUtil.isMinimized(this);
    }

    /**
     * Implement isMaximized method
     */
    public boolean isMaximized()
    {
        return ComponentUtil.isMaximized(this);
    }

    /**
     * Implement setMinimized method
     */
    public void setMinimized(final boolean value)
    {
        ComponentUtil.setMinimized(this, value);
    }

    /**
     * Implement setMaximized method
     */
    public void setMaximized(final boolean value)
    {
        ComponentUtil.setMaximized(this, value);
    }

    /**
     * @return the titleBarVisible
     */
    public boolean isTitleBarVisible()
    {
        return getRootPane().getWindowDecorationStyle() != JRootPane.NONE;
    }

    /**
     * @return the closeItemVisible
     */
    public boolean isCloseItemVisible()
    {
        return closeItemVisible;
    }

    /**
     * @param value
     *        the closeItemVisible to set
     */
    public void setCloseItemVisible(boolean value)
    {
        if (closeItemVisible != value)
        {
            closeItemVisible = value;

            ThreadUtil.invokeLater(new Runnable()
            {
                @Override
                public void run()
                {
                    updateSystemMenu();
                }
            });
        }
    }

    /**
     * Return the default system menu
     */
    public JMenu getDefaultSystemMenu()
    {
        final JMenu result = new JMenu();

        if (closeItemVisible)
            result.add(new CloseAction());

        return result;
    }

    /**
     * @return the systemMenuCallback
     */
    public MenuCallback getSystemMenuCallback()
    {
        return systemMenuCallback;
    }

    /**
     * @param value
     *        the systemMenuCallback to set
     */
    public void setSystemMenuCallback(MenuCallback value)
    {
        if (systemMenuCallback != value)
        {
            systemMenuCallback = value;

            ThreadUtil.invokeLater(new Runnable()
            {
                @Override
                public void run()
                {
                    updateSystemMenu();
                }
            });
        }
    }

    @Override
    public void reshape(int x, int y, int width, int height)
    {
        final Rectangle r = new Rectangle(x, y, width, height);

        // prevent to go completely off screen
        ComponentUtil.fixPosition(this, r);

        super.reshape(r.x, r.y, r.width, r.height);
    }

//    @Override
//    public synchronized void setMaximizedBounds(Rectangle bounds)
//    {
//        Rectangle bnds = SystemUtil.getScreenBounds(ComponentUtil.getScreen(this), true);
//
//        if (bnds.isEmpty())
//            bnds = bounds;
//        // at least use the location from original bounds
//        else if (bounds != null)
//            bnds.setLocation(bounds.getLocation());
//        else
//            bnds.setLocation(0, 0);
//
//        super.setMaximizedBounds(bnds);
//    }
}