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

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;

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.JLabel;
import javax.swing.JPanel;
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;
import com.artenum.cassandra.plugin.glyph.GlyphPlugin.glyph_color_mode;
import com.artenum.cassandra.plugin.glyph.GlyphPlugin.glyph_scale_mode;
import com.artenum.cassandra.plugin.glyph.GlyphPlugin.glyph_source;

/**
 * <pre>
 * <b>Project ref           :</b> CASSANDRA project
 * <b>Copyright and license :</b> See relevant sections
 * <b>Status                :</b> under development
 * <b>Creation              :</b> 24/06/2010
 * <b>Modification          :</b>
 * 
 * <b>Description  :</b> Control panel for the plugin.
 * 
 * 
 * @author        Julien Forest
 * @version       0.1
 */
public class GlyphControlUI extends PlugInControlUI {
    /**
     * 
     */
    private static final long serialVersionUID = -6854692922870232665L;
    private final PipeLineManager pipeLineManager;
    private JFormattedTextField centerX;
    private final JCheckBox useNormalcheckbox;
    private final JComboBox input;
    private final JComboBox sourceCombo;
    private final JComboBox scaleModeCombo;
    private final JComboBox colorModeCombo;
    private final JFormattedTextField maskOnRatioTF;
    private final JFormattedTextField scalingFactorTF;
    private final JFormattedTextField resolutionTF;

