/*
 * FunctionPanel.java
 *
 * Created on March 10, 2006, 3:38 PM
 */

package cz.pcland.functions;
import cz.pcland.ga.PopulationType;
import cz.pcland.ga.crossover.CrossoverOpearator;
import cz.pcland.ga.crossover.SimpleCrossover;
import cz.pcland.ga.crossover.UniformCrossover;
import cz.pcland.ga.crossover.twoPointCrossover;
import cz.pcland.ga.fitness.BaseFunctionFitness;
import cz.pcland.ga.fitness.Evaluator;
import cz.pcland.ga.fitness.FunctionFitnessGray;
import cz.pcland.ga.fitness.FunctionFitnessNaive;
import cz.pcland.gavisualization.*;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import cz.pcland.functions.lexan.*;
import cz.pcland.functions.nodes.*;
import cz.pcland.functions.syntax.*;
import cz.pcland.ga.*;

/**
 *
 * @author  Petr Benhak
 * @version 1.3
 */
public class FunctionPanel extends BaseProblemPanel {
    DefaultListModel dlmInfo = new DefaultListModel();
    DefaultListModel dlmExpr = new DefaultListModel();
    DefaultListModel dlmErrors = new DefaultListModel();
    
    int selected = 0;
    
    Vector instances = new Vector();
    FunctionInstance instanceToSolve;
    
   // int precision = 30;
    
    /** Creates new form FunctionPanel */
    public FunctionPanel(MainApplet3 parent) {
        super(parent);
        initComponents();
       
        
        addInstance("sin(x)*x", -10, 10,30);
        addInstance("-(x^2)", -10, 10,30);
        addInstance("log(x)", 0, 10,30);
        //String.valueOf(this.precision)
        this.lstFunctions.setSelectedIndex(selected);
        //   this.lstFunctions.setModel(this.dlmExpr);
    }
    
    /**
     * This method is called from main form to select visualization mode.
     */
    public void visualizeFitness() {
        this.panelVisualization = new GAVisualizationFitness(10,10, "Fitness");
        this.jTabbedPane1.setComponentAt(3, panelVisualization);
        this.pnlVisualization = panelVisualization;
        //panelVisualization.setGAConfig(this.GAConfig);
        panelVisualization.updateGraph(infoData);
    }
    
    /**
     * This method is called from main form to select visualization mode.
     */
    public void visualizeRank() {
        this.panelVisualization = new GAVisualizationEvaluation(10,10, "Function value");
        this.jTabbedPane1.setComponentAt(3, panelVisualization);
        this.pnlVisualization = panelVisualization;
        //panelVisualization.setGAConfig(this.GAConfig);
        panelVisualization.updateGraph(infoData);
    }
    
    /**
     * Creates abstract syntax tree of given expression and function instance as well.
     * This instance is added to the list of instances
     * @param function Funtion string
     * @param from drawing from this value
     * @param to Drawing to this value
     * @param resolution Number of bits used for discretization
     */
    public void addInstance(String function, int from, int to, int resolution){
        try{
            Syntax s = new Syntax();
            Node node = s.startAnalysis(function,dlmInfo,dlmExpr);
            FunctionInstance fi = new FunctionInstance(node, from,to, "x", resolution);
            this.instances.add(fi);
            updateFunctionList();
        }catch(ParseErrorException e){
            JOptionPane.showMessageDialog(this,"Parse error:  " + e.getMessage());
        }
        
    }
    
    
    /**
     * @return list of available evaluators specific for selected problem.
     */
    public Evaluator[] getEvaluators() {
        Evaluator[] ret = {new FunctionFitnessNaive(), new FunctionFitnessGray()};
        return ret;
    }
    
    /**
     * @return list of available crossover operators specific for selected problem.
     */
    public CrossoverOpearator[] getCrossoverOperators() {
        CrossoverOpearator[] ret = {new SimpleCrossover(), new twoPointCrossover(), new UniformCrossover()};
        return ret;
    }
    
