/**
 * 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.cutter;

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

import vtk.vtkDataSet;

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.JComboBox;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListDataListener;

/**
 * <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
 * @version       0.1
 */
public class CutterControlUI extends PlugInControlUI {
    private PipeLineManager pipeLineManager;

    // general
    private JComboBox input;
    private JTabbedPane tab;

    // plane
    private JFormattedTextField planeCenterX;
    private JFormattedTextField planeCenterY;
    private JFormattedTextField planeCenterZ;
    private JFormattedTextField planeNormalX;
    private JFormattedTextField planeNormalY;
    private JFormattedTextField planeNormalZ;
    private JSlider planeSlider;

    // sphere
    private JFormattedTextField sphereCenterX;
    private JFormattedTextField sphereCenterY;
    private JFormattedTextField sphereCenterZ;
    private JFormattedTextField sphereRadius;

    // cylinder
    private JFormattedTextField cylinderCenterX;
    private JFormattedTextField cylinderCenterY;
    private JFormattedTextField cylinderCenterZ;
    private JFormattedTextField cylinderRx;
    private JFormattedTextField cylinderRy;
    private JFormattedTextField cylinderRz;
    private JFormattedTextField cylinderRadius;

    //
    private CutterPlugin 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 CutterControlUI(PipeLineManager pipeLineManager, CutterPlugin plugin, Frame owner) {
        super(owner, "Generic cutter configuration panel");

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

        // Input dataset
        input = new JComboBox(new DataSetListModel(pipeLineManager.getDataSetList()));
        JPanel line1 = new JPanel();
        line1.setLayout(new BoxLayout(line1, BoxLayout.LINE_AXIS));
        line1.add(new JLabel("Input Dataset"));
        line1.add(input);

        // Plane cut
        JPanel planeCutPanel = new JPanel();
        planeCutPanel.setLayout(new BoxLayout(planeCutPanel, BoxLayout.PAGE_AXIS));

        // plane Info
        planeCenterX = new JFormattedTextField("0");
        planeCenterX.setValue(new Double(0));
        planeCenterY = new JFormattedTextField("0");
        planeCenterY.setValue(new Double(0));
        planeCenterZ = new JFormattedTextField("0");
        planeCenterZ.setValue(new Double(0));
        planeNormalX = new JFormattedTextField("0");
        planeNormalX.setValue(new Double(0));
        planeNormalY = new JFormattedTextField("0");
        planeNormalY.setValue(new Double(0));
        planeNormalZ = new JFormattedTextField("0");
        planeNormalZ.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(planeCenterX);
        grid.add(planeCenterY);
        grid.add(planeCenterZ);
        grid.add(new JLabel("Normal"));
        grid.add(planeNormalX);
        grid.add(planeNormalY);
        grid.add(planeNormalZ);

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

        planeCutPanel.add(grid);
        planeCutPanel.add(planeSlider);

        // Sphere cut
        JPanel sphereCutPanel = new JPanel();
        sphereCutPanel.setLayout(new BoxLayout(sphereCutPanel, BoxLayout.PAGE_AXIS));

        // Sphere Info
        sphereCenterX = new JFormattedTextField("0");
        sphereCenterX.setValue(new Double(0));
        sphereCenterY = new JFormattedTextField("0");
        sphereCenterY.setValue(new Double(0));
        sphereCenterZ = new JFormattedTextField("0");
        sphereCenterZ.setValue(new Double(0));
        sphereRadius = new JFormattedTextField("0");
        sphereRadius.setValue(new Double(1));
        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(sphereCenterX);
        grid.add(sphereCenterY);
        grid.add(sphereCenterZ);
        grid.add(new JLabel("Radius"));
        grid.add(sphereRadius);

        sphereCutPanel.add(grid);

        // Cylinder cut
        JPanel cylinderCutPanel = new JPanel();
        cylinderCutPanel.setLayout(new BoxLayout(cylinderCutPanel, BoxLayout.PAGE_AXIS));

        // Cylinder Info
        cylinderCenterX = new JFormattedTextField("0");
        cylinderCenterX.setValue(new Double(0));
        cylinderCenterY = new JFormattedTextField("0");
        cylinderCenterY.setValue(new Double(0));
        cylinderCenterZ = new JFormattedTextField("0");
        cylinderCenterZ.setValue(new Double(0));
        cylinderRx = new JFormattedTextField("0");
        cylinderRx.setValue(new Double(0));
        cylinderRy = new JFormattedTextField("0");
        cylinderRy.setValue(new Double(0));
        cylinderRz = new JFormattedTextField("0");
        cylinderRz.setValue(new Double(0));
        cylinderRadius = new JFormattedTextField("0");
        cylinderRadius.setValue(new Double(1));
        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(cylinderCenterX);
        grid.add(cylinderCenterY);
        grid.add(cylinderCenterZ);
        grid.add(new JLabel("Rotate"));
        grid.add(cylinderRx);
        grid.add(cylinderRy);
        grid.add(cylinderRz);

        JPanel line = new JPanel();
        line.setLayout(new BoxLayout(line, BoxLayout.LINE_AXIS));
        line.add(new JLabel("Radius"));
        line.add(cylinderRadius);

        cylinderCutPanel.add(grid);
        cylinderCutPanel.add(line);

        // Command line
        //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 cmdLine = new JPanel();
        cmdLine.setLayout(new BoxLayout(cmdLine, BoxLayout.LINE_AXIS));
        cmdLine.add(Box.createHorizontalGlue());
        cmdLine.add(exec);
        cmdLine.add(cancel);

        // Cutting type
        tab = new JTabbedPane();
        tab.add("Plane", planeCutPanel);
        tab.add("Sphere", sphereCutPanel);
        tab.add("Cylinder", cylinderCutPanel);

        // Dialog layout
        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
        getContentPane().add(line1);
        getContentPane().add(tab);
        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);
    }

    /**
     * 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) {
                return;
            }

            switch (tab.getSelectedIndex()) {
            case 0: // Plane
                planeSlider.setValue(0);
                //here update the cutting plan input data of the cutting plane plugin 
                plugin.updateCuttingPlane(((Number) planeCenterX.getValue()).doubleValue(), ((Number) planeCenterY.getValue()).doubleValue(),
                    ((Number) planeCenterZ.getValue()).doubleValue(), ((Number) planeNormalX.getValue()).doubleValue(),
                    ((Number) planeNormalY.getValue()).doubleValue(), ((Number) planeNormalZ.getValue()).doubleValue(),
                    (vtkDataSet) ((CassandraObject) input.getSelectedItem()).getVtkObject());
                break;
            case 1: // Sphere
                plugin.updateCuttingSphere(((Number) sphereCenterX.getValue()).doubleValue(), ((Number) sphereCenterY.getValue()).doubleValue(),
                    ((Number) sphereCenterZ.getValue()).doubleValue(), ((Number) sphereRadius.getValue()).doubleValue(),
                    (vtkDataSet) ((CassandraObject) input.getSelectedItem()).getVtkObject());
                break;
            case 2: // Cylinder
                plugin.updateCuttingCylinder(((Number) cylinderCenterX.getValue()).doubleValue(), ((Number) cylinderCenterY.getValue()).doubleValue(),
                    ((Number) cylinderCenterZ.getValue()).doubleValue(), ((Number) cylinderRx.getValue()).doubleValue(),
                    ((Number) cylinderRy.getValue()).doubleValue(), ((Number) cylinderRz.getValue()).doubleValue(),
                    ((Number) cylinderRadius.getValue()).doubleValue(), (vtkDataSet) ((CassandraObject) input.getSelectedItem()).getVtkObject());
                break;
            case 3: // Cube
                break;
            }

            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.
     */
    public void stateChanged(ChangeEvent e) {
        double value = ((double) planeSlider.getValue()) / 10;
        double nx = ((Number) planeNormalX.getValue()).doubleValue();
        double ny = ((Number) planeNormalY.getValue()).doubleValue();
        double nz = ((Number) planeNormalZ.getValue()).doubleValue();
        double cx = ((Number) planeCenterX.getValue()).doubleValue();
        double cy = ((Number) planeCenterY.getValue()).doubleValue();
        double cz = ((Number) planeCenterZ.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();
        }
    }

    /**
     * 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);
        }
    }

    public void itemStateChanged(ItemEvent arg0) {
        // TODO Auto-generated method stub
        
    }
}
