/*  Monte-Carlo simulation code for statistical physics
    Copyright (C) 2001-2004  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.data;

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

import java.awt.*; 
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.applet.Applet;
import java.util.Locale;

/**
 * Holds several "Samples" together, e.g. the energy, magnetization, etc...
 */
public class SamplesBag implements ActionListener, ChangeListener {
	Samples energySamples; 
	Samples magnetizationSamples;
	Samples energyRGSamples;  // not always used
	Plot2D graphSamples, graphHistogram, graphDOS;
	int graphUpdateIdx = 0, graphUpdateDelay = 10;

	// --- UI ---
	AbstractApplet controller;
	JLabel acceptanceLBL,autocorrelationLBL,graphUpdateDelayLBL;
	JButton resetGraphsBUT;
	JSlider graphUpdateDelaySB;

	public SamplesBag(int defMCTherm){
		fr.ensea.Log.debug();
		energySamples = new Samples();
		magnetizationSamples = new Samples();
		energySamples.setThermalizationTime(defMCTherm);
		magnetizationSamples.setThermalizationTime(defMCTherm);
		magnetizationSamples.setAutocomputeCorrelationTime(true);
		// not always used
		energyRGSamples = new Samples();
		energyRGSamples.setThermalizationTime(defMCTherm);
	}
	
	// --- properties ---
	public Samples getEnergySamples(){
		return energySamples;
	}
	
	public Samples getMagnetizationSamples(){
		return magnetizationSamples;
	}
	
	public Samples getEnergyRGSamples(){
		return energyRGSamples;
	}
	
	public int size(){
		return energySamples.size();
	}
	
	public boolean isEmpty(){
		return energySamples.isEmpty();
	}
	
	public void clear(){
		energySamples.clear();
		energyRGSamples.clear();
		magnetizationSamples.clear();
	}
	
	public double getCorrelationTime(){
		return magnetizationSamples.getCorrelationTime();
	}		
		
	public void setMCSWait(int i){
		energySamples.setMCSWait(i);
		energyRGSamples.setMCSWait(i);
		magnetizationSamples.setMCSWait(i); 
	}
	
	public int getMCSWait(){
		return energySamples.getMCSWait();
	}
	
	public void setThermalizationTime(int i){
		energySamples.setThermalizationTime(i);
		energyRGSamples.setThermalizationTime(i);
		magnetizationSamples.setThermalizationTime(i);
	}
	
	public int getThermalizationTime(){
		return energySamples.getThermalizationTime();
	}
		
	// --- samples accumulation ---
	public void addEnergySample(double E){
		energySamples.addSample(E);
	}
	
	public void addMagnetizationSample(double M){
		magnetizationSamples.addSample(M);
	}

	public void addEnergyRGSample(double E){
		energyRGSamples.addSample(E);
	}
	
	// --- thermal averages ---
	public double computeEnergyMean(){
		return energySamples.computeMean();
	}
	
	public double computeEnergyRGMean(){
		return energyRGSamples.computeMean();
	}

	public double computeMagnetizationMean(){
		return magnetizationSamples.computeMean();
	}
	
	public double computeEnergyVariance(double meanEnergy){
		return energySamples.computeVariance(meanEnergy);
	}
	
	public double computeMagnetizationVariance(double meanMagnetization){
		return magnetizationSamples.computeVariance(meanMagnetization);
	}
	
	// --- UI ---

	public void updateGUI(){
		graphUpdateIdx++;
		if (graphUpdateIdx > graphUpdateDelaySB.getValue()){
			acceptanceLBL.setText(controller.getSimulationThread().getCountersRateJLabel());
			autocorrelationLBL.setText(Localizer.get("Autocorrelation")+"="+AbstractApplet.format(getCorrelationTime())+" "+Localizer.get("steps"));
			graphSamples.dataChanged();
			if (graphHistogram!=null) graphHistogram.dataChanged();
			if (graphDOS!=null) graphDOS.dataChanged();
			graphUpdateIdx=0;
		}
	}

