/*
 * (c) Copyright: Artenum SARL, 101-103 Boulevard Mac Donald,
 *                75019, Paris, France 2005.
 *                http://www.artenum.com
 *
 * License:
 *
 *  This program is free software; you can redistribute it
 *  and/or modify it under the terms of the Q Public License;
 *  either version 1 of the License.
 *
 *  This program 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 Q Public License for more details.
 *
 *  You should have received a copy of the Q Public License
 *  License along with this program;
 *  if not, write to:
 *    Artenum SARL, 101-103 Boulevard Mac Donald,
 *    75019, PARIS, FRANCE, e-mail: contact@artenum.com
 */
package com.artenum.cassandra.plugin.cutting;

import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListDataListener;

import vtk.vtkDataSet;

import com.artenum.cassandra.pipeline.PipeLineManager;
import com.artenum.cassandra.pipeline.VtkObjectListModel;

/**
 * <pre>
 * <b>Project ref           :</b> CASSANDRA project
 * <b>Copyright and license :</b> See relevant sections
 * <b>Status                :</b> under development
 * <b>Creation              :</b> 04/03/2005
 * <b>Modification          :</b>
 * 
 * <b>Description  :</b> Control panel for the plugin.
 * 
 * </pre>
 * <table cellpadding="3" cellspacing="0" border="1" width="100%">
 * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
 * <td><b>Version number</b></td>
 * <td><b>Author (name, e-mail)</b></td>
 * <td><b>Corrections/Modifications</b></td>
 * </tr>
 * <tr>
 * <td>0.1</td>
 * <td>Sebastien Jourdain, jourdain@artenum.com</td>
 * <td>Creation</td>
 * </tr>
 * </table>
 * 
 * @author Sebastien Jourdain
 * @version 0.1
 */
public class CuttingPlaneControlUI extends JDialog implements ActionListener, ChangeListener {
    private final PipeLineManager pipeLineManager;
    private final JFormattedTextField centerX;
    private final JFormattedTextField centerY;
    private final JFormattedTextField centerZ;
    private final JFormattedTextField normalX;
    private final JFormattedTextField normalY;
    private final JFormattedTextField normalZ;
    private final JComboBox input;
    private final JSlider slider;

    //
    private final CuttingPlanePlugin plugin;

    /**
     * Defines the graphical interface of the control panel for the cutting plane plugin. This method just defines the
     * components and attach the action listener.
     * 
     * @param pipeLineManager
     * @param plugin
     */
    public CuttingPlaneControlUI(final PipeLineManager pipeLineManager, final CuttingPlanePlugin plugin,
            final Frame owner) {
        super(owner, "Cutting plane configuration panel");

        //
        this.pipeLineManager = pipeLineManager;
        this.plugin = plugin;

        //
        this.input = new JComboBox(new DataSetListModel(pipeLineManager.getDataSetList()));

        //
        this.centerX = new JFormattedTextField("0");
        this.centerX.setValue(new Double(0));
        this.centerY = new JFormattedTextField("0");
        this.centerY.setValue(new Double(0));
        this.centerZ = new JFormattedTextField("0");
        this.centerZ.setValue(new Double(0));
        this.normalX = new JFormattedTextField("0");
        this.normalX.setValue(new Double(0));
        this.normalY = new JFormattedTextField("0");
        this.normalY.setValue(new Double(0));
        this.normalZ = new JFormattedTextField("0");
        this.normalZ.setValue(new Double(1));

        final JPanel grid = new JPanel(new GridLayout(3, 4));
        grid.add(new JLabel());
        grid.add(new JLabel("X"));
        grid.add(new JLabel("Y"));
        grid.add(new JLabel("Z"));
        grid.add(new JLabel("Center"));
        grid.add(this.centerX);
        grid.add(this.centerY);
        grid.add(this.centerZ);
        grid.add(new JLabel("Normal"));
        grid.add(this.normalX);
        grid.add(this.normalY);
        grid.add(this.normalZ);

        // define the "Update" buton. The corresponding action name
        // is "UPDATE". The action istself is performed in the
        // actionPerformed method.
        final JButton exec = new JButton("Update");
        exec.setActionCommand("UPDATE");
        exec.addActionListener(this);

        final JButton cancel = new JButton("Cancel");
        cancel.setActionCommand("CANCEL");
        cancel.addActionListener(this);

        //
        final JPanel line1 = new JPanel();
        line1.setLayout(new BoxLayout(line1, BoxLayout.LINE_AXIS));
        line1.add(new JLabel("Input Dataset"));
        line1.add(this.input);

        //
        final JPanel cmdLine = new JPanel();
        cmdLine.setLayout(new BoxLayout(cmdLine, BoxLayout.LINE_AXIS));
        cmdLine.add(Box.createHorizontalGlue());
        cmdLine.add(exec);
        cmdLine.add(cancel);

        //
        final Hashtable label = new Hashtable();
        label.put(new Integer(-10), new JLabel("-1"));
        label.put(new Integer(10), new JLabel("1"));
        label.put(new Integer(0), new JLabel("0"));
        this.slider = new JSlider(-10, 10, 0);
        this.slider.setMinorTickSpacing(1);
        this.slider.setMajorTickSpacing(10);
        this.slider.setLabelTable(label);
        this.slider.setPaintLabels(true);
        this.slider.setPaintLabels(true);
        this.slider.addChangeListener(this);
        this.slider.setToolTipText("Translation based on center point with the normal vector has unit");

        //
        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
        getContentPane().add(line1);
        getContentPane().add(grid);
        getContentPane().add(this.slider);
        getContentPane().add(cmdLine);

        // getContentPane().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        pack();
        final Dimension size = getSize();
        size.setSize(size.getWidth() + 100, size.getHeight());
        setSize(size);
        setLocationRelativeTo(null);
    }

