/*
 * (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 com.artenum.cassandra.pipeline.PipeLineManager;
import com.artenum.cassandra.pipeline.VtkObjectListModel;
import com.artenum.cassandra.plugin.PlugInControlUI;
import com.artenum.cassandra.pipeline.CassandraObject;


import vtk.vtkDataSet;

import java.awt.Checkbox;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Hashtable;

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

/**
 * <pre>
 * &lt;b&gt;Project ref           :&lt;/b&gt; CASSANDRA project
 * &lt;b&gt;Copyright and license :&lt;/b&gt; See relevant sections
 * &lt;b&gt;Status                :&lt;/b&gt; stable
 * &lt;b&gt;Creation              :&lt;/b&gt; 04/03/2005
 * &lt;b&gt;Modification          :&lt;/b&gt;
 * &lt;b&gt;Description  :&lt;/b&gt; Control panel for the plugin.
 * 
 * 
 * 
 * &#064;author Sebastien Jourdain, ARTENUM SARL
 * &#064;author Julien Forest, ARTENUM SARL
 * 
 * @version 1.2
 */
public class CuttingPlaneControlUI extends PlugInControlUI {
    private PipeLineManager pipeLineManager;
    private JFormattedTextField centerX;
    private JFormattedTextField centerY;
    private JFormattedTextField centerZ;
    private JFormattedTextField normalX;
    private JFormattedTextField normalY;
    private JFormattedTextField normalZ;
    private JComboBox input;
    private JSlider slider;
    private JCheckBox widgetCheckBox;

    //
    private 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(PipeLineManager pipeLineManager, CuttingPlanePlugin plugin, Frame owner) {
        super(owner, "Cutting plane configuration panel");

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

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

        //
        NumberFormat format = new DecimalFormat("#.###");
        centerX = new JFormattedTextField(format);
        centerX.setValue(new Double(0));
        centerY = new JFormattedTextField(format);
        centerY.setValue(new Double(0));
        centerZ = new JFormattedTextField(format);
        centerZ.setValue(new Double(0));
        normalX = new JFormattedTextField(format);
        normalX.setValue(new Double(0));
        normalY = new JFormattedTextField(format);
        normalY.setValue(new Double(0));
        normalZ = new JFormattedTextField(format);
        normalZ.setValue(new Double(1));

        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(centerX);
        grid.add(centerY);
        grid.add(centerZ);
        grid.add(new JLabel("Normal"));
        grid.add(normalX);
        grid.add(normalY);
        grid.add(normalZ);

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

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

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

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

        //
        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"));
        slider = new JSlider(-10, 10, 0);
        slider.setMinorTickSpacing(1);
        slider.setMajorTickSpacing(10);
        slider.setLabelTable(label);
        slider.setPaintLabels(true);
        slider.setPaintLabels(true);
        slider.addChangeListener(this);
        slider.setToolTipText("Translation based on center point with the normal vector has unit");

        // 
        JPanel widgetLine = new JPanel();
        widgetLine.setLayout(new BoxLayout(widgetLine, BoxLayout.LINE_AXIS));
        widgetLine.add(Box.createHorizontalGlue());
        widgetCheckBox = new JCheckBox("Active 3D widget");
        widgetCheckBox.addItemListener(this);
        widgetLine.add(widgetCheckBox);

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

        getContentPane().add(cmdLine);

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

    public void update3DWidgetStatus() {
        plugin.show3DWidget(widgetCheckBox.isSelected());
    }

    /** Listens to the check boxes. */
    public void itemStateChanged(ItemEvent e) {

        Object source = e.getItemSelectable();

        if (source == widgetCheckBox) {
            // System.out.println(
            // "3D widgetBox is: "+widgetCheckBox.isSelected());
            plugin.show3DWidget(widgetCheckBox.isSelected());
        } else {
            System.out.println("Item not found");
        }
    }
    
    /**
     * set the selected input data set. 
     * @param selectedInput
     */
    public void setSelectedInput(CassandraObject selectedInput){
        if (selectedInput != null){
        input.getModel().setSelectedItem(selectedInput);
        } else {
            System.out.println("Selection is null");
        }
    }
    

    /**
     * Perform 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.
     */
    public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();
        if (command.equals("UPDATE")) {
            if (input.getSelectedItem() == null) {
                JOptionPane.showMessageDialog(new JFrame(), "Please select a valid input dataset.", "Input Filter Selection Error", JOptionPane.ERROR_MESSAGE);
                return;
            }

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

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

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

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

    }

    /**
     * Set the fields of the normal definition.
     * 
     * @param normal
     */
    public void setNormalFieldsValues(double[] normal) {
        normalX.setValue(new Double(normal[0]));
        normalY.setValue(new Double(normal[1]));
        normalZ.setValue(new Double(normal[2]));
    }

    public void setNormalFieldsValues(double nx, double ny, double nz) {
        normalX.setValue(nx);
        normalY.setValue(ny);
        normalZ.setValue(nz);
    }

    /**
     * Set the fields of the plane origin definition.
     * 
     * @param origine
     */
    public void setOrigineFieldsValues(double[] origine) {
        centerX.setValue(new Double(origine[0]));
        centerY.setValue(new Double(origine[1]));
        centerZ.setValue(new Double(origine[2]));
    }
    
    public void setOrigineFieldsValues(double cx, double cy, double cz) {
        centerX.setValue(cx);
        centerY.setValue(cy);
        centerZ.setValue(cz);
    }

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

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

        public Object getElementAt(int index) {
            return datasetModel.getElementAt(index);
        }

        public Object getSelectedItem() {
            return selectedItem;
        }

        public int getSize() {
            return datasetModel.getSize();
        }

        public void setSelectedItem(Object anItem) {
            selectedItem = anItem;
        }

        public void addListDataListener(ListDataListener l) {
            datasetModel.addListDataListener(l);
        }

        public void removeListDataListener(ListDataListener l) {
            datasetModel.removeListDataListener(l);
        }
    }
}
