/*  Monte-Carlo simulation code for statistical physics
    Copyright (C) 2001-2005  Sylvain Reynal
    
    Département de Physique
    Ecole Nationale Supérieure de l'Electronique et de ses Applications (ENSEA)
    6, avenue du Ponceau,    
    F-95014 CERGY CEDEX

    et
    
    Laboratoire de Physique Théorique et Modélisation (LPTM)
    Université de Cergy-Pontoise - Site de Neuville
    F-95031 CERGY CEDEX
    
	
    Tel : 00 +33 130 736 245
    Fax : 00 +33 130 736 667
    e-mail : reynal@ensea.fr
    web page : http://www.ensea.fr/staff/reynal/
*/

package fr.ensea.montecarlo;

import fr.ensea.Version;
import fr.ensea.Localizer;
import fr.ensea.chart.*;
import fr.ensea.montecarlo.data.*;
import fr.ensea.montecarlo.model.*;
import fr.ensea.montecarlo.canonical.*;
import fr.ensea.montecarlo.multicanonical.*;
import fr.ensea.montecarlo.misc.*;
import fr.ensea.montecarlo.event.*;

import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import java.text.NumberFormat;
import java.util.Locale;

public class ControlPane extends Panel implements ActionListener, AdjustmentListener, ItemListener, SignalListener {

	private AbstractApplet controller;
	
	// --- widgets ---
	private Button startStopBUT;
	private Button pauseResumeBUT,configureParamBUT,createRandomConfigurationBUT, createUniformConfigurationBUT;
	private TextField latticeSizeTF, pottsQTF, extFieldTF;
	private Label sleepDelayLBL, exactTcLBL, runNameLBL; 
	private Choice algoChooserCH;
	private Scrollbar sleepDelaySB;
	private Checkbox activateRedrawViewerCB;
	private NumberFormat nfDouble;

