package gp;


import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;

import DDrawing.DArea;
import DDrawing.DFunction;
import DDrawing.DPointSet;
import DDrawing.ScaledBorder;

/**
 * @author  mkron
 */
public class EaGui extends JFrame implements ActionListener, EaGuiCallback
{
  JButton pbStartStop;
  JButton pbEnde;
  DArea output;
  JTextField tfMu;
  JTextField tfTmax;
  JTextField tfPcross;
  JTextField tfPmut;
  JCheckBox cbLog;
  JCheckBox cbCompare;
  boolean bAlgoRunning = false;
  AlgorithmInterface algo;
  DFunction logf = new LogFct();
  public double mingz;
  final int nFitCurves = 8;
  DPointSet[] fitCurve = new DPointSet[nFitCurves];
  final Color[] fitCurveColor = {Color.blue, Color.green, 
    Color.red, Color.cyan, Color.magenta, Color.black, Color.pink, Color.gray};
  int nFitCurve = -1;

  class LogFct extends DFunction
  {
    public boolean isDefinedOn( double source ){ return true; }
    public double getImageOf( double source ){ return Math.exp( source ); }
    public double getSourceOf( double target )
      { if (target<=0) return Math.log(mingz/10); else return Math.log( target ); }
  }
  
  /**
   * Define which algorithm to load. 
   */
  protected void initAlgo() {
	  algo = new EvolutionaryAlgorithm(this);
	  algo.setCallback(this);
  }
  
  public EaGui()
  { 
    super("Evolutionary Algorithms - GUI");
     
    Container cp = getContentPane();
    JLabel lb;
    GridBagLayout gbl = new GridBagLayout();
    GridBagConstraints gbc = new GridBagConstraints();
            
    setBackground(Color.lightGray);
    cp.setLayout(gbl);
        
    gbc.gridx = 0; gbc.gridy = 0;
    gbc.gridwidth = 1; gbc.gridheight = 1;
    gbc.weightx = 1; gbc.weighty = 1;
    gbc.insets = new Insets(5,5,5,5);
    gbc.anchor = GridBagConstraints.EAST;
    gbc.fill = GridBagConstraints.NONE;
    lb = new JLabel("Mu");
    gbl.setConstraints(lb, gbc);
    cp.add(lb);
    lb = new JLabel("tMax");
    gbc.gridy = 1;
    gbl.setConstraints(lb, gbc);
    cp.add(lb);
    lb = new JLabel("pCross");
    gbc.gridy = 2;
    gbl.setConstraints(lb, gbc);
    cp.add(lb);
    lb = new JLabel("pMut");
    gbc.gridy = 3;
    gbl.setConstraints(lb, gbc);
    cp.add(lb);
    
    lb = new JLabel("yScale");
    gbc.gridy = 7;
    gbl.setConstraints(lb, gbc);
    cp.add(lb);
    lb = new JLabel("Mode");
    gbc.gridy = 8;
    gbl.setConstraints(lb, gbc);
    cp.add(lb);
    
    
    tfMu = new JTextField("100",5);
    gbc.gridx = 1; gbc.gridy = 0;    
    gbc.anchor = GridBagConstraints.EAST;
    gbl.setConstraints(tfMu, gbc);
    cp.add(tfMu);
    tfTmax = new JTextField("50",5);
    gbc.gridy = 1;
    gbl.setConstraints(tfTmax, gbc);
    cp.add(tfTmax);
    tfPcross = new JTextField("0.9",5);
    gbc.gridy = 2;
    gbl.setConstraints(tfPcross, gbc);
    cp.add(tfPcross);
    tfPmut = new JTextField("0.01",5);
    gbc.gridy = 3;
    gbl.setConstraints(tfPmut, gbc);
    cp.add(tfPmut);
    
    cbLog = new JCheckBox("log");
    cbLog.addActionListener(this);
    gbc.gridy = 7;
    gbl.setConstraints(cbLog, gbc);
    cp.add(cbLog);
    cbCompare = new JCheckBox("compare");
    cbCompare.addActionListener(this);
    gbc.gridy = 8;
    gbl.setConstraints(cbCompare, gbc);
    cp.add(cbCompare);    
    
    pbStartStop = new JButton("Start");
    pbStartStop.addActionListener(this);
    gbc.gridx = 0;
    gbc.gridy = 9;
    gbc.gridwidth = 2;
    gbc.anchor = GridBagConstraints.CENTER;
    gbl.setConstraints(pbStartStop, gbc);
    cp.add(pbStartStop);
    pbEnde = new JButton("Ende");
    pbEnde.addActionListener(this);
    gbc.gridy = 10;
    gbl.setConstraints(pbEnde, gbc);
    cp.add(pbEnde);  
    
    output = new DArea();
    output.setBackground(Color.white);
    output.setPreferredSize(new Dimension(400,400));
    output.setMinRectangle( 0, 0, 100, 1 );
    output.setAutoFocus(true);
    
    gbc.gridx = 2; gbc.gridy = 0;
    gbc.gridwidth = 10; gbc.gridheight = 10;
    gbc.weightx = 5; gbc.weighty = 5;
    gbc.fill = GridBagConstraints.BOTH;
    gbl.setConstraints(output, gbc);
    cp.add(output);

    addWindowListener(
      new WindowAdapter() {
        public void windowClosing(WindowEvent e)
        { dispose(); System.exit(0); }
        }
    );
    
    for (int i=0;i<nFitCurves;i++)
    {
      fitCurve[i] = new DPointSet(100);
      fitCurve[i].setConnected(true);
      fitCurve[i].setColor(fitCurveColor[i]);
      output.addDElement(fitCurve[i]);
    }
    
    ScaledBorder sb = new ScaledBorder();
    sb.x_label = "t";
    sb.y_label = "fit";
    output.setBorder(sb);
    
    pack();
    setLocation(200,100);    
    setVisible(true);

    initAlgo();
  }
  