    /**
     * Button start or steps was pressed. User must call start method to start GA.
     */
    public Object run(boolean steps) {
      
        selected = this.lstFunctions.getSelectedIndex();
        if(selected == -1)selected = 0;
        
        if(this.lstFunctions.getModel().getSize() == 0) {
            JOptionPane.showMessageDialog(null, "You must add at least one instance to be solved !");
            parent.btnSteps.setEnabled(true);
            parent.btnStart.setEnabled(true);
            parent.btnCancel.setEnabled(false);
            return "Nothing done ...";
        }
        
        instanceToSolve = ((FunctionInstance)instances.get(selected));
        ((GraphPanel)this.pnlGraph).setInstance(instanceToSolve);

        initWorker(((BaseVisualization)this.pnlVisualization), this.lstProgress, PopulationType.BINARY, steps, instanceToSolve);
        return start(1);
    }
    
    
     public void onDoWorkBegin() {
        
     }
    
    /**
     * Called whenever new population is created. That coresponds to button start pressed.
     */
    public void onInitBegin() {
        this.setStrLen(this.instanceToSolve.precision);
    }
    
    public void onInitEnd() {
        ((GraphPanel)this.pnlGraph).setPopulation(population);
    }
    
    /**
     * Called whenever GA invoked. That coresponds to button start or step pressed.
     */
    public void onDoWorkRunBegin() {
        
    }
    
    public void finish(){
        ((GraphPanel)this.pnlGraph).repaint();
    }
    
    /**
     * Called whenever GA ends.
     */
    public void onDoWorkEnd() {
        updateFunctionList();
        this.lstFunctions.setSelectedIndex(selected);
    }
    
    public void onProgress() {
        ((GraphPanel)this.pnlGraph).repaint();
    }
    
    public void onDoWorkStepsBegin() {
        
    }
    
