/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on ----
!  AUTHOR(S): KOGA, Junichiro
!  File : Desk.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */
package ciss.phase_viewer.mainpanel;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;

import org.apache.log4j.Logger;

import ciss.phase_viewer.settings.GlobalProperties;
import ciss.phase_viewer.settings.PropertiesManager;

public class Desk extends JDesktopPane implements ChaseDesktop {
    private static Logger logger = Logger.getLogger(Desk.class.getName());
    private static Desk desktop;

    private int widthCount = 0;
    private int heightCount = 0;

    private JScrollPane scrollpane; // scroll pane associated with this desktop.
    private GlobalProperties gp;

    private Desk() {
        super();
        gp = PropertiesManager
                .getGlobalProperties(PropertiesManager.PROPERTIES_PVIEWER);
        String outline = gp.getProperty("outline_only");
        if (outline == null || !outline.trim().equals("false")) {
            this.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
        }
        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                int x = e.getX();
                int y = e.getY();
                if (e.getButton() == MouseEvent.BUTTON3) {
                    JPopupMenu popup = new JPopupMenu();
                    ChaseJMenuItems items = new ChaseJMenuItems();
                    JMenuItem[] ite = items.getMenuItems();
                    for (int i = 0; i < ite.length; i++) {
                        if (ite[i] != null) {
                            popup.add(ite[i]);
                        } else {
                            popup.addSeparator();
                        }
                    }
                    popup.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        });
    }

    public static JDesktopPane getDesktop() {
        if (desktop == null) {
            desktop = new Desk();
        }
        return (JDesktopPane) desktop;
    }

    public int getMaxLayer() {
        int layer = 0;
        JInternalFrame[] frames = getAllFrames();
        if (frames == null) {
            return layer;
        }
        for (int i = 0; i < frames.length; i++) {
            int foo = frames[i].getLayer();
            if (foo > layer) {
                layer = foo;
            }
        }
        return layer;
    }

    public Component add(Component component) {
        if (component instanceof AbstractInternalFrameChase) {
            Component[] comps = ((JInternalFrame) component).getComponents();
            for (int i = 0; i < comps.length; i++) {
                comps[i].addKeyListener(new InternalFrameKeyListener());
            }
        }
        return super.add(component);
    }

    public void setScrollPane(JScrollPane scrollpane_) {
        this.scrollpane = scrollpane_;
        this.scrollpane.getHorizontalScrollBar().addAdjustmentListener(
                new AdjustmentListener() {
                    public void adjustmentValueChanged(AdjustmentEvent e) {
                        if (scrollpane.getHorizontalScrollBar()
                                .getValueIsAdjusting()) {
                            deactivateHeavy();
                        }
                    }
                });

        this.scrollpane.getVerticalScrollBar().addAdjustmentListener(
                new AdjustmentListener() {
                    public void adjustmentValueChanged(AdjustmentEvent e) {
                        if (scrollpane.getVerticalScrollBar()
                                .getValueIsAdjusting()) {
                            deactivateHeavy();
                        }
                    }
                });
    }

    private ChaseGUI parent;

    protected void setParentFrame(ChaseGUI parent) {
        this.parent = parent;
    }

    public ChaseGUI getParentFrame() {
        return this.parent;
    }

    public JScrollPane getScrollPane() {
        return this.scrollpane;
    }

    private void deactivateHeavy() {
        JInternalFrame[] frames = getAllFrames();
        if (frames != null && frames.length > 0) {
            for (int i = 0; i < frames.length; i++) {
                if (((AbstractInternalFrameChase) frames[i]).isHeavyWeight()) {
                    try {
                        frames[i].setSelected(false);
                        frames[i].setLayer(0);
                    } catch (Exception ex) {
                    }
                }
            }
        }
    }

    public void componentShown() {
        scrollBarUpdate();
    }

    public void componentResized() {
        scrollBarUpdate();
    }

    public void componentMoved() {
        scrollBarUpdate();
    }

    public void componentHidden() {
        scrollBarUpdate();
    }

    public void initialLocation(Component frameNow) {
        initialLocation(frameNow, InternalFrameChase.AUTOMATIC);
    }

    public void selectLast() {
        Component[] components = super.getAllFrames();
        if (components == null || components.length <= 1) {
            return;
        }

        int visibles = 0;
        for (int i = 0; i < components.length; i++) {
            if (components[i].isVisible()) {
                visibles++;
            }
        }
        if (visibles == 0) {
            return;
        }

        int numFrames = components.length;

        for (int i = numFrames - 1; i >= 0; i--) {
            JInternalFrame frame = (JInternalFrame) components[i];
            if (frame.isVisible() && !frame.isIcon()) {
                try {
                    frame.setSelected(true);
                } catch (Exception ex) {
                }
                return;
            }
        }
    }

    public void initialLocation(Component frameNow, int location) {
        Component[] components = super.getAllFrames();
        if (components == null || components.length <= 1) {
            return;
        }

        int visibles = 0;
        for (int i = 0; i < components.length; i++) {
            if (components[i].isVisible()) {
                visibles++;
            }
        }
        if (visibles == 0) {
            return;
        }

        if (getSelectedFrame() == null || !getSelectedFrame().isVisible())
            return;

        String initial_position = gp.getProperty("initial_position");

        if (initial_position != null && initial_position.trim().equals("tile")) {
            tile(location, frameNow);
        } else {
            cascade(location, frameNow);
        }

    }

    private void tile(int location, Component frameNow) {
        logger.debug("setting initial location ...");
        int widthThis = getWidth();
        int heightThis = getHeight();

        Component framePre = getSelectedFrame();
        if (framePre == null) {
            framePre = ((Component[]) super.getAllFrames())[0];
            if (framePre == null) {
                frameNow.setLocation(0, 0);
                return;
            }
        }

        int hidari = framePre.getLocation().x;
        int migi = hidari + framePre.getSize().width;
        int ue = framePre.getLocation().y;
        int sita = ue + framePre.getSize().height;

        logger.debug("hidari, migi, ue, sita: " + hidari + " " + migi + " "
                + ue + " " + sita);

        if (location == InternalFrameChase.AUTOMATIC) {
            float a = (float) hidari / (float) widthThis;
            float b = (float) ue / (float) heightThis;
            float c = (float) (widthThis - migi) / (float) widthThis;
            if (c < 0.f) {
                c = 0.f;
            }
            float d = (float) (heightThis - sita) / (float) heightThis;
            if (d < 0.f) {
                d = 0.f;
            }

            float comp = 0.f;
            int index = 1;

            if (a > comp) {
                comp = a;
                index = 1;
                widthCount++;
            }

            if (b > comp) {
                comp = b;
                index = 2;
                heightCount++;
            }

            if (c > comp) {
                comp = c;
                index = 3;
                widthCount++;
            }

            if (d > comp) {
                comp = d;
                index = 4;
                heightCount++;
            }

            if (widthCount == 2) {
                index = 4;
                widthCount = 0;
            }

            if (heightCount == 2) {
                index = 3;
                heightCount = 0;
            }

            logger.debug("a,b,c,d,index: " + index + " " + a + " " + b + " "
                    + c + " " + d);

            if (index == 1) {
                frameNow.setLocation(hidari - frameNow.getSize().width, ue);
            } else if (index == 2) {
                frameNow.setLocation(hidari, ue - frameNow.getSize().height);
            } else if (index == 3) {
                frameNow.setLocation(migi, ue);
            } else if (index == 4) {
                frameNow.setLocation(hidari, sita);
            }
        } else if (location == InternalFrameChase.WEST) {
            frameNow.setLocation(hidari - frameNow.getSize().width, ue);
        } else if (location == InternalFrameChase.EAST) {
            frameNow.setLocation(migi, ue);
        } else if (location == InternalFrameChase.CENTER) {
            center(frameNow);
        }
    }

    private void center(Component frameNow) {
        Component framePre = getSelectedFrame();
        if (framePre == null) {
            framePre = ((Component[]) super.getAllFrames())[0];
            if (framePre == null) {
                frameNow.setLocation(0, 0);
                return;
            }
        }
        int centerx = framePre.getLocation().x + framePre.getWidth() / 2;
        int centery = framePre.getLocation().y + framePre.getHeight() / 2;
        int locx = centerx - frameNow.getWidth() / 2;
        int locy = centery - frameNow.getHeight() / 2;
        frameNow.setLocation(locx, locy);
    }

    private void cascade(int location, Component frameNow) {
        logger.debug("setting initial location ...");
        int widthThis = getWidth();
        int heightThis = getHeight();

        Component framePre = getSelectedFrame();
        if (framePre == null) {
            framePre = ((Component[]) super.getAllFrames())[0];
            if (framePre == null) {
                frameNow.setLocation(0, 0);
                return;
            }
        }

        int hidari = framePre.getLocation().x;
        int migi = hidari + framePre.getSize().width;
        int ue = framePre.getLocation().y;
        int sita = ue + framePre.getSize().height;

        logger.debug("hidari, migi, ue, sita: " + hidari + " " + migi + " "
                + ue + " " + sita);

        if (location == InternalFrameChase.AUTOMATIC) {

            int overlap_x = 20;
            int overlap_y = 20;

            String ox = gp.getProperty("overlap_x");
            String oy = gp.getProperty("overlap_y");
            if (ox != null) {
                try {
                    overlap_x = Integer.parseInt(ox);
                } catch (NumberFormatException nfe) {
                    overlap_x = 20;
                }
            }
            if (oy != null) {
                try {
                    overlap_y = Integer.parseInt(oy);
                } catch (NumberFormatException nfe) {
                    overlap_y = 20;
                }
            }

            int prex = framePre.getLocation().x;
            int prey = framePre.getLocation().y;

            int locx = prex + overlap_x;
            int locy = prey + overlap_y;
            frameNow.setLocation(locx, locy);
        } else if (location == InternalFrameChase.WEST) {
            frameNow.setLocation(hidari - frameNow.getSize().width, ue);
        } else if (location == InternalFrameChase.EAST) {
            frameNow.setLocation(migi, ue);
        } else if (location == InternalFrameChase.CENTER) {
            center(frameNow);
        }
    }

    protected void scrollBarUpdate() {
        JInternalFrame[] frames = null;
        try {
            frames = super.getAllFrames();
        } catch (Exception ex) {
            return;
        }
        int numFrames = frames.length;

        int migi = 0;
        int imigi = 0;
        int sita = 0;
        int isita = 0;

        for (int i = 0; i < numFrames; i++) {
            JInternalFrame frame = frames[i];
            int migi_ = frame.getLocation().x + frame.getSize().width;
            int sita_ = frame.getLocation().y + frame.getSize().height;
            if (migi_ > migi) {
                migi = migi_;
                imigi = i;
            }
            if (sita_ > sita) {
                sita = sita_;
                isita = i;
            }

            int hidari_ = frame.getLocation().x;
            int ue_ = frame.getLocation().y;
            int hidari = 0;
            int ue = 0;

            hidari = hidari_;
            ue = ue_;
            if (hidari_ < 0) {
                hidari = 0;
            }
            if (ue_ < 0) {
                ue = 0;
            }
            if (hidari != hidari_ || ue != ue_) {
                frame.setLocation(hidari, ue);
                frame.revalidate();
            }
        }
        logger.debug("migi: " + migi);
        logger.debug("sita: " + sita);

        this.setPreferredSize(new Dimension(migi, sita));
        this.revalidate();
    }
}

class InternalFrameKeyListener extends KeyAdapter {
    private Logger logger = Logger.getLogger(InternalFrameKeyListener.class
            .getName());

    protected InternalFrameKeyListener() {

    }

    public void keyPreseed(KeyEvent e) {
        logger.debug("pressed key: " + e);
    }

    public void keyReleased(KeyEvent e) {
        logger.debug("pressed key: " + e);
    }

    public void keyTyped(KeyEvent e) {
        logger.debug("pressed key: " + e);
    }

}
