/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/08/29, 11:16
!  AUTHOR(S): KOGA, Junichiro
!  File : MeasurePanel.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.plugins.viewer.measure;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.media.j3d.BranchGroup;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.TitledBorder;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;

import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;

import ciss.phase_viewer.acviewer.ConfigData;
import ciss.phase_viewer.acviewer.ConfigDataUpdateEvent;
import ciss.phase_viewer.acviewer.J3DPanel;
import ciss.phase_viewer.acviewer.measure.Measurable;
import ciss.phase_viewer.acviewer.measure.Measure;
import ciss.phase_viewer.acviewer.measure.MeasureBranchGroup;
import ciss.phase_viewer.acviewer.measure.MeasureListener;
import ciss.phase_viewer.acviewer.measure.NullMeasure;
import ciss.phase_viewer.acviewer.scenegraphelements.MeasureObject;
import ciss.phase_viewer.main.PluginLoader;
import ciss.phase_viewer.mainpanel.InternalFrameChase;

/**
 * 「測定用」GUI
 * 
 * @author
 */
public class MeasurePanel extends InternalFrameChase implements ConfigData,
        MeasureListener {
    private Logger logger = Logger.getLogger(MeasurePanel.class.getName());
    private J3DPanel parent;
    private Measurable measurable;
    private Measure[] measures;

    private JComboBox measureSelector;

    private JList jList;
    private DefaultListModel listModel;

    public MeasurePanel(J3DPanel parent) {
        super("measure", new Dimension(350, 250));
        this.parent = parent;
        if (parent.getRootTransform() instanceof Measurable) {
            this.measurable = (Measurable) parent.getRootTransform();
            this.measurable.addMeasureListener(this);
        } else {
            logger.error("'measure' function not supported.");
            dispose();
            return;
        }
        init();
        parent.addDisposeOnExit(this);
        setVisible(true);
    }

    private void init() {
        Container container = getContentPane();
        container.setLayout(new BorderLayout());
        createMeasures();
        JPanel mpanel = new JPanel();
        mpanel.setBorder(new TitledBorder("select measure"));
        mpanel.add(measureSelector);
        container.add(mpanel, BorderLayout.NORTH);

        JPanel mlist = createMeasureList();
        container.add(mlist, BorderLayout.CENTER);

        JPanel btns = createBtnPanel();
        container.add(btns, BorderLayout.SOUTH);
        // addWindowListener(new WindowAdapter() {
        // public void windowClosed(WindowEvent e) {
        // winclosed();
        // }
        // });
        addInternalFrameListener(new InternalFrameAdapter() {
            public void internalFrameClosed(InternalFrameEvent ev) {
                winclosed();
            }
        });
    }

    private void winclosed() {
        measurable.removeMeasureListener(this);
        measurable.registerMeasure(new NullMeasure(measurable));
    }

    private JPanel createMeasureList() {
        JPanel ret = new JPanel();
        ret.setLayout(new BoxLayout(ret, BoxLayout.Y_AXIS));
        listModel = new DefaultListModel();
        jList = new JList(listModel);
        JScrollPane scrpane = new JScrollPane(jList);
        ret.add(scrpane);
        MeasureBranchGroup[] mbgs = measurable.getExistingMeasures();
        if (mbgs != null && mbgs.length != 0) {
            for (int i = 0; i < mbgs.length; i++) {
                for (int j = 0; j < mbgs[i].numChildren(); j++) {
                    MeasureObject mobj = (MeasureObject) mbgs[i].getChild(j);
                    listModel.addElement(mobj);
                }
            }
        }

        return ret;
    }

    private String FS = System.getProperty("file.separator");
    private String specfile = System.getProperty("pviewer.home") + FS
            + "plugins" + FS + "ciss" + FS + "phase_viewer" + FS + "plugins"
            + FS + "viewer" + FS + "measure" + FS + "supported.xml";

    private void createMeasures() {
        logger.debug("specfile: " + specfile);
        String[] measureNames;
        Object[] args = new Object[] { measurable };
        Document doc = ciss.phase_viewer.jdom.XMLUtils
                .getDocumentFromFile(new File(specfile));
        Element rootElement = doc.getRootElement();
        java.util.List measureList = rootElement.getChildren("measure");
        measureNames = new String[measureList.size()];
        measures = new Measure[measureList.size()];
        for (int i = 0; i < measureList.size(); i++) {
            Element measureElement = (Element) measureList.get(i);
            measureNames[i] = measureElement.getChildTextTrim("name");
            String clazz = measureElement.getChildTextTrim("class");
            measures[i] = (Measure) PluginLoader.instantiate(clazz, args);
        }
        measureSelector = new JComboBox(measures);
        measureSelector.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                measurable.registerMeasure((Measure) measureSelector
                        .getSelectedItem());
            }
        });
        measureSelector.setSelectedIndex(0);
    }

    private JButton remselected;
    private JButton remall;
    private JButton dismiss;

    private JPanel createBtnPanel() {
        JPanel btnpanel = new JPanel();
        btnpanel.setLayout(new BoxLayout(btnpanel, BoxLayout.X_AXIS));
        remselected = new JButton("remove selected");
        remall = new JButton("remove all");
        dismiss = new JButton("dismiss");
        btnpanel.add(remselected);
        btnpanel.add(remall);
        btnpanel.add(dismiss);

        dismiss.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });

        remselected.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                remSelected();
            }
        });

        remall.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                remAll();
            }
        });

        JPanel ret = new JPanel();
        ret.add(btnpanel);
        return ret;
    }

    private void remSelected() {
        int[] indeces = jList.getSelectedIndices();
        if (indeces == null || indeces.length == 0) {
            logger.info("measure unselected");
            return;
        }

        for (int i = indeces.length - 1; i >= 0; i--) {
            if (indeces[i] < 0 || indeces[i] >= listModel.size())
                continue;
            Object obj = listModel.remove(indeces[i]);
            ((BranchGroup) obj).detach();
        }

    }

    private void remAll() {
        for (int i = listModel.size() - 1; i >= 0; i--) {
            if (i < 0 || i >= listModel.size())
                continue;
            Object obj = listModel.remove(i);
            ((BranchGroup) obj).detach();
        }
    }

    /**
     * 座標の変更に伴い, メジャーを作り直す
     */
    public void configDataUpdate(boolean rescaleOnUpdate,
            ConfigDataUpdateEvent e) {
        configDataUpdate();
    }

    public boolean needsUpdate() {
        return true;
    }

    public void configDataUpdate() {
    }

    public void measured(Measure measure) {
        logger.debug("at measured");
        MeasureBranchGroup mbg = measure.getMeasureBranch();
        if (mbg.numChildren() == 0)
            return;
        MeasureObject mobj = (MeasureObject) mbg
                .getChild(mbg.numChildren() - 1);
        mobj.setAssociatedListModel(listModel);
        listModel.addElement(mobj);
    }

    public void measureUpdated(Measure measure) {
        if (jList != null)
            jList.repaint();
    }

}
