/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * SupervisedTrainingMonitor2.java
 *
 * Created on Jan 10, 2010, 3:31:34 PM
 */

package org.neuroph.easyneurons.dialog;

import java.util.Observable;
import java.util.Observer;
import org.jdesktop.application.Action;
import org.neuroph.easyneurons.NeuralNetworkTraining;
import org.neuroph.nnet.learning.LMS;
import javax.swing.SwingWorker;
import java.util.List;
import javax.swing.SwingWorker.StateValue;

/**
 *
 * @author zoran
 */
public class SupervisedTrainingMonitorFrame extends javax.swing.JInternalFrame implements Observer {

	NeuralNetworkTraining controller;
        boolean userPaused = false;
        TrainerSwingWorker worker;

    /** Creates new form SupervisedTrainingMonitor2 */
    public SupervisedTrainingMonitorFrame() {
        initComponents();

    }

    public SupervisedTrainingMonitorFrame(NeuralNetworkTraining controller) {
        this.controller = controller;
        initComponents();

        worker = new TrainerSwingWorker();
        worker.execute();
    }

        // update with data from learning rule
        @Override
	public void update(Observable o, Object arg) {
		LMS learningRule = (LMS) o;

                learningRule.pause();
                LearningInfo learningInfo = new LearningInfo( learningRule.getCurrentIteration(),
                                                learningRule.getTotalNetworkError());


//                if (worker.getState() == StateValue.PENDING) {
//                    worker = new TrainerSwingWorker();
//                    worker.execute();
//                }

                worker.setData(learningInfo);

                if (!userPaused) learningRule.resume();
                
                if (learningRule.isStopped()) {
                    worker.setFinished(true);
                    worker.cancel(true);
                    learningRule.deleteObserver(this);

                    stopButton.setEnabled(false);
                    pauseButton.setEnabled(false);
                    closeButton.setEnabled(true);
                } 
	}

        public void observe(Observable learningRule) {
             learningRule.addObserver(this);
        }