    public void updateInfoList(){
        Runnable doSetData = new Runnable() {
            public void run() {
                lstProgress.setListData(infoData);
            }
        };
        SwingUtilities.invokeLater(doSetData);
    }
    
    
    public void updateFunctionList() {
        Runnable doSetData = new Runnable() {
            public void run() {
                lstFunctions.setListData(instances);
            }
        };
        SwingUtilities.invokeLater(doSetData);
    }
    
    
    /** 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() {
        java.awt.GridBagConstraints gridBagConstraints;

        jTabbedPane1 = new javax.swing.JTabbedPane();
        jPanel1 = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        lstProgress = new javax.swing.JList();
        jPanel2 = new javax.swing.JPanel();
        inputFunction = new javax.swing.JTextField();
        jButton1 = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        lstFunctions = new javax.swing.JList();
        jButton2 = new javax.swing.JButton();
        jLabel1 = new javax.swing.JLabel();
        inputFrom = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        inputTo = new javax.swing.JTextField();
        jButton3 = new javax.swing.JButton();
        jLabel3 = new javax.swing.JLabel();
        inputResolution = new javax.swing.JTextField();
        jPanel4 = new javax.swing.JPanel();
        pnlGraph = new GraphPanel();
        jPanel3 = new javax.swing.JPanel();
        pnlVisualization = new GAVisualizationEvaluation(15,15, "Function value");

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

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

        jScrollPane2.setViewportView(lstProgress);

        jPanel1.add(jScrollPane2, java.awt.BorderLayout.CENTER);

        jTabbedPane1.addTab("Progress", jPanel1);

        jPanel2.setLayout(new java.awt.GridBagLayout());

        inputFunction.setText("sin(x)*x");
        inputFunction.setMinimumSize(new java.awt.Dimension(200, 19));
        inputFunction.setPreferredSize(new java.awt.Dimension(200, 19));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 6, 0, 0);
        jPanel2.add(inputFunction, gridBagConstraints);

        jButton1.setText("Add function");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(9, 10, 10, 0);
        jPanel2.add(jButton1, gridBagConstraints);

        lstFunctions.setPreferredSize(new java.awt.Dimension(100, 0));
        lstFunctions.setSelectedIndex(0);
        jScrollPane1.setViewportView(lstFunctions);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridwidth = 9;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        jPanel2.add(jScrollPane1, gridBagConstraints);

        jButton2.setText("Remove selected");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.gridwidth = 5;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(9, 8, 10, 8);
        jPanel2.add(jButton2, gridBagConstraints);

        jLabel1.setText("from:");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 3;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 6, 0, 0);
        jPanel2.add(jLabel1, gridBagConstraints);

        inputFrom.setText("-10");
        inputFrom.setPreferredSize(new java.awt.Dimension(40, 19));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 4;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 6, 0, 0);
        jPanel2.add(inputFrom, gridBagConstraints);

        jLabel2.setText("to:");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 5;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 6, 0, 0);
        jPanel2.add(jLabel2, gridBagConstraints);

        inputTo.setText("10");
        inputTo.setPreferredSize(new java.awt.Dimension(40, 19));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 6;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 6, 0, 0);
        jPanel2.add(inputTo, gridBagConstraints);

        jButton3.setText("Preview selected");
        jButton3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton3ActionPerformed(evt);
            }
        });

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 8;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.insets = new java.awt.Insets(10, 0, 10, 8);
        jPanel2.add(jButton3, gridBagConstraints);

        jLabel3.setText("Resolution:");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 7;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 6, 0, 0);
        jPanel2.add(jLabel3, gridBagConstraints);

        inputResolution.setText("30");
        inputResolution.setPreferredSize(new java.awt.Dimension(40, 18));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 8;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 6, 0, 0);
        jPanel2.add(inputResolution, gridBagConstraints);

        jTabbedPane1.addTab("Function to maximize", jPanel2);

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

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

        pnlGraph.setBackground(new java.awt.Color(255, 255, 255));
        pnlGraph.setPreferredSize(new java.awt.Dimension(300, 10));
        jPanel4.add(pnlGraph, java.awt.BorderLayout.CENTER);

        jTabbedPane1.addTab("Function graph", jPanel4);

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

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

        jPanel3.add(pnlVisualization, java.awt.BorderLayout.CENTER);

        jTabbedPane1.addTab("Visualization", jPanel3);

        add(jTabbedPane1, java.awt.BorderLayout.CENTER);

    }// </editor-fold>//GEN-END:initComponents
        
    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
// TODO add your handling code here:
        int[] selected = this.lstFunctions.getSelectedIndices();
        if(selected.length > 0){
            for(int i=selected.length-1;i>=0;i--){
                this.instances.remove(selected[i]);
            }
            this.updateFunctionList();
        }
    }//GEN-LAST:event_jButton2ActionPerformed
    
    private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton3ActionPerformed
// TODO add your handling code here:
        if(this.lstFunctions.getSelectedValue() instanceof FunctionInstance) {
            FunctionInstance fi = (FunctionInstance)this.lstFunctions.getSelectedValue();
            ((GraphPanel)this.pnlGraph).setInstance(fi);
            this.jTabbedPane1.setSelectedIndex(2);
        }
        
    }//GEN-LAST:event_jButton3ActionPerformed
    
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
// TODO add your handling code here:
        
        String function = this.inputFunction.getText();
        try{
            int from = Integer.valueOf(this.inputFrom.getText()).intValue();
            int to = Integer.valueOf(this.inputTo.getText()).intValue();
            int resolution = Integer.valueOf(this.inputResolution.getText()).intValue();
            if(resolution > 30) {
                JOptionPane.showMessageDialog(null, "Maximum resolution is 30");
            }else {
                this.addInstance(function, from, to, resolution);
            }
        }catch(NumberFormatException e){
            System.out.println("Bad function ranges: " + e.getMessage());
        }
        
        
    }//GEN-LAST:event_jButton1ActionPerformed
    
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTextField inputFrom;
    private javax.swing.JTextField inputFunction;
    private javax.swing.JTextField inputResolution;
    private javax.swing.JTextField inputTo;
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JButton jButton3;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JList lstFunctions;
    private javax.swing.JList lstProgress;
    private javax.swing.JPanel pnlGraph;
    private javax.swing.JPanel pnlVisualization;
    // End of variables declaration//GEN-END:variables
    
}