    /**
     * Performe the actions requested by the components (buttons, etc...) of the control GUI of the plugin. The actions
     * are filtered on the keywords previously defined. If needed and depending on the action, this method the relevant
     * update method of the plugin.
     */
    @Override
    public void actionPerformed(final ActionEvent e) {
        final String command = e.getActionCommand();
        if (command.equals("UPDATE")) {
            if (this.input.getSelectedItem() == null) {
                return;
            }

            this.slider.setValue(0);
            final double cx = ((Number) this.centerX.getValue()).doubleValue();
            final double cy = ((Number) this.centerY.getValue()).doubleValue();
            final double cz = ((Number) this.centerZ.getValue()).doubleValue();
            final double nx = ((Number) this.normalX.getValue()).doubleValue();
            final double ny = ((Number) this.normalY.getValue()).doubleValue();
            final double nz = ((Number) this.normalZ.getValue()).doubleValue();

            // here update the cutting plan input data of the cutting plane plugin
            this.plugin.updateCuttingPlane(cx, cy, cz, nx, ny, nz,
                    (vtkDataSet) ((VtkObject) this.input.getSelectedItem()).getVtkObject());
            this.pipeLineManager.validateViewAndGo();
        }

        if (command.equals("CANCEL")) {
            this.dispose();
        }
    }

    /**
     * slide bar listener. The update of the pipeline is directly performed when the sldie bar is changed.
     */
    @Override
    public void stateChanged(final ChangeEvent e) {
        final double value = ((double) this.slider.getValue()) / 10;
        final double cx = ((Number) this.centerX.getValue()).doubleValue();
        final double cy = ((Number) this.centerY.getValue()).doubleValue();
        final double cz = ((Number) this.centerZ.getValue()).doubleValue();
        final double nx = ((Number) this.normalX.getValue()).doubleValue();
        final double ny = ((Number) this.normalY.getValue()).doubleValue();
        final double nz = ((Number) this.normalZ.getValue()).doubleValue();
        if (this.input.getSelectedItem() != null) {
            this.plugin.updateCuttingPlane(cx + (nx * value), cy + (ny * value), cz + (nz * value), nx, ny, nz,
                    (vtkDataSet) ((VtkObject) this.input.getSelectedItem()).getVtkObject());
            this.pipeLineManager.validateViewAndGo();
        }
    }

    /**
     * Define the data model for the input combobox.
     */
    class DataSetListModel implements ComboBoxModel {
        private final VtkObjectListModel datasetModel;
        private Object selectedItem;

        public DataSetListModel(final VtkObjectListModel datasetModel) {
            this.datasetModel = datasetModel;
        }

        @Override
        public Object getElementAt(final int index) {
            return this.datasetModel.getElementAt(index);
        }

        @Override
        public Object getSelectedItem() {
            return this.selectedItem;
        }

        @Override
        public int getSize() {
            return this.datasetModel.getSize();
        }

        @Override
        public void setSelectedItem(final Object anItem) {
            this.selectedItem = anItem;
        }

        @Override
        public void addListDataListener(final ListDataListener l) {
            this.datasetModel.addListDataListener(l);
        }

        @Override
        public void removeListDataListener(final ListDataListener l) {
            this.datasetModel.removeListDataListener(l);
        }
    }
}
