/**
 * Copyright (c) Artenum SARL 2004-2005
 * @author Julien Forest / Sebastien Jourdain
 *
 * All rights reserved. This software can
 * not be used or copy or diffused without
 * an explicit license of Artenum SARL, Paris-France
 */
package com.artenum.cassandra.plugin.clipping;

import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
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.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.ListDataListener;

import vtk.vtkDataSet;

import com.artenum.cassandra.pipeline.CassandraObject;
import com.artenum.cassandra.pipeline.PipeLineManager;
import com.artenum.cassandra.pipeline.VtkObjectListModel;
import com.artenum.cassandra.plugin.PlugInControlUI;

/**
 * <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, ARTENUM SARL
 * @author        Julien Forest, ARTENUM SARL
 * @version       1.2
 */
public class ClippingPlaneControlUI extends PlugInControlUI {
    /**
	 * 
	 */
	private static final long serialVersionUID = 2136608770217571843L;
	
	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 insideOut;
    private JCheckBox widgetCheckBox;

    //
    private ClippingPlanePlugin plugin;

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

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

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

        //
        centerX = new JFormattedTextField("0");
        centerX.setValue(new Double(0));
        centerY = new JFormattedTextField("0");
        centerY.setValue(new Double(0));
        centerZ = new JFormattedTextField("0");
        centerZ.setValue(new Double(0));
        normalX = new JFormattedTextField("0");
        normalX.setValue(new Double(0));
        normalY = new JFormattedTextField("0");
        normalY.setValue(new Double(0));
        normalZ = new JFormattedTextField("0");
        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" button. The corresponding action name
        //is "UPDATE". The action itself 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);

        insideOut = new JCheckBox("Inside-Out");
        insideOut.setActionCommand("UPDATE");
        insideOut.addActionListener(this);

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

		// 
		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);
        
        //
        JPanel cmdLine = new JPanel();
        cmdLine.setLayout(new BoxLayout(cmdLine, BoxLayout.LINE_AXIS));
        cmdLine.add(insideOut);
        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");

        //
        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);
    }
    
    /**
     * Update the 3D widget status according the checkbox of the control panel. 
     */
    public void update3DWidgetStatus(){
        plugin.show3DWidget(widgetCheckBox.isSelected());
    }

	/** Listens to the check boxes. */
	public void itemStateChanged(ItemEvent e) {
		Object source = e.getItemSelectable();
		if (source == widgetCheckBox) {
			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 
     * of the plugin's control.
     * 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.updateClippingPlane(cx, cy, cz, nx, ny, nz, (vtkDataSet) ((CassandraObject) input.getSelectedItem()).getVtkObject(), insideOut.isSelected());
            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.updateClippingPlane(cx + (nx * value), cy + (ny * value), cz + (nz * value), nx, ny, nz,
                (vtkDataSet) ((CassandraObject) input.getSelectedItem()).getVtkObject(), insideOut.isSelected());
            pipeLineManager.validateViewAndGo();
        }
    }

	/**
	 * Set the fields of the normal definition of the clipping plane. 
	 * 
	 * @param normal
	 */
	public void setNormalFieldsValues(double[] normal) {
		normalX.setValue(normal[0]);
		normalY.setValue(normal[1]);
		normalZ.setValue(normal[2]);
	}
	
	/**
	 * Set the fields of the normal definition of the clipping plane.
	 * 
	 * @param nx 
	 * 			x-coordinate of the normal. 
	 * @param ny
	 * 			y-coordinate of the normal.
	 * @param nz
	 * 			z-coordinate of the normal.
	 */
	public void setNormalFieldsValues(double nx, double ny, double nz) {
        normalX.setValue(nx);
        normalY.setValue(ny);
        normalZ.setValue(nz);
    }

	/**
	 * Set the origin point of the clipping plane.
	 * @param origine
	 */
	public void setOrigineFieldsValues(double[] origine) {
		centerX.setValue(origine[0]);
		centerY.setValue(origine[1]);
		centerZ.setValue(origine[2]);
	}
	
	/**
	 * Set the origin point of the clipping plane.
	 * 
	 * @param cx
	 * @param cy
	 * @param cz
	 */
	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 combo box.
     */
    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);
        }
    }
}