  public void actionPerformed(ActionEvent e)
  {
    if (e.getSource()==cbCompare)
    {
      if (bAlgoRunning) cbCompare.setSelected(nFitCurve>=0); else
      {        
        if (nFitCurve>=0)
        {
          for(int i=0;i<nFitCurves;i++) fitCurve[i].removeAllPoints();
          nFitCurve = -1;
        } else
        {
          for(int i=0;i<3;i++) fitCurve[i].removeAllPoints();
          nFitCurve = nFitCurves-1;
        }
      }
    } else if (e.getSource()==cbLog) 
    {
      if (cbLog.isSelected()) output.setYScale(logf); 
        else output.setYScale(null);
      output.setAutoFocus(true);  
    } else if (e.getSource()== pbEnde)
    {
      dispose(); System.exit(0);
    } else
    {
      if (bAlgoRunning) algo.stop(); else
      {
        int mu = Integer.parseInt(tfMu.getText());
        int tMax = Integer.parseInt(tfTmax.getText());
        SelectionEnum selMeth = SelectionEnum.nonlinRank;
        double pCross = Double.parseDouble(tfPcross.getText());
        double pMut = Double.parseDouble(tfPmut.getText());
        double selParam = 0.05;
        if (nFitCurve<0) for(int i=0;i<3;i++) fitCurve[i].removeAllPoints(); else
        {
          nFitCurve = (nFitCurve+1)%nFitCurves;
          fitCurve[nFitCurve].removeAllPoints();
        }
        mingz = 1.0;
        bAlgoRunning = true;
        pbStartStop.setText("Stop");
        cbCompare.setEnabled(false);
        algo.start(mu,tMax,pCross,pMut,selMeth,selParam);
      }
    }
  }
  
  public void algoStop(InterfaceIndividual best)
  {
    if (bAlgoRunning)
    {
      bAlgoRunning = false;
      pbStartStop.setText("Start");
      cbCompare.setEnabled(true);
      System.out.println(best.getStringRepresentation());
    }
  }
  
  public void plotFit(int t, double vmin, double vmean, double vmax, InterfaceIndividual indy)
  {
    System.out.print(String.valueOf(t)+"  "+String.valueOf(vmin)+"  "+
      String.valueOf(vmean)+"  "+String.valueOf(vmax));
    System.out.println("");
    if (vmin>0 && vmin<mingz) mingz = vmin;  
    if (nFitCurve<0)
    {
      fitCurve[0].addDPoint(t, vmin);
      fitCurve[1].addDPoint(t, vmean);
      fitCurve[2].addDPoint(t, vmax);
    } else fitCurve[nFitCurve].addDPoint(t, vmin);
  }
  
  public static void main(String[] args)
  {
    new EaGui();
  }
  
  public void clearFun() 
  {
    for(int i=0;i<nFitCurves;i++) fitCurve[i].removeAllPoints();
    nFitCurve = 0;
  }
   
  public void plotFun(double []f) 
  { 
    for(int i=0;i<f.length;i++) fitCurve[nFitCurve].addDPoint(i, f[i]);
    nFitCurve = (nFitCurve+1)%nFitCurves;
  }
}
