/*
 * CorrelationRegressionDialog.java
 *
 * Created on July 8, 2008, 2:43 PM
 */

package org.statcato.dialogs.stat.correg;

import org.statcato.*;
import org.statcato.spreadsheet.*;
import org.statcato.utils.HelperFunctions;
import org.statcato.utils.NumDataset;
import org.statcato.statistics.inferential.*;
import org.statcato.graph.GraphFactory;

import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.chart.*;

import java.util.*;

/**
 * A dialog for linear correlation and regression between two variables.
 * Allows the user to specify the independent and dependent variable and
 * significance level.  Computes linear correlation coefficient, 
 * critical value, p-Value, regression equation, explained, unexplained
 * and total variations, coefficient of determination, and standard error
 * of estimate.  Displays results in the log window.
 * 
 * @author  Margaret Yau
 * @version %I%, %G%
 * @see org.statcato.statistics.inferential.CorrelationRegression
 * @since 1.0
 */
public class CorrelationRegressionDialog extends StatcatoDialog {

    /** Creates new form CorrelationRegressionDialog */
    public CorrelationRegressionDialog(java.awt.Frame parent, boolean modal,
            Statcato app) {
        super(parent, modal);
        this.app = app;
        ParentSpreadsheet = app.getSpreadsheet(); 
      
        initComponents();
        customInitComponents();    
        setHelpFile("stat-reg-two-variables");
        name = "Correlation and Regression";
        description = "For performing computations that determine the " +
                "correlation and regression between two variables. ";
        helpStrings.add("Select the columns containing data values for " +
                "the input variables. Control-click to select multiple variables. " +
                "");
        helpStrings.add("A correlation and regression analysis is done for " +
                "each pair of variables.");
        helpStrings.add("Enter the significance level of the hypothesis test for correlation.");
        helpStrings.add("Select the Show a scatterplot for all pairs of data " +
                "values check box to display a scatter plot " +
                "showing data values in each pair of input variables.");
    }

    /**
     * Updates elements on the dialog so that they have the most
     * current values.  Called by {@link #setVisible} to make
     * sure the dialog displays current values when made visible again.
     * 
     * @see #setVisible(boolean)
     */
    @Override
    public void updateElements() {
        updateColumnsList(InputVarList); 
    }
    
    public void customInitComponents() {  
        ParentSpreadsheet.populateColumnsList(InputVarList);     
        GraphPanel.setVisible(false);
        getRootPane().setDefaultButton(OKButton);
        pack();
    }
    
