/*
 * -------------------------------------------------------------------------
 *      $Id: RBPanel.java,v 1.5 2006/03/16 18:33:59 estewart Exp $
 * -------------------------------------------------------------------------
 *      Copyright (c) 1999 Visual Numerics Inc. All Rights Reserved.
 *
 *      This software is confidential information which is proprietary to
 *      and a trade secret of Visual Numerics, Inc.  Use, duplication or
 *      disclosure is subject to the terms of an appropriate license
 *      agreement.
 *
 *      VISUAL NUMERICS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
 *      SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING
 *      BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 *      FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. VISUAL
 *      NUMERICS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 *      AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
 *      ITS DERIVATIVES.
 *--------------------------------------------------------------------------
 */

/*
 * RBPanel.java
 *
 * Created on August 19, 2003, 10:45 AM
 */

package com.imsl.demo.fitting;

import com.imsl.chart.*;
import java.util.Vector;
import java.awt.event.*;
import javax.swing.event.*;

public class RBPanel extends javax.swing.JPanel implements ActionListener, ChangeListener, MouseListener {

    private double mse;
    private Chart chart;
    private AxisXY axis;
    private Data point;
    private Contour contour;
    private Vector dataX, dataY, dataZ;
    private double[] x, y, z;
    private double[] xRange, yRange, zRange;
    private boolean showSurface;
    private javax.swing.JFrame parentFrame;
    private javax.swing.JRadioButtonMenuItem[] jRadioButtons;
    public javax.swing.JCheckBox jCheck3d;
    private SurfacePlot surfacePlot;
    private final java.awt.Color light = new java.awt.Color(255,236,215);
    private final java.awt.Color dark = new java.awt.Color(43,0,0);
    private final int numData = 4;
    private final String dataName[] = {"Blank", "Topography", "Plume Concentration", "Colorado Temperature"};
    private final java.awt.Cursor defCursor = new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR);
    private final java.awt.Cursor waitCursor = new java.awt.Cursor(java.awt.Cursor.WAIT_CURSOR);


    /** Creates new form LRPanel */
    public RBPanel(javax.swing.JFrame parent) {
        this.parentFrame = parent;

        // Set initial values.
        mse = 0.0;
        dataX = new Vector();
        dataY = new Vector();
        dataZ = new Vector();
        x = new double[2];
        y = new double[2];
        z = new double[2];

        initComponents();
        setPreferredSize(new java.awt.Dimension(parent.getSize().width, (int)(0.85*parent.getSize().height)));
        jButtonGenerate.addActionListener(this);
        jButtonEnter.addActionListener(this);
        jButtonReset.addActionListener(this);

        addDataButtons();
        setChart();
        jPanelChartMain.setPreferredSize(new java.awt.Dimension(parent.getSize().width, (int)(0.66*parent.getSize().height)));
        getData();
        update();
    }

    private void setChart() {
        chart = jPanelChartMain.getChart();
        axis = new AxisXY(chart);
        axis.setViewport(0.12,0.8,0.1,0.88);

        // Set axes ranges
        axis.getAxisX().setAutoscaleInput(AxisXY.AUTOSCALE_OFF);
        axis.getAxisY().setAutoscaleInput(AxisXY.AUTOSCALE_OFF);
        axis.getAxisX().setWindow(0.0, 50.0);
        axis.getAxisY().setWindow(0.0, 75.0);
        axis.getAxisX().setTextFormat(new java.text.DecimalFormat("###.##"));
        axis.getAxisY().setTextFormat(new java.text.DecimalFormat("###.##"));

        // Add MouseListeren to the chart.
        jPanelChartMain.addMouseListener(this);

        Chart sideChart = jPanelChartSide.getChart();
        sideChart.setFillType(Data.FILL_TYPE_GRADIENT);
        sideChart.setGradient(light, light, dark, dark);
    }

    // add the available data sets to the dataMenu
    private void addDataButtons() {
        jRadioButtons = new javax.swing.JRadioButtonMenuItem[numData];
        javax.swing.ButtonGroup group = new javax.swing.ButtonGroup();

        for (int i=0; i<numData; i++) {
            jRadioButtons[i] = new javax.swing.JRadioButtonMenuItem();
            jRadioButtons[i].setText(dataName[i]);

            jRadioButtons[i].addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    getData();
                    update();
                }
            });

            group.add(jRadioButtons[i]);
            ((FittingMain)parentFrame).getDataMenu().add(jRadioButtons[i]);
        }
        jRadioButtons[1].setSelected(true);
    }

    // clear and load data sets determined by the menu selection
    public void getData() {
        dataX.clear();
        dataY.clear();
        dataZ.clear();
        xRange = new double[2];
        yRange = new double[2];
        zRange = new double[2];
        String xTitle = "";
        String yTitle = "";
        String zTitle = "";
        int zTickMajor = 5;
        int zTickMinor = 1;
        int selected = -1;
        for (int i=0; i<numData; i++) {
            if (jRadioButtons[i].isSelected()) {
                selected = i;
                break;
            }
        }
        switch (selected) {
            case 0: // blank
                xTitle = "X Value";
                yTitle = "Y Value";
                zTitle = "";
                xRange[0] = 0.0;
                xRange[1] = 50.0;
                yRange[0] = 0.0;
                yRange[1] = 50.0;
                zRange[0] = 0.0;
                zRange[1] = 50.0;
                break;
            case 2: /* plume concentration
                     *
                     */
                double x[] = {-30,-24,-18,-12,-6,0,6,12,18,24,30,-30,-24,-18,-12,-6,0,6,12,18,24,30,-30,-24,-18,-12,-6,0,6,12,18,24,30,-30,-24,-18,-12,-6,0,6,12,18,24,30,-30,-24,-18,-12,-6,0,6,12,18,24,30,-30,-24,-18,-12,-6,0,6,12,18,24,30,-24,-18,-12,-6,0,6,12,18,24,-30,-24,-18,-12,-6,0,6,12,18,24,30,-30,-24,-18,-12,-6,0,6,12,18,24,30,-30,-24,-18,-12,-6,0,6,12,18,24,30};
                double y[] = {46,46,46,46,46,46,46,46,46,46,46,52,52,52,52,52,52,52,52,52,52,52,58,58,58,58,58,58,58,58,58,58,58,64,64,64,64,64,64,64,64,64,64,64,70,70,70,70,70,70,70,70,70,70,70,76,76,76,76,76,76,76,76,76,76,76,82,82,82,82,82,82,82,82,82,88,88,88,88,88,88,88,88,88,88,88,94,94,94,94,94,94,94,94,94,94,94,100,100,100,100,100,100,100,100,100,100,100};
                double z[] = {0,0,0,0.008103115,0.013900935,0.003619315,0.013900935,0.008103115,0,0,0,0,0,0.013083178,0.027365109,0.03181028,0.006929283,0.03181028,0.027365109,0.013083178,0,0,0,0.008681308,0.023371028,0.031588785,0.039390343,0.011635826,0.039390343,0.031588785,0.023371028,0.008681308,0,0.004919626,0.008167601,0.022924611,0.029348598,0.042998442,0.016685981,0.042998442,0.029348598,0.022924611,0.008167601,0.004919626,0.004981308,0.00882648,0.021449221,0.025684112,0.036566355,0.020574143,0.036566355,0.025684112,0.021449221,0.00882648,0.004981308,0.005433645,0.007045794,0.019802181,0.022018692,0.026570093,0.021243925,0.026570093,0.022018692,0.019802181,0.007045794,0.005433645,0.00610405,0.013904673,0.016543302,0.021547352,0.020204984,0.021547352,0.016543302,0.013904673,0.00610405,0,0.004276012,0.010677614,0.010108411,0.016629283,0.01626729,0.016629283,0.010108411,0.010677614,0.004276012,0,0,0,0.00712648,0.006494393,0.009508411,0.008309346,0.009508411,0.006494393,0.00712648,0,0,0,0,0,0,0.007291589,0.003783801,0.007291589,0,0,0,0};
                for (int i=0; i<x.length; i++) {
                    dataX.add(new Double(x[i]));
                    dataY.add(new Double(y[i]));
                    dataZ.add(new Double(z[i]*1000));
                }
                xTitle = "Width, cm";
                yTitle = "Height, cm";
                zTitle = "Concentration, gm/cc";
                xRange[0] = -30.0;
                xRange[1] = 30.0;
                yRange[0] = 46.0;
                yRange[1] = 100.0;
                zRange[0] = 0.0;
                zRange[1] = 50;
                break;
            case 1: /* These data are topography data from an oil field.
                     */
                double x2[] = {1,2,4,7,8,10,14,14,18,22,23,23,30,35,37,41,42,44};
                double y2[] = {43,7,24,48,36,11,1,43,26,8,18,39,27,47,20,42,30,4};
                double z2[] = {36.6631,41.7752,42.7543,36.4728,38.0706,43.1325,42.2735,37.5282,38.9239,37.4302,36.1548,34.9149,35.8765,32.6606,34.6344,32.9266,33.6234,32.2425};
                for (int i=0; i<x2.length; i++) {
                    dataX.add(new Double(x2[i]));
                    dataY.add(new Double(y2[i]));
                    dataZ.add(new Double(z2[i]));
                }
                xTitle = "X location";
                yTitle = "Y location";
                zTitle = "Elevation, m";
                xRange[0] = 0.0;
                xRange[1] = 45.0;
                yRange[0] = 0.0;
                yRange[1] = 50.0;
                zRange[0] = 35.0;
                zRange[1] = 45.0;
                zTickMajor = 1;
                zTickMinor = 0;
                break;
            case 3: /* These are average summer temperature in CO
                     */
                double x3[] = {40.00,38.42,39.22,38.82,39.25,37.67,39.63,37.28,38.48,40.58,40.22,39.17,38.53,37.77,38.05,38.08,38.07,37.17,38.48,38.03,38.08,40.50,37.95,37.17,40.07};
                double y3[] = {105.27,105.23,105.28,102.35,107.97,106.35,106.03,107.88,102.78,105.08,103.80,108.75,106.97,107.13,102.12,102.62,103.22,105.95,107.88,103.70,106.13,106.83,107.87,104.48,102.23};
                double z3[] = {35.52,38.76,30.86,33.92,28.78,26.84,21.03,31.72,35.41,32.97,34.89,31.93,20.31,20.79,32.77,35.42,37.00,28.48,30.60,36.26,29.60,19.00,22.65,37.66,35.34};
                for (int i=0; i<x3.length; i++) {
                    dataX.add(new Double(x3[i]));
                    dataY.add(new Double(y3[i]));
                    dataZ.add(new Double(z3[i]));
                }
                xTitle = "Latitude";
                yTitle = "Longitude";
                zTitle = "Average Winter Temperature, °F";
                xRange[0] = 37.0;
                xRange[1] = 41.0;
                yRange[0] = 102.0;
                yRange[1] = 110.0;
                zRange[0] = 15.0;
                zRange[1] = 40.0;
                zTickMajor = 5;
                break;
        }
        axis.getAxisX().getAxisTitle().setTitle(xTitle);
        axis.getAxisY().getAxisTitle().setTitle(yTitle);
        axis.getAxisX().setWindow(xRange);
        axis.getAxisY().setWindow(yRange);
        chart.getChartTitle().setTitle(zTitle);

        zSlider.setMinimum((int)zRange[0]);
        zSlider.setMaximum((int)zRange[1]);
        zSlider.setValue((int)(zRange[1]+zRange[0])/2);
        zSlider.setMajorTickSpacing(zTickMajor);
        zSlider.setMinorTickSpacing(zTickMinor);
    }

    // Draw the graph.
    private void drawGraph() {
        if ((dataX.size() != 0) && (dataY.size() != 0)) {
            x = new double[dataX.size()];
            y = new double[dataY.size()];
            z = new double[dataZ.size()];

            for (int i = 0; i < x.length; i++) {
                x[i] = ((Double) dataX.get(i)).doubleValue();
                y[i] = ((Double) dataY.get(i)).doubleValue();
                z[i] = ((Double) dataZ.get(i)).doubleValue();
            }

            // Draw the contour graph
            if (x.length > 1) {
                double[] cLevels = new double[10];
                for (int i=0; i<cLevels.length; i++) {
                    cLevels[i] = (double)i*(zRange[1]-zRange[0])/10.0 + zRange[0];
                }
                int nCenters = x.length/2;
                contour = new Contour(axis, x, y, z, cLevels, nCenters);
                contour.getContourLegend().setPaint(true);

                contour.getContourLevel(0).setFillColor(new java.awt.Color(43,0,0));
                contour.getContourLevel(1).setFillColor(new java.awt.Color(64,23,21));
                contour.getContourLevel(2).setFillColor(new java.awt.Color(85,47,43));
                contour.getContourLevel(3).setFillColor(new java.awt.Color(106,70,64));
                contour.getContourLevel(4).setFillColor(new java.awt.Color(127,94,86));
                contour.getContourLevel(5).setFillColor(new java.awt.Color(148,118,107));
                contour.getContourLevel(6).setFillColor(new java.awt.Color(170,141,129));
                contour.getContourLevel(7).setFillColor(new java.awt.Color(191,165,150));
                contour.getContourLevel(8).setFillColor(new java.awt.Color(212,188,172));
                contour.getContourLevel(9).setFillColor(new java.awt.Color(233,212,193));
                contour.getContourLevel(10).setFillColor(new java.awt.Color(255,236,215));
            }

            // Draw the points.
            point = new Data(axis, x, y);
            point.setDataType(Data.DATA_TYPE_MARKER);
            point.setMarkerType(Data.MARKER_TYPE_OCTAGON_X);
            point.setMarkerSize(0.8);
            point.setMarkerColor(java.awt.Color.blue);
        }
    }

    // Redraw the chart.
    public void update() {
        setCursor(waitCursor);
        if (point != null) point.remove();
        if (contour != null) {
            contour.getContourLegend().remove();
            contour.remove();
        }
        drawGraph();
        setCursor(defCursor);
        if (showSurface) plotSurface();
        repaint();
    }

    public void setVisible(boolean show) {
        super.setVisible(show);
        if (show) {
            addDataButtons();
            if (surfacePlot == null) {
                surfacePlot = new SurfacePlot(parentFrame, jCheck3d);
            } else {
                if (showSurface) {
                    surfacePlot.setVisible(true);
                }
            }
        } else {
            if (surfacePlot != null) {
                surfacePlot.setVisible(false);
            }
        }
    }


    private void plotSurface() {
        if (!surfacePlot.isVisible()) surfacePlot.show();
        // note that x,y,z are defined in drawGraph()
        surfacePlot.draw(x, y, z);
    }



    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {//GEN-BEGIN:initComponents
        jPanel = new javax.swing.JPanel();
        jButtonEnter = new javax.swing.JButton();
        jButtonGenerate = new javax.swing.JButton();
        jLabelPoints = new javax.swing.JLabel();
        numField = new javax.swing.JTextField("6", 4);
        jButtonReset = new javax.swing.JButton();
        jPanelChartMain = new com.imsl.chart.JPanelChart();
        jPanelZ = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        zSlider = new javax.swing.JSlider();
        jPanelChartSide = new com.imsl.chart.JPanelChart();

        setLayout(new java.awt.BorderLayout());

        setPreferredSize(new java.awt.Dimension(500, 600));
        jButtonEnter.setText("Enter Points");
        jPanel.add(jButtonEnter);

        jButtonGenerate.setText("Generate");
        jPanel.add(jButtonGenerate);

        jLabelPoints.setText("# of Points: ");
        jPanel.add(jLabelPoints);

        numField.setColumns(4);
        numField.setText("6");
        jPanel.add(numField);

        jButtonReset.setText("Reset");
        jPanel.add(jButtonReset);

        jCheck3d = new javax.swing.JCheckBox();
        jCheck3d.setSelected(false);
        jCheck3d.setText("Show 3D Surface");
        jCheck3d.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                showSurface = jCheck3d.isSelected();
                if ((!showSurface) && (surfacePlot.isVisible())) {
                    surfacePlot.setVisible(false);
                }
                if (showSurface) {
                    plotSurface();
                }
            }
        });
        jPanel.add(jCheck3d);

        add(jPanel, java.awt.BorderLayout.NORTH);

        jPanelChartMain.setPreferredSize(new java.awt.Dimension(500, 500));
        add(jPanelChartMain, java.awt.BorderLayout.CENTER);

        jPanelZ.setLayout(new java.awt.BorderLayout());

        jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel1.setText("Z Value");
        jPanelZ.add(jLabel1, java.awt.BorderLayout.NORTH);

        zSlider.setMajorTickSpacing(5);
        zSlider.setMinorTickSpacing(1);
        zSlider.setOrientation(javax.swing.JSlider.VERTICAL);
        zSlider.setPaintLabels(true);
        zSlider.setPaintTicks(true);
        zSlider.setSnapToTicks(true);
        jPanelZ.add(zSlider, java.awt.BorderLayout.CENTER);

        jPanelZ.add(jPanelChartSide, java.awt.BorderLayout.WEST);

        add(jPanelZ, java.awt.BorderLayout.EAST);

    }//GEN-END:initComponents

    // Implement ActionListener
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("Enter Points")) {
            // Enter points using a text area.
            javax.swing.JTextArea textArea = new javax.swing.JTextArea(10, 5);
            javax.swing.JScrollPane scroll = new javax.swing.JScrollPane(textArea);

            int option = 0;
            try {
                option = javax.swing.JOptionPane.showConfirmDialog(this, scroll,
                    "Enter Points", javax.swing.JOptionPane.OK_CANCEL_OPTION);
                if (option == javax.swing.JOptionPane.CANCEL_OPTION) return;
            } catch (Exception ex) {
            }

            java.util.StringTokenizer lineToken =
                new java.util.StringTokenizer(textArea.getText(), "\n");
            while (lineToken.hasMoreElements()) {
                java.util.StringTokenizer token = new java.util.StringTokenizer(lineToken.nextToken(), "(){}[] ,\t\n");
                // If the line does not contain 3 numbers, then ignore.
                if (token.countTokens() == 3) {
                    try {
                        double x = Double.parseDouble(token.nextToken());
                        double y = Double.parseDouble(token.nextToken());
                        double z = Double.parseDouble(token.nextToken());

                        // Ignore any points that are not in the range.
                        if ((x >= xRange[0]) && (x <= xRange[1]) &&
                            (y >= yRange[0]) && (y <= yRange[1])) {
                            dataX.add(new Double(x));
                            dataY.add(new Double(y));
                            dataZ.add(new Double(z));
                        }
                    } catch (Exception ex) {
                    }
                }
            }
            update();
        } else if (e.getActionCommand().equals("Generate")) {
            int i = 0;
            try {
                i = Integer.parseInt(numField.getText());
            } catch (Exception exception) {
                i = 6;
                numField.setText("6");
            } finally {
                if (i <= 0) {
                    i = 6;
                    numField.setText("6");
                }
                for (int j = 0; j < i; j++) {
                    dataX.add(new Double(xRange[1] * Math.random() + xRange[0]));
                    dataY.add(new Double(yRange[1] * Math.random() + yRange[0]));
                    dataZ.add(new Double(zRange[1] * Math.random() + zRange[0]));
                }
                update();
            }
        } else {
            // Reset button is clicked.  Reset everything to default.
            numField.setText("6");
            mse = 0.0;
            dataX = new Vector();
            dataY = new Vector();
            dataZ = new Vector();
            update();
            getData();
            update();
        }
    }

    // Implement ChangeListener
    public void stateChanged(ChangeEvent e) {
        update();
    }

    // Implement MouseListener
    public void mouseClicked(MouseEvent e) {
        double user[] = {0,0};
        axis.mapDeviceToUser(e.getX(), e.getY(), user);

        // Do not add the point if it is not in the range.
        if ((user[0] < xRange[0]) || (user[0] > xRange[1]) ||
            (user[1] < yRange[0]) || (user[1] > yRange[1])) return;

        // Button is to add points.  Otherwise, remove points.
        if (e.getModifiers() == MouseEvent.BUTTON1_MASK) {
            dataX.add(new Double(user[0]));
            dataY.add(new Double(user[1]));
            dataZ.add(new Double(zSlider.getValue()));
            update();
        } else {
            int idx = -1;
            double min = 0.01;
            final double ux = (user[0]-xRange[0])/(double)(xRange[1]-xRange[0]);
            final double uy = (user[1]-yRange[0])/(double)(yRange[1]-yRange[0]);

            for (int i = 0; i < dataX.size(); i++) {
                double x = (((Double)dataX.get(i)).doubleValue()-xRange[0])/
                            (double)(xRange[1]-xRange[0]);
                double y = (((Double)dataY.get(i)).doubleValue()-yRange[0])/
                            (double)(yRange[1]-yRange[0]);
                double dist = Math.sqrt((ux - x)*(ux - x) + (uy - y)*(uy - y));

                if (dist < min) {
                    min = dist;
                    idx = i;
                }
            }

            if (idx != -1) {
                dataX.remove(idx);
                dataY.remove(idx);
                dataZ.remove(idx);
                update();
            }
        }
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabelPoints;
    private javax.swing.JButton jButtonGenerate;
    private javax.swing.JButton jButtonReset;
    private javax.swing.JTextField numField;
    private javax.swing.JSlider zSlider;
    private com.imsl.chart.JPanelChart jPanelChartMain;
    private javax.swing.JPanel jPanelZ;
    private javax.swing.JButton jButtonEnter;
    private com.imsl.chart.JPanelChart jPanelChartSide;
    private javax.swing.JPanel jPanel;
    // End of variables declaration//GEN-END:variables
}