    /** 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.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        fieldPanel = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        totalNetErrorField = new javax.swing.JTextField();
        currentIterationField = new javax.swing.JTextField();
        buttonPanel = new javax.swing.JPanel();
        stopButton = new javax.swing.JButton();
        pauseButton = new javax.swing.JButton();
        closeButton = new javax.swing.JButton();

        setIconifiable(true);
        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(org.neuroph.easyneurons.EasyNeuronsApplication.class).getContext().getResourceMap(SupervisedTrainingMonitorFrame.class);
        setTitle(resourceMap.getString("Form.title")); // NOI18N
        setName("Form"); // NOI18N
        addInternalFrameListener(new javax.swing.event.InternalFrameListener() {
            public void internalFrameActivated(javax.swing.event.InternalFrameEvent evt) {
            }
            public void internalFrameClosed(javax.swing.event.InternalFrameEvent evt) {
            }
            public void internalFrameClosing(javax.swing.event.InternalFrameEvent evt) {
                formInternalFrameClosing(evt);
            }
            public void internalFrameDeactivated(javax.swing.event.InternalFrameEvent evt) {
            }
            public void internalFrameDeiconified(javax.swing.event.InternalFrameEvent evt) {
            }
            public void internalFrameIconified(javax.swing.event.InternalFrameEvent evt) {
            }
            public void internalFrameOpened(javax.swing.event.InternalFrameEvent evt) {
            }
        });

        fieldPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        fieldPanel.setName("fieldPanel"); // NOI18N
        fieldPanel.setLayout(new java.awt.GridBagLayout());

        jLabel1.setText(resourceMap.getString("jLabel1.text")); // NOI18N
        jLabel1.setName("jLabel1"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 10, 5, 5);
        fieldPanel.add(jLabel1, gridBagConstraints);

        jLabel2.setText(resourceMap.getString("jLabel2.text")); // NOI18N
        jLabel2.setName("jLabel2"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(5, 10, 10, 5);
        fieldPanel.add(jLabel2, gridBagConstraints);

        totalNetErrorField.setColumns(18);
        totalNetErrorField.setName("totalNetErrorField"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(10, 5, 5, 10);
        fieldPanel.add(totalNetErrorField, gridBagConstraints);

        currentIterationField.setColumns(10);
        currentIterationField.setName("currentIterationField"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 10);
        fieldPanel.add(currentIterationField, gridBagConstraints);

        buttonPanel.setName("buttonPanel"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(org.neuroph.easyneurons.EasyNeuronsApplication.class).getContext().getActionMap(SupervisedTrainingMonitorFrame.class, this);
        stopButton.setAction(actionMap.get("stop")); // NOI18N
        stopButton.setName("stopButton"); // NOI18N
        buttonPanel.add(stopButton);

        pauseButton.setAction(actionMap.get("pause")); // NOI18N
        pauseButton.setText(resourceMap.getString("pauseButton.text")); // NOI18N
        pauseButton.setName("pauseButton"); // NOI18N
        buttonPanel.add(pauseButton);

        closeButton.setAction(actionMap.get("close")); // NOI18N
        closeButton.setText(resourceMap.getString("closeButton.text")); // NOI18N
        closeButton.setEnabled(false);
        closeButton.setName("closeButton"); // NOI18N
        buttonPanel.add(closeButton);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 310, Short.MAX_VALUE)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addGap(0, 23, Short.MAX_VALUE)
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addComponent(fieldPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(buttonPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 264, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGap(0, 23, Short.MAX_VALUE)))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 135, Short.MAX_VALUE)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addGap(0, 13, Short.MAX_VALUE)
                    .addComponent(fieldPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGap(8, 8, 8)
                    .addComponent(buttonPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGap(0, 12, Short.MAX_VALUE)))
        );

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

    private void formInternalFrameClosing(javax.swing.event.InternalFrameEvent evt) {//GEN-FIRST:event_formInternalFrameClosing
        //this.controller.getNetwork().getLearningRule().deleteObserver(this);
//         learningRule.deleteObservers();
//         this.controller.getNetwork().getLearningRule().deleteObservers();
    }//GEN-LAST:event_formInternalFrameClosing


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel buttonPanel;
    private javax.swing.JButton closeButton;
    private javax.swing.JTextField currentIterationField;
    private javax.swing.JPanel fieldPanel;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JButton pauseButton;
    private javax.swing.JButton stopButton;
    private javax.swing.JTextField totalNetErrorField;
    // End of variables declaration//GEN-END:variables

        private class LearningInfo {
            Integer iteration;
            Double error;


            public LearningInfo(Integer iteration, Double error) {
                this.iteration = iteration;
                this.error = error;
            }

            public Double getError() {
                return error;
            }

            public Integer getIteration() {
                return iteration;
            }

        }

    @Action
    public void stop() {
		this.controller.stopTraining();
                closeButton.setEnabled(true);
                pauseButton.setEnabled(false);
                stopButton.setEnabled(false);
    }

    
    private class TrainerSwingWorker extends SwingWorker<Void, LearningInfo>
    {
        LearningInfo learningInfo;
        boolean hasData = false;
        boolean finished = false;

        public TrainerSwingWorker() {
            
        }

        public boolean isFinished() {
            return finished;
        }

        public void setFinished(boolean finished) {
            this.finished = finished;
        }

        

        public void setData(LearningInfo learningInfo) {
            this.learningInfo = learningInfo;
            hasData = true;
            synchronized(this) {
                notify();
            }
        }

        public boolean hasData() {
            return this.hasData;
        }

	@Override
	protected Void doInBackground() throws Exception
	{
                while (!finished) {
                   //Wait until data is available.
                    synchronized(this) {
                            while (!hasData && !finished) {
                                try {
                                    wait();
                                } catch (InterruptedException e) {}
                            }
                    }

                 publish(learningInfo);
                 hasData = false;
                }

                return null;
	}

	@Override
	protected void process(List<LearningInfo> chunks)
	{
                    LearningInfo li = chunks.get(chunks.size()-1);
                    currentIterationField.setText(li.getIteration().toString());
                    totalNetErrorField.setText(li.getError().toString());
	}

//        @Override
//        protected void done() {
//            System.out.println("This thread is done!");
//        }

}

    @Action
    public void pause() {
       if (!userPaused) {
           userPaused = true;
           controller.pause();
//           ((IterativeLearning)controller.getNetwork().getLearningRule()).pause();
           pauseButton.setText("Resume");
           stopButton.setEnabled(false);
       } else {
           controller.resume();
//           ((IterativeLearning)controller.getNetwork().getLearningRule()).resume();
           userPaused = false;
           pauseButton.setText("Pause");
           closeButton.setEnabled(false);
           stopButton.setEnabled(true);
       }
    }

    @Action
    public void close() {
//        this.controller.getNetwork().getLearningRule().deleteObservers();
        this.dispose();
    }



}