    /** 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.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        OKButton = new javax.swing.JButton();
        CancelButton = new javax.swing.JButton();
        jPanel1 = new javax.swing.JPanel();
        jLabel2 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        InputVarList = new javax.swing.JList();
        jLabel1 = new javax.swing.JLabel();
        jPanel2 = new javax.swing.JPanel();
        jLabel6 = new javax.swing.JLabel();
        SigTextField = new javax.swing.JTextField();
        GraphCheckBox = new javax.swing.JCheckBox();
        GraphPanel = new javax.swing.JPanel();
        jLabel7 = new javax.swing.JLabel();
        jLabel8 = new javax.swing.JLabel();
        LegendCheckBox = new javax.swing.JCheckBox();
        YTextField = new javax.swing.JTextField();
        TitleTextField = new javax.swing.JTextField();
        XTextField = new javax.swing.JTextField();
        jLabel5 = new javax.swing.JLabel();
        LineCheckBox = new javax.swing.JCheckBox();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Correlation and Regression");

        OKButton.setText("OK");
        OKButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                OKButtonActionPerformed(evt);
            }
        });

        CancelButton.setText("Cancel");
        CancelButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                CancelButtonActionPerformed(evt);
            }
        });

        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Inputs"));

        jLabel2.setText("<html><b>Column variables:</b><br>Ctrl+click to select multiple column variables</html>");

        jScrollPane1.setViewportView(InputVarList);

        jLabel1.setText("Analysis is done for each pair of input variables.");

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGap(18, 18, 18)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel1)
                    .addComponent(jLabel2)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(40, Short.MAX_VALUE))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 141, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addComponent(jLabel1)
                .addContainerGap(19, Short.MAX_VALUE))
        );

        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Significance"));

        jLabel6.setText("Significance level:");

        SigTextField.setText("0.05");

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel6)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(SigTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(108, Short.MAX_VALUE))
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel6)
                    .addComponent(SigTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );

        GraphCheckBox.setText("Show a scatterplot for all pairs of data values");
        GraphCheckBox.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                GraphCheckBoxStateChanged(evt);
            }
        });

        GraphPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Graph Options"));

        jLabel7.setText("Plot Title:");

        jLabel8.setText("X-axis Label:");

        LegendCheckBox.setSelected(true);
        LegendCheckBox.setText("Show legend");

        YTextField.setText("y");

        TitleTextField.setText("Scatterplot");

        XTextField.setText("x");

        jLabel5.setText("Y-axis Label:");

        LineCheckBox.setSelected(true);
        LineCheckBox.setText("Show regression line");

        javax.swing.GroupLayout GraphPanelLayout = new javax.swing.GroupLayout(GraphPanel);
        GraphPanel.setLayout(GraphPanelLayout);
        GraphPanelLayout.setHorizontalGroup(
            GraphPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(GraphPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(GraphPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(LineCheckBox)
                    .addGroup(GraphPanelLayout.createSequentialGroup()
                        .addGroup(GraphPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel5)
                            .addComponent(jLabel7))
                        .addGap(18, 18, 18)
                        .addGroup(GraphPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(TitleTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE)
                            .addComponent(YTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE)))
                    .addGroup(GraphPanelLayout.createSequentialGroup()
                        .addComponent(jLabel8)
                        .addGap(18, 18, 18)
                        .addComponent(XTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE))
                    .addGroup(GraphPanelLayout.createSequentialGroup()
                        .addComponent(LegendCheckBox)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 191, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        GraphPanelLayout.setVerticalGroup(
            GraphPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(GraphPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(GraphPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel8)
                    .addComponent(XTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(GraphPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel5)
                    .addComponent(YTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(GraphPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel7)
                    .addComponent(TitleTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(LegendCheckBox)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(LineCheckBox)
                .addContainerGap(17, Short.MAX_VALUE))
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(GraphCheckBox)
                            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                                .addComponent(GraphPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(88, 88, 88)
                        .addComponent(OKButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(CancelButton)))
                .addContainerGap(23, Short.MAX_VALUE))
        );

        layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {CancelButton, OKButton});

        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(28, 28, 28)
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addComponent(GraphCheckBox)
                .addGap(10, 10, 10)
                .addComponent(GraphPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 19, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(OKButton)
                    .addComponent(CancelButton))
                .addGap(25, 25, 25))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void OKButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_OKButtonActionPerformed
        app.compoundEdit = new DialogEdit("correlation & regression");
        
        double significance = 0;
        Vector<Double> xVector = null, yVector = null;
        String heading = "Correlation and Regression:";
        String text = "";
        
        // get confidence level from dialog
        try {
            significance = Double.parseDouble(SigTextField.getText());
        } catch (NumberFormatException e) {
            app.showErrorDialog("Enter a number between 0 and 1 for the confidence level.");
            return;
        }
        if (significance <= 0 || significance >= 1) {
            app.showErrorDialog("Enter a number between 0 and 1 for the confidence level.");
            return;
        }        
        heading += "  Significance level = " + significance;
        
        // get selected input variables
        Object[] SelectedColumns = InputVarList.getSelectedValues();
        int[] columnNumbers = ParentSpreadsheet.convertColumnLabelsToNumbers(SelectedColumns);
        
        // check that at least one input variable is selected
        if (columnNumbers.length < 2) {
            app.showErrorDialog("Select at least two input variables.");
            return;
        }
        
        // build dataset
        NumDataset dataset = new NumDataset();
        XYSeriesCollection seriesCollection = new XYSeriesCollection();
            
        text += "Input variables: ";
        for (int i = 0; i < columnNumbers.length; ++i) {
            Vector<Cell> StrColumnVector = ParentSpreadsheet.getColumn(columnNumbers[i]);
            String columnLabel = (String) SelectedColumns[i];
            text += columnLabel + " ";
            // get input column of doubles
            Vector<Double> ColumnVector = HelperFunctions.ConvertInputVectorToDoubles(StrColumnVector);
            ColumnVector = HelperFunctions.removeNullValues(ColumnVector);
            if (ColumnVector == null) {
                app.showErrorDialog("Invalid input column " + columnLabel +
                    ": all data must be numbers.");
                return;
            }
            
            dataset.add(ColumnVector, columnLabel);            
        }
        
        // compute results
        text += "<br>The row variables are the independent variables," +
                "and the column variables are the dependent variables.<br>";
        Vector<Vector<Double>> data = dataset.getValues();
        Vector<String> labels = dataset.getLabels();
        text += "<table border='1'>";
        text += "<tr><td>&nbsp;</td>";
        for (int i = 0; i < data.size(); ++i) {
            text += "<td>" + labels.elementAt(i) + "</td>";
        }        
        text += "</tr>";
        double min = 0, max = 0;
        for (int i = 0; i < data.size(); ++i) {
            text += "<tr><td>" + labels.elementAt(i) + "</td>";
           
            for (int j = 0; j < data.size(); ++j) {
                if (i == j) {
                    text += "<td>&nbsp;</td>";
                }
                else {
                    text += "<td>";
                    xVector = data.elementAt(i);
                    yVector = data.elementAt(j);
                    if (xVector.size() != yVector.size()) {
                        app.showErrorDialog("Each pair of variables must have the same " +
                                "number of values.");
                        return;
                    }

                    CorrelationRegression CG = new CorrelationRegression(
                            xVector, yVector, significance);
                    text += CG + "</td>";       
                    
                    // create new series for graph
                    XYSeries series = new XYSeries(labels.elementAt(i) + "," +
                        labels.elementAt(j));
                    for (int k = 0; k < xVector.size(); ++k) {
                        double x = xVector.elementAt(k).doubleValue();
                        if (x < min)
                            min = x;
                        if (x > max)
                            max = x;
                        series.add(x,
                                yVector.elementAt(k).doubleValue());
                    }      
                    seriesCollection.addSeries(series);
                }
            
            }
            text += "</tr>";
        }
        text += "</table>";
     
        app.addLogParagraph(heading, text);

        // create scatterplot
        if (GraphCheckBox.isSelected()) {
            JFreeChart chart = GraphFactory.createScatterplot(
                    seriesCollection, 
                    TitleTextField.getText(), 
                    XTextField.getText(), 
                    YTextField.getText(), 
                    LegendCheckBox.isSelected(), 
                    LineCheckBox.isSelected(),
                    min, 
                    max);        
            StatcatoChartFrame frame = 
                    new StatcatoChartFrame(TitleTextField.getText(), chart, app);
            frame.pack();
            frame.setVisible(true);
        }
        
        app.compoundEdit.end();
        app.addCompoundEdit(app.compoundEdit);
        
        setVisible(false);
    }//GEN-LAST:event_OKButtonActionPerformed

    private void CancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CancelButtonActionPerformed
        setVisible(false);
    }//GEN-LAST:event_CancelButtonActionPerformed

    private void GraphCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_GraphCheckBoxStateChanged
        if (GraphCheckBox.isSelected()) {
            GraphPanel.setVisible(true);
            pack();
        }
        else {
            GraphPanel.setVisible(false);
            pack();
        }
}//GEN-LAST:event_GraphCheckBoxStateChanged
    
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton CancelButton;
    private javax.swing.JCheckBox GraphCheckBox;
    private javax.swing.JPanel GraphPanel;
    private javax.swing.JList InputVarList;
    private javax.swing.JCheckBox LegendCheckBox;
    private javax.swing.JCheckBox LineCheckBox;
    private javax.swing.JButton OKButton;
    private javax.swing.JTextField SigTextField;
    private javax.swing.JTextField TitleTextField;
    private javax.swing.JTextField XTextField;
    private javax.swing.JTextField YTextField;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    // End of variables declaration//GEN-END:variables
    
}