	public ControlPane(AbstractApplet controller){
		super();
		this.controller = controller;
		nfDouble = NumberFormat.getNumberInstance(Locale.US);
		nfDouble.setGroupingUsed(false);
		nfDouble.setMaximumFractionDigits(2);
		
		// gridbag layout for all subpanes
		GridBagLayout gridbag = new GridBagLayout();
		GridBagConstraints c = new GridBagConstraints();
		c.insets = new Insets(5,5,5,5);
		setLayout(gridbag);

		// --- init widgets ---
		startStopBUT=new Button(Localizer.get("Start"));
		pauseResumeBUT=new Button("Pause"+"      ");
		activateRedrawViewerCB = new Checkbox(Localizer.get("Redraw"));
		activateRedrawViewerCB.setState(true);
		algoChooserCH=controller.getSimulationThread().createAlgoChoice(); // may be null !
		sleepDelayLBL=new Label(Localizer.get("Latency")+" ("+((int)controller.getSimulationThread().getSleepDelay())+" ms)");
		sleepDelaySB = new Scrollbar(Scrollbar.HORIZONTAL, (int)controller.getSimulationThread().getSleepDelay(), 5, 1, 500);
		createRandomConfigurationBUT=new Button(Localizer.get("random"));
		createUniformConfigurationBUT=new Button(Localizer.get("uniform"));
		configureParamBUT=new Button(Localizer.get("SimulationParameters"));
		if (controller.getLattice() instanceof PottsLattice){
			pottsQTF = new TextField(Integer.toString(controller.getLattice().getPottsQ()),2);
			exactTcLBL=new Label("(Tc="+nfDouble.format(((PottsLattice)controller.getLattice()).getExactTc())+")");
			extFieldTF = new TextField(Double.toString(((PottsLattice)controller.getLattice()).getMagneticField()),0);
		}
		latticeSizeTF=new TextField(Integer.toString(controller.getLattice().getLatticeSize()),4);
		runNameLBL=new Label("            ");

		Label lbl; // buffer
		
		// --- add widgets in the 1st column
		c.gridx = 0; // place all buttons in the first column 
		c.gridy = GridBagConstraints.RELATIVE; // adding them in a top-to-bottom fashion
		
		c.fill = GridBagConstraints.BOTH; // resizing behaviour: resize H and V
		c.gridwidth = 2;// or GridBagConstraints.REMAINDER;

		c.weightx = 1.0;
		c.weighty = 1.0;
		
		gridbag.setConstraints(startStopBUT,c); add(startStopBUT);
		gridbag.setConstraints(pauseResumeBUT,c); add(pauseResumeBUT);
		gridbag.setConstraints(activateRedrawViewerCB,c); add(activateRedrawViewerCB);
		gridbag.setConstraints(sleepDelayLBL,c); add(sleepDelayLBL);
		gridbag.setConstraints(sleepDelaySB,c); add(sleepDelaySB);
		if (algoChooserCH!=null){
			gridbag.setConstraints(algoChooserCH,c); add(algoChooserCH);
		}
		lbl = new Label(Localizer.get("LatticeConfiguration")+":");
		gridbag.setConstraints(lbl,c); add(lbl);
		gridbag.setConstraints(createRandomConfigurationBUT,c); add(createRandomConfigurationBUT);
		gridbag.setConstraints(createUniformConfigurationBUT,c); add(createUniformConfigurationBUT);
		gridbag.setConstraints(configureParamBUT,c); add(configureParamBUT);
		
		if (controller.getLattice() instanceof PottsLattice){
				// add "Q=" + textfield
				c.gridwidth=1;	lbl = new Label("Q="); 
				gridbag.setConstraints(lbl,c); add(lbl);
				c.gridx=1;
				gridbag.setConstraints(pottsQTF,c); add(pottsQTF);
				if (controller instanceof MCApplet && ((MCApplet)controller).isRGActive()==false){
					// add "h=" + textField 
					c.gridx = 0;c.gridwidth=1;	lbl = new Label("h(Ext)="); 
					gridbag.setConstraints(lbl,c); add(lbl);
					c.gridx=1;
					gridbag.setConstraints(extFieldTF,c); add(extFieldTF);
				}
			
			// in any case, add exact Tc
			c.gridx=0;c.gridwidth=2;
			gridbag.setConstraints(exactTcLBL,c); add(exactTcLBL);
		}
		else {
			// exact Tc not displayed [pending]
			c.gridx=0;c.gridwidth=2;
			lbl = new Label("AF-Ising");
			gridbag.setConstraints(lbl,c); add(lbl);
		}
		
		c.gridwidth=1;	lbl = new Label(Localizer.get("Size")+"=");
		gridbag.setConstraints(lbl,c); add(lbl);
		c.gridx=1;
		gridbag.setConstraints(latticeSizeTF,c); add(latticeSizeTF);
		
		c.gridx=0;c.gridwidth=2;
		gridbag.setConstraints(runNameLBL,c); add(runNameLBL);
		
		c.gridwidth=2;
		
		// --- add viewer in the 2nd column
		c.gridx = 2; // place all buttons in the first column 
		c.gridy = GridBagConstraints.RELATIVE; // adding them in a top-to-bottom fashion
		c.gridheight = GridBagConstraints.REMAINDER; // eats up all space
		c.insets=new Insets(5,5,5,5);
		c.weightx = 100.0;
		c.weighty = 1.0;
		gridbag.setConstraints(controller.getLatticeViewer(),c); add(controller.getLatticeViewer());
		int s = getSize().width/2;
		//viewer.setSize(s,s);
		
		

		// --- random/uniform lattice configuration ---
		//if (lattice instanceof PottsLattice && lattice.getPottsQ()==2)

		// --- Q-display/kT-display/Lattice-size ---
		/*
		if (lattice instanceof PottsLattice){
		}
		else {
			add(new Label("AF-Ising"));
		}
		*/
		addListeners();
	}
	
	private void addListeners(){
		startStopBUT.addActionListener(this);
		pauseResumeBUT.addActionListener(this);
		configureParamBUT.addActionListener(this);
		if (pottsQTF!=null) pottsQTF.addActionListener(this);
		if (extFieldTF!=null) extFieldTF.addActionListener(this);
		this.activateRedrawViewerCB.addItemListener(this);
		latticeSizeTF.addActionListener(this);
		createRandomConfigurationBUT.addActionListener(this);
		createUniformConfigurationBUT.addActionListener(this);
		sleepDelaySB.addAdjustmentListener(this);
		if (algoChooserCH!=null) algoChooserCH.addItemListener(this);
	}
	
	
	public void setRunName(String s){
		runNameLBL.setText(s);
	}