    //
    private final GlyphPlugin 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 GlyphControlUI(final PipeLineManager pipeLineManager, final GlyphPlugin plugin, final Frame owner) {
        super(owner, "Glyph configuration panel");

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

        this.useNormalcheckbox = new JCheckBox("Normal oriented glyphs (instead of vector)");
        final JPanel vertexControlPanel = new JPanel();
        vertexControlPanel.add(this.useNormalcheckbox);

        // to select the input dataSet
        this.input = new JComboBox(new DataSetListModel(pipeLineManager.getDataSetList()));

        // define the "Update" button. The corresponding action name
        // is "UPDATE". The action itself 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 globalConfPanel = new JPanel(new GridBagLayout());
        final GridBagConstraints c = new GridBagConstraints();

        c.anchor = GridBagConstraints.LINE_START;
        c.insets.set(5, 5, 0, 10);
        c.weightx = 0.1;
        c.gridx = 0;
        c.gridy = 0;
        globalConfPanel.add(new JLabel("Input Dataset:"), c);
        c.gridy = 1;
        globalConfPanel.add(new JLabel("Mask-on ratio:"), c);
        c.gridy = 2;
        globalConfPanel.add(new JLabel("Scaling ratio:"), c);
        c.gridy = 3;
        globalConfPanel.add(new JLabel("Scale mode:"), c);
        c.gridy = 4;
        globalConfPanel.add(new JLabel("Color mode:"), c);
        c.gridy = 5;
        globalConfPanel.add(new JLabel("Force normal:"), c);
        c.gridy = 6;
        globalConfPanel.add(new JLabel("Glyph Type:"), c);
        c.gridy = 7;
        final JLabel resolutionLabel = new JLabel("Glyph resolution:");
        globalConfPanel.add(resolutionLabel, c);

        c.fill = GridBagConstraints.HORIZONTAL;
        c.anchor = GridBagConstraints.CENTER;
        c.insets.set(5, 5, 0, 5);
        c.weightx = 0.9;
        c.gridx = 1;

        c.gridy = 0;
        globalConfPanel.add(this.input, c);

        c.gridy = 1;
        this.maskOnRatioTF = new JFormattedTextField("0");
        this.maskOnRatioTF.setValue(plugin.maskOnRatio);
        this.maskOnRatioTF.addMouseWheelListener(new MouseWheelListener() {
            @Override
            public void mouseWheelMoved(final java.awt.event.MouseWheelEvent evt) {
                maskOnRationTFMouseWheelMoved(evt);
            }
        });
        globalConfPanel.add(this.maskOnRatioTF, c);

        c.gridy = 2;
        this.scalingFactorTF = new JFormattedTextField("1.0");
        this.scalingFactorTF.setValue(plugin.scalFactor);
        this.scalingFactorTF.addMouseWheelListener(new MouseWheelListener() {
            @Override
            public void mouseWheelMoved(final java.awt.event.MouseWheelEvent evt) {
                scalingFactorTFMouseWheelMoved(evt);
            }
        });
        globalConfPanel.add(this.scalingFactorTF, c);

        c.gridy = 3;
        this.scaleModeCombo = new JComboBox(GlyphPlugin.glyph_scale_mode.values());
        globalConfPanel.add(this.scaleModeCombo, c);

        c.gridy = 4;
        this.colorModeCombo = new JComboBox(GlyphPlugin.glyph_color_mode.values());
        globalConfPanel.add(this.colorModeCombo, c);

        c.gridy = 5;
        globalConfPanel.add(this.useNormalcheckbox, c);

        c.gridy = 6;
        this.sourceCombo = new JComboBox(GlyphPlugin.glyph_source.values());
        globalConfPanel.add(this.sourceCombo, c);
        this.sourceCombo.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(final ActionEvent e) {
                GlyphControlUI.this.resolutionTF.setVisible(((glyph_source) GlyphControlUI.this.sourceCombo
                        .getSelectedItem()).hasResolution());
                final int resolt = ((glyph_source) GlyphControlUI.this.sourceCombo.getSelectedItem())
                        .getBaseResolution();
                GlyphControlUI.this.resolutionTF.setText(Integer.toString(resolt));
                plugin.resolution = resolt;
                resolutionLabel.setVisible(((glyph_source) GlyphControlUI.this.sourceCombo.getSelectedItem())
                        .hasResolution());

                pack();
                final Dimension size = getSize();
                size.setSize(size.getWidth() + 100, size.getHeight());
                setSize(size);
            }
        });

        c.gridy = 7;
        this.resolutionTF = new JFormattedTextField(Integer.toString(plugin.resolution));
        this.resolutionTF.addMouseWheelListener(new MouseWheelListener() {
            @Override
            public void mouseWheelMoved(final java.awt.event.MouseWheelEvent evt) {
                resolutionTFMouseWheelMoved(evt);
            }
        });
        globalConfPanel.add(this.resolutionTF, c);

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

        getContentPane().add(BorderLayout.CENTER, globalConfPanel);
        getContentPane().add(BorderLayout.SOUTH, cmdLine);

        pack();
        final Dimension size = getSize();
        size.setSize(size.getWidth() + 100, size.getHeight());
        setSize(size);

        setLocationRelativeTo(null);
    }

    private void maskOnRationTFMouseWheelMoved(final MouseWheelEvent evt) {
        int tmpLevel;
        tmpLevel = ((Number) this.maskOnRatioTF.getValue()).intValue() - evt.getWheelRotation();
        if (tmpLevel < 1) {
            tmpLevel = 1;
        }
        this.maskOnRatioTF.setValue(tmpLevel);
        this.plugin.maskOnRatio = ((Number) this.maskOnRatioTF.getValue()).intValue();
    }

    private void scalingFactorTFMouseWheelMoved(final MouseWheelEvent evt) {
        double tmpScaling;
        tmpScaling = ((Number) this.scalingFactorTF.getValue()).doubleValue() - (evt.getWheelRotation() * 0.1);
        if (tmpScaling < 0) {
            tmpScaling = 0;
        }
        this.scalingFactorTF.setValue(tmpScaling);
        this.plugin.scalFactor = ((Number) this.scalingFactorTF.getValue()).doubleValue();
    }

    private void resolutionTFMouseWheelMoved(final MouseWheelEvent evt) {
        int tmpScaling;
        tmpScaling = ((int) Double.parseDouble(this.resolutionTF.getText())) - evt.getWheelRotation();
        if (tmpScaling < 0) {
            tmpScaling = 0;
        }
        this.resolutionTF.setText(String.valueOf(tmpScaling));
        this.plugin.resolution = tmpScaling;
    }

    /**
     * set the selected input data set.
     * 
     * @param selectedInput
     */
    public void setSelectedInput(final CassandraObject selectedInput) {
        if (selectedInput != null) {
            this.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.
     */
    @Override
    public void actionPerformed(final ActionEvent e) {
        final String command = e.getActionCommand();
        if (command.equals("UPDATE")) {
            if (this.input.getSelectedItem() == null) {
                return;
            }

            this.plugin.maskOnRatio = ((Number) this.maskOnRatioTF.getValue()).intValue();
            this.plugin.scalFactor = ((Number) this.scalingFactorTF.getValue()).doubleValue();
            this.plugin.resolution = (int) Double.parseDouble(this.resolutionTF.getText());

            this.plugin.updateGlyph((vtkDataSet) ((CassandraObject) this.input.getSelectedItem()).getVtkObject(),
                    (glyph_source) this.sourceCombo.getSelectedItem(),
                    (glyph_scale_mode) this.scaleModeCombo.getSelectedItem(),
                    (glyph_color_mode) this.colorModeCombo.getSelectedItem(), this.useNormalcheckbox.isSelected());
            this.pipeLineManager.validateViewAndGo();
        }

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

    /**
     *
     */
    @Override
    public void stateChanged(final 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.updateCellCenter(cx + (nx * value), cy + (ny * value), cz + (nz * value), nx, ny, nz,
        // (vtkDataSet) ((VtkObject) input.getSelectedItem()).getVtkObject());
        // pipeLineManager.validateViewAndGo();
        // }
    }

    /**
     * Define the data model for the input combo box.
     */
    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);
        }
    }

    @Override
    public void itemStateChanged(final ItemEvent arg0) {
        // TODO Auto-generated method stub

    }
}
