/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on ----
!  AUTHOR(S): KOGA, Junichiro
!  File : AbstractInternalFrameChase.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.Dimension;
import java.awt.Point;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;

import javax.swing.JInternalFrame;
import javax.swing.JViewport;

import org.apache.log4j.Logger;

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

public abstract class AbstractInternalFrameChase extends JInternalFrame
        implements ChaseFrame {
    private int location = AUTOMATIC;

    private static Logger logger = Logger
            .getLogger(AbstractInternalFrameChase.class.getName());
    protected GlobalProperties props = PropertiesManager
            .getGlobalProperties(PropertiesManager.PROPERTIES_PVIEWER);

    private boolean initVisible = true;
    private boolean deiconfiedBySelect = false;

    private String ident;

    public AbstractInternalFrameChase() {
        super("");
        this.initIFC();
        this.addListeners();
    }

    public AbstractInternalFrameChase(Dimension size) {
        super("");
        this.initIFC();
        this.setSize(size);
        this.addListeners();
    }

    public AbstractInternalFrameChase(String title) {
        super(title);
        this.initIFC();
        this.addListeners();
    }

    public AbstractInternalFrameChase(String title, Dimension size) {
        super(title, true, true, true, true);
        this.setSize(size);
        this.initIFC();
        this.addListeners();
    }

    public AbstractInternalFrameChase(String title, boolean b1) {
        super(title, b1);
        this.initIFC();
        this.addListeners();
    }

    public AbstractInternalFrameChase(String title, boolean b1, boolean b2) {
        super(title, b1, b2);
        this.initIFC();
        this.addListeners();
    }

    public AbstractInternalFrameChase(String title, boolean b1, boolean b2,
            boolean b3) {
        super(title, b1, b2, b3);
        this.initIFC();
        this.addListeners();
    }

    public AbstractInternalFrameChase(String title, boolean b1, boolean b2,
            boolean b3, boolean b4) {
        super(title, b1, b2, b3, b4);
        this.initIFC();
        this.addListeners();
    }

    public AbstractInternalFrameChase(String title, boolean b1, boolean b2,
            boolean b3, boolean b4, Dimension size) {
        super(title, b1, b2, b3, b4);
        this.setSize(size);
        this.initIFC();
        this.addListeners();
    }

    public AbstractInternalFrameChase(String title, boolean b1, boolean b2,
            boolean b3, boolean b4, Dimension size, String ID) {
        super(title, b1, b2, b3, b4);
        this.ID = ID;
        this.setSize(size);
        this.initIFC();
        this.addListeners();
    }

    public AbstractInternalFrameChase(String title, boolean b1, boolean b2,
            boolean b3, boolean b4, Dimension size, boolean initVisible) {
        super(title, b1, b2, b3, b4);
        this.location = location;
        this.initVisible = initVisible;
        this.setSize(size);
        this.initIFC();
        this.addListeners();
    }

    public AbstractInternalFrameChase(String title, boolean b1, boolean b2,
            boolean b3, boolean b4, int location) {
        super(title, b1, b2, b3, b4);
        this.location = location;
        this.initIFC();
        this.addListeners();
    }

    public AbstractInternalFrameChase(String title, boolean b1, boolean b2,
            boolean b3, boolean b4, Dimension size, int location) {
        super(title, b1, b2, b3, b4);
        this.location = location;
        this.setSize(size);
        this.initIFC();
        this.addListeners();
    }

    public AbstractInternalFrameChase(String title, boolean b1, boolean b2,
            boolean b3, boolean b4, Dimension size, int location,
            boolean initVisible) {
        super(title, b1, b2, b3, b4);
        this.location = location;
        this.initVisible = initVisible;
        this.setSize(size);
        this.initIFC();
        this.addListeners();
    }

    private String ID = "";

    private void initIFC() {
        try {
            Desk.getDesktop().add(this);

            // ident =
            // AbstractInternalFrameChase.class.getName()+"."+getTitle();
            ident = getClass().getName();
            if (ID.trim().length() != 0) {
                ident = getClass().getName() + "." + ID;
            }

            String winx = ident + ".window_size_x";
            String winy = ident + ".window_size_y";
            GlobalProperties props = PropertiesManager
                    .getGlobalProperties(PropertiesManager.PROPERTIES_WINDOW);
            try {
                int sizex = Integer.parseInt(props.getProperty(winx));
                int sizey = Integer.parseInt(props.getProperty(winy));
                setSize(sizex, sizey);
            } catch (NumberFormatException exc) {
            }

            String listen = props.getProperty("listen_to_component");
            if (listen == null || !listen.trim().equals("false")) {
                super.addComponentListener(new ComponentListenerChase(this));
            }

            ((ChaseDesktop) Desk.getDesktop()).initialLocation(this, location);

            if (initVisible) {
                this.setVisible(true);
            }
        } catch (RuntimeException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // JPanel dummy = new JPanel();
        // getContentPane().add(dummy);
        // addKeyListener(new InternalFrameKeyListener());

    }

    abstract void addListeners();

    public ChaseDesktop getDesktop() {
        return (ChaseDesktop) Desk.getDesktop();
    }

    public void selected() {
        selected(false);
    }

    public void selected(boolean initialize) {

        if (this.isIcon()) {
            try {
                this.setIcon(false);
                deiconfiedBySelect = true;
            } catch (java.beans.PropertyVetoException ex) {
                logger.warn("failed to select frame: " + this.getTitle());
            }
        }
        try {
            if (!this.isSelected()) {
                this.setSelected(true);
            }
        } catch (java.beans.PropertyVetoException ex) {
            logger.warn("failed to select frame: " + this.getTitle());
        }

        if (initialize) {
            deiconfiedBySelect = false;
        }

        checkBounds(((Desk) Desk.getDesktop()).getScrollPane().getViewport());
    }

    public void unselect() {
        try {
            this.setSelected(false);
            if (deiconfiedBySelect) {
                try {
                    this.setIcon(true);
                    deiconfiedBySelect = false;
                } catch (java.beans.PropertyVetoException ex) {
                    logger.warn("couldn't iconfy frame: " + this.getTitle());
                    System.out.println("couldn't iconfy frame: "
                            + this.getTitle());
                    deiconfiedBySelect = false;
                }
            }
        } catch (java.beans.PropertyVetoException ex) {
            logger.warn("failed to 'un' select frame: " + this.getTitle());
        }
    }

    protected void checkBounds(JViewport viewport) {
        String check = PropertiesManager.getGlobalProperties(
                PropertiesManager.PROPERTIES_PVIEWER).getProperty(
                "check_bounds_internal_frame");
        if (check != null && check.trim().equals("false")) {
            return;
        }

        int viewxmin = viewport.getViewPosition().x;
        int viewymin = viewport.getViewPosition().y;
        int viewxmax = viewxmin + viewport.getExtentSize().width;
        int viewymax = viewymin + viewport.getExtentSize().height;

        int framexmin = this.getLocation().x;
        int frameymin = this.getLocation().y;
        int framexmax = framexmin + this.getWidth();
        int frameymax = frameymin + this.getHeight();

        logger.debug("bounding box of viewport: " + viewxmin + " " + viewymin
                + " " + viewxmax + " " + viewymax);
        logger.debug("bounding box of frame: " + framexmin + " " + frameymin
                + " " + framexmax + " " + frameymax);

        if (framexmin < viewxmin || frameymin < viewymin
                || framexmax > viewxmax || frameymax > viewymax) {
            logger.debug("frame is out of bounds.");
        } else {
            logger.debug("frame is not out of bounds.");
            return;
        }

        int posx = viewxmin;
        int posy = viewymin;

        if (framexmax > viewxmax) {
            posx = posx + framexmax - viewxmax;
        }

        if (frameymax > viewymax) {
            posy = posy + frameymax - viewymax;
        }

        if (framexmin < viewxmin) {
            posx = posx + framexmin - viewxmin;
        }

        if (frameymin < viewymin) {
            posy = posy + frameymin - viewymin;
        }

        logger.debug("setting view position at: " + posx + " " + posy);
        logger.debug("framemax: " + framexmax + " " + frameymax);

        viewport.setViewPosition(new Point(posx, posy));
        Desk.getDesktop().revalidate();
    }

    public void saveState() {
    }

    class ComponentListenerChase implements ComponentListener {
        private Logger logger = Logger.getLogger(ComponentListenerChase.class
                .getName());

        private ChaseDesktop desktop;

        public ComponentListenerChase(ChaseFrame parent) {
            this.desktop = parent.getDesktop();
        }

        public void componentHidden(ComponentEvent e) {
            desktop.componentHidden();
        }

        public void componentMoved(ComponentEvent e) {
            desktop.componentMoved();
            checkBounds(e);
        }

        public void componentResized(ComponentEvent e) {
            desktop.componentResized();
            Dimension dim = e.getComponent().getSize();
            logger.debug("size of component: " + dim.width + ", " + dim.height);
            checkBounds(e);
            String winx = ident + ".window_size_x";
            String winy = ident + ".window_size_y";
            GlobalProperties props = PropertiesManager
                    .getGlobalProperties(PropertiesManager.PROPERTIES_WINDOW);
            props.setProperty(winx, String.valueOf(getSize().width));
            props.setProperty(winy, String.valueOf(getSize().height));
            props.storeProperty();
        }

        public void componentShown(ComponentEvent e) {
            desktop.componentShown();
            checkBounds(e);
        }

        private void checkBounds(ComponentEvent e) {
            ChaseFrame fr = (ChaseFrame) e.getSource();
            fr.selected();
        }
    }

}