	/**
	 * Create the pane containing graphs of sample measurements  
	 */
	public Box createUI(AbstractApplet controller){
		fr.ensea.Log.debug();
		this.controller = controller;
		Dimension graphPreferredSize = new Dimension(200,200);

		
		// --- Pane 1 = acceptance rate ---
		acceptanceLBL=new JLabel("------------------------------");

		// --- Pane 2 = autocorrelation time ---
		autocorrelationLBL = new JLabel("------------------------------");

		// --- Pane 3 = reset graphs, etc. ---
		JPanel buttonPane = new JPanel();
		buttonPane.add(graphUpdateDelayLBL=new JLabel(Localizer.get("Refresh")+" "+Integer.toString(graphUpdateDelay)+ Localizer.get("steps")));
		buttonPane.add(graphUpdateDelaySB = new JSlider(JSlider.HORIZONTAL, 0, 1000,graphUpdateDelay));
		buttonPane.add(resetGraphsBUT=new JButton(Localizer.get("Clear")));

		// --- Pane "graphs" = graphs of E and M (and possibly E(RG)) ---
		graphSamples = new Plot2D(AbstractApplet.PANELS_BACKGROUND, AbstractApplet.PLOT2D_FRAME_COLOR1, AbstractApplet.PLOT2D_GRID_COLOR);
		String magLbl;
		if (controller.getLattice() instanceof AFIsingLattice) magLbl = "M(stag)";
		else magLbl = "M";
		graphSamples.addCurve(getMagnetizationSamples(), magLbl, AbstractApplet.PLOT2D_CURVE_COLOR2, DecoratedCurve2D.LINES);
		graphSamples.addCurve(getEnergySamples(), "E", AbstractApplet.PLOT2D_CURVE_COLOR1, DecoratedCurve2D.LINES);
		boolean displayERG = controller instanceof MCApplet && ((MCApplet)controller).isRGActive(); 
		if (displayERG) 
			graphSamples.addCurve(getEnergyRGSamples(), "E(RG)", AbstractApplet.PLOT2D_CURVE_COLOR3, DecoratedCurve2D.LINES);
		
		graphSamples.setForeground(AbstractApplet.TEXT_COLOR); // title, keys
		graphSamples.setTitle("");
		graphSamples.setPreferredSize(graphPreferredSize);

		// --- Pane "energy histogram" ---
		boolean displayHistogram = (controller instanceof MCApplet && ((MCApplet)controller).isRGActive()==false);
		displayHistogram = displayHistogram || (controller instanceof WLApplet);
		if (displayHistogram){
			this.graphHistogram = new Plot2D(AbstractApplet.PANELS_BACKGROUND, AbstractApplet.PLOT2D_FRAME_COLOR1, AbstractApplet.PLOT2D_GRID_COLOR);
			//if (lattice instanceof AFIsingLattice) graphHistogram.xAxis().setManualAxisBounds(-0.1,2.1);
			//else graphHistogram.xAxis().setManualAxisBounds(-2.1,0.1);
			if (controller instanceof MCApplet){
				Histogram histo = getEnergySamples().createHistogram(50); // 50 bins
				graphHistogram.addCurve(histo, "", AbstractApplet.PLOT2D_CURVE_COLOR1, DecoratedCurve2D.SAMPLES);
			}
			else if (controller instanceof WLApplet){
				WLDOSHistogram histo = ((WLSimulationThread)controller.getSimulationThread()).getWLDOSHistogram();
				Curve2D histoCurve = histo.createHistoCurve2D(controller.getLattice());
				graphHistogram.addCurve(histoCurve, "", AbstractApplet.PLOT2D_CURVE_COLOR1, DecoratedCurve2D.SAMPLES);
			}
			graphHistogram.setForeground(AbstractApplet.TEXT_COLOR); // title, keys
			graphHistogram.setTitle(Localizer.get("EnergyHistogram"));
			graphHistogram.setPreferredSize(graphPreferredSize);
		}

		// --- Pane "density of state" (WL only) ---
		boolean displayDOS = (controller instanceof WLApplet);
		if (displayDOS){
			this.graphDOS = new Plot2D(AbstractApplet.PANELS_BACKGROUND, AbstractApplet.PLOT2D_FRAME_COLOR1, AbstractApplet.PLOT2D_GRID_COLOR);
			WLDOSHistogram histo = ((WLSimulationThread)controller.getSimulationThread()).getWLDOSHistogram();
			Curve2D dosCurve = histo.createSECurve2D(controller.getLattice());
			graphDOS.addCurve(dosCurve, "", AbstractApplet.PLOT2D_FRAME_COLOR2, DecoratedCurve2D.DOTS);
			graphDOS.setForeground(AbstractApplet.TEXT_COLOR); // title, keys
			graphDOS.setTitle("S(E)=ln n(E)");
			graphDOS.setPreferredSize(graphPreferredSize);
		}
			
			

		// layout:
		Box graphPanel = Box.createVerticalBox();

		if (controller instanceof MCApplet){
			graphPanel.add(acceptanceLBL);
			graphPanel.add(autocorrelationLBL);
		}

		graphPanel.add(graphSamples);

		if (displayHistogram)  graphPanel.add(graphHistogram);

		if (displayDOS) graphPanel.add(graphDOS);
			
		graphPanel.add(buttonPane);

		if (displayERG) {
			JPanel p = ((MCApplet)controller).getRenormalizationPanel();
			graphPanel.add(p);
		}

		// --- listeners ---
		resetGraphsBUT.addActionListener(this);
		graphUpdateDelaySB.addChangeListener(this);
		
		graphSamples.addMouseListener(new GraphMouseHandler(controller,this.graphSamples));
		graphSamples.addMouseMotionListener(new StatusHelpMouseHandler(controller,graphSamples.getTitle()+": "+Localizer.get("HelpStatus1")));
		if (graphHistogram!=null) {
			graphHistogram.addMouseListener(new GraphMouseHandler(controller,this.graphHistogram));
			graphHistogram.addMouseMotionListener(new StatusHelpMouseHandler(controller,graphHistogram.getTitle()+": "+Localizer.get("HelpStatus1")));
		}
		if (graphDOS!=null) {
			graphDOS.addMouseListener(new GraphMouseHandler(controller,this.graphDOS));
			graphDOS.addMouseMotionListener(new StatusHelpMouseHandler(controller,graphDOS.getTitle()+": "+Localizer.get("HelpStatus1")));
		}
		
		// --- other init
		graphUpdateIdx = graphUpdateDelaySB.getValue();
		graphPanel.setBackground(AbstractApplet.PANELS_BACKGROUND);
		return graphPanel;
	}
	
	public void resetSamplesGraphs(){
		controller.getSimulationThread().reinitCounters();
		clear();
		graphSamples.dataChanged();
		if (graphHistogram!=null) graphHistogram.dataChanged();
	}


	public void actionPerformed(ActionEvent evt){
		if (evt.getSource() == resetGraphsBUT){
			resetSamplesGraphs();
		}
	}
	
	public void stateChanged(ChangeEvent evt){
		if (evt.getSource() == graphUpdateDelaySB){
			graphUpdateDelay = graphUpdateDelaySB.getValue();
			graphUpdateDelayLBL.setText(Localizer.get("Refresh")+". "+Integer.toString(graphUpdateDelay)+ Localizer.get("steps"));
		}
	}
		
}