	// --- listeners ---
	public void actionPerformed(ActionEvent evt){

		if (evt.getSource() == startStopBUT){
			if (controller.getSimulationThread().isAlive()){ // terminer la simulation
				controller.getSimulationThread().kill();
			}
			else { 
				controller.getSimulationThread().start();
			}
		}
		else if (evt.getSource() == pauseResumeBUT){
			if (controller.getSimulationThread().isAlive()){ // sinon ca n'a pas de sens
				if (controller.getSimulationThread().isPaused()){ // reprendre
					controller.getSimulationThread().resume();
					pauseResumeBUT.setLabel("Pause");
				}
				else  { // pauser
					controller.getSimulationThread().pause();
					pauseResumeBUT.setLabel(Localizer.get("Resume"));
				}
			}
		}
		else if (evt.getSource() == pottsQTF || evt.getSource() == latticeSizeTF){
			try {
				controller.getSimulationThread().kill(); // blocks until dead
				int Q=2,L=10;
				if (pottsQTF!=null) Q = new Integer(pottsQTF.getText()).intValue();
				if (Q < 2) Q=2;
				L = new Integer(latticeSizeTF.getText()).intValue();
				if (L<2) L=2;
				boolean isRGActive = (controller instanceof MCApplet && ((MCApplet)controller).isRGActive());
				if  (isRGActive){
					L=PottsLattice.floorToPowerOf2(L);
					latticeSizeTF.setText(Integer.toString(L));
				}
				controller.getLattice().init(Q,L);
				if  (isRGActive) ((MCApplet)controller).getRenormalizationPanel().reinit(); // reinit RG lattices
				if (this.exactTcLBL!=null && controller.getLattice() instanceof PottsLattice)
					exactTcLBL.setText("(Tc="+nfDouble.format(((PottsLattice)controller.getLattice()).getExactTc())+")");
				controller.getLatticeViewer().redraw();
				boolean isWangLandau = (controller instanceof WLApplet);
				if (isWangLandau) {
					((WLSimulationThread)((WLApplet)controller).getSimulationThread()).getWLDOSHistogram().reinit(Q);
					controller.getSamplesBag().updateGUI();
				}
				controller.getSamplesBag().resetSamplesGraphs();
				//addNewAveragesSet(); // pb si on bidouille avec algo arreter
			}
			catch (NumberFormatException nfe){
				controller.showStatus(nfe.toString());
			}			
		}
		else if (evt.getSource() == extFieldTF){
			if (controller.getLattice() instanceof PottsLattice){
				try {
					double h = Double.parseDouble(extFieldTF.getText());
					((PottsLattice)controller.getLattice()).setMagneticField(h);
				}
				catch (NumberFormatException nfe){
					controller.showStatus(nfe.toString());
				}				
			}
		}
		else if (evt.getSource() == configureParamBUT){
			controller.toggleConfigurationPanel();
		}
		else if (evt.getSource() == createRandomConfigurationBUT){
			controller.getSimulationThread().reinitCounters();
			controller.getLattice().createRandomConfiguration();
			controller.getLatticeViewer().redraw();
		}
		else if (evt.getSource() == createUniformConfigurationBUT){
			controller.getSimulationThread().reinitCounters();
			controller.getLattice().createGroundstateConfiguration();
			controller.getLatticeViewer().redraw();
		}
	}

	public void adjustmentValueChanged(AdjustmentEvent evt){
		if (evt.getSource() == sleepDelaySB){
			int i = sleepDelaySB.getValue();
			sleepDelayLBL.setText(Localizer.get("Latency")+" ("+((int)i)+" ms)");
			controller.getSimulationThread().setSleepDelay(i);
		}
	}

	public void itemStateChanged(ItemEvent evt){
		if (algoChooserCH!=null && evt.getSource() == algoChooserCH){
			boolean wasRunning=controller.getSimulationThread().isRunning();
			boolean success;
			switch(algoChooserCH.getSelectedIndex()){
				
				case 0: // metropolis
				success = controller.getSimulationThread().setAlgorithm(MCSimulationThread.METROPOLIS);
				if (success && extFieldTF!=null) {
					extFieldTF.setEnabled(true);
					if (controller.getLattice() instanceof PottsLattice){
						((PottsLattice)controller.getLattice()).setMagneticField(0.0);
						extFieldTF.setText("0.0");
					}
				}
				break;
				case 1: // wolff
				success = controller.getSimulationThread().setAlgorithm(MCSimulationThread.WOLFF);
				if (success && extFieldTF!=null) {
					if (controller.getLattice() instanceof PottsLattice){
						((PottsLattice)controller.getLattice()).setMagneticField(0.0);
						extFieldTF.setText("0.0");
					}
					extFieldTF.setEnabled(false);
				}
				break;
			default:
			}
		}
		else if (evt.getSource() == activateRedrawViewerCB){
			controller.getSimulationThread().suspendRedrawViewer(!activateRedrawViewerCB.getState());
		}
	}

	public void signalBroadcast(SignalEvent e){
		if (e.getID()==e.STARTED || e.getID()==e.RESUMED) startStopBUT.setLabel(Localizer.get("Stop"));
		else if (e.getID()==e.SUSPENDED || e.getID()==e.COMPLETED)  startStopBUT.setLabel(Localizer.get("Start"));
	}


}

