/*  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.multicanonical.*;
import fr.ensea.montecarlo.misc.*;

import java.awt.*; import javax.swing.*;
import java.io.*;
import java.awt.event.*;
import java.applet.Applet;
import java.text.NumberFormat;
import java.util.*;

/**
 * Abstract class for the UI controller. 
 * This is the hub that holds together several classes involved in the simulation, including
 * the algorithm thread, graphs and widgets, event listeners, and data bags.
 */
public abstract class AbstractApplet extends Applet  {

	// --- controller ---
	protected ControlPane controlPane;

	// --- data bags ---
	protected SamplesBag samplesBag;
	
	// --- graphs ---
	protected ThermalAveragesSet thermalAveragesSet;

	// --- misc ---
	protected NumberFormat nfDouble;

	// --- algorithms ---
	protected AbstractSimulationThread algoThread;
	
	// --- lattice viewer ---
	protected ILattice lattice;
	protected LatticeViewer2D viewer;

	// --- stand-alone only ---
	protected boolean isStandalone;
	protected Properties parameters;
	protected JTextField statusLBL;
	protected static final int STANDALONE_FRAME_WIDTH=1000;
	protected static final int STANDALONE_FRAME_HEIGHT=700;
	protected static final int STANDALONE_AVERPANE_HEIGHT=200;
	public static final Color FRAME_BACKGROUND=Color.yellow;
	public static final Color PANELS_BACKGROUND=Color.white;
	public static final Color TEXT_COLOR=Color.blue;
	public static final Color PLOT2D_GRID_COLOR=Color.lightGray;
	public static final Color PLOT2D_FRAME_COLOR1=Color.green.darker();
	public static final Color PLOT2D_FRAME_COLOR2=Color.magenta;
	public static final Color PLOT2D_CURVE_COLOR1=Color.blue; // free energy, energy
	public static final Color PLOT2D_CURVE_COLOR2=Color.red; // magnetization
	public static final Color PLOT2D_CURVE_COLOR3=Color.cyan; // E (RG)
	
	public static final Color[] PREDEFINED_COLORS_DARKBG={
	            Color.gray,
	            Color.cyan, // debut
	            Color.red,
	            Color.white,
	            Color.green,
	            Color.yellow,
	            Color.blue,
	            Color.pink,
	            Color.lightGray,
	            Color.magenta, 
	            Color.orange
	        };

	public static final Color[] PREDEFINED_COLORS_LIGHTBG={
	            Color.yellow,
				Color.black, // debut
	            Color.blue, 
	            Color.red,
	            Color.green.darker(),
	            Color.magenta,
	            Color.cyan.darker(),
	            Color.pink,
	            Color.lightGray,
	            Color.gray, 
	            Color.orange
	        };

	public static final Color[] PREDEFINED_COLORS = PREDEFINED_COLORS_LIGHTBG;
	
	////////////////////////////////////////////////////////

	// applet init
	public AbstractApplet(){
		//System.out.println("constructor");
		setBackground(FRAME_BACKGROUND);
		setForeground(TEXT_COLOR);
		nfDouble = NumberFormat.getNumberInstance();
		nfDouble.setGroupingUsed(false);
		nfDouble.setMaximumFractionDigits(2);
	}

	// stand-alone init
	public AbstractApplet(String[] args){
		this();
		String parameterFile;
		if (args.length > 0) parameterFile = args[0];
		else parameterFile = "parameters.props";
		isStandalone=true;
		try {
			FileInputStream is = new FileInputStream(parameterFile);
			this.parameters = new Properties();
			this.parameters.load(is);
			is.close();
		}
		catch (IOException ex){
			System.out.println(ex.toString());
			System.exit(0);
		}
		JFrame f = new JFrame(getAppletInfo());
		f.addWindowListener(
			new WindowAdapter(){
				public void windowClosing(WindowEvent we){
					System.exit(0);
			}});
		f.getContentPane().add(this);
		f.setSize(STANDALONE_FRAME_WIDTH,STANDALONE_FRAME_HEIGHT);
		init();
		start();
		f.show();
	}

	public Container getContentPane(){
		return this;
	}
	
	public Insets getInsets(){
		return new Insets(5,5,5,5);
	}


	/**
	 * Returns information about this applet.
	 */
	public String getAppletInfo(){
		return "Monte-Carlo simulation of the 2D Ising/Potts models [Release "+Version.getVersion()+" built " + Version.getBuildDate()+"] (c) Sylvain Reynal (ENSEA)";
	}

	 
	/**
	 * Called by the browser or applet viewer to inform this applet that it should start its execution.  
	 */
	public void start(){
		//System.out.println("start");
		showStatus(Localizer.get("started")+" !");
	}
	
	//////////////////////////////////////////////////////
	//// UI init
	/////////////////////////////////////////////////////
	
	/**
	 *
	 */
	protected void _initUI(){
		setLayout(new BorderLayout(5,5));
		thermalAveragesSet = new ThermalAveragesSet(lattice, samplesBag, isRGActive());
		this.controlPane=createControlPane();
		algoThread.addSignalListener(controlPane);
		JSplitPane northPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,false,controlPane,samplesBag.createUI(this));
		JSplitPane mainPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,false,northPane,thermalAveragesSet.createUI(this));
		this.add(mainPane);
		thermalAveragesSet.addNewAveragesSet();
		this.viewer.addMouseMotionListener(new StatusHelpMouseHandler(this,Localizer.get("HelpStatus2")));
		updateGUI();
		showStatus(Localizer.get("initialized")+" !");
	}

	protected void initUI(){
		getContentPane().setLayout(new BorderLayout(5,5));
		thermalAveragesSet = new ThermalAveragesSet(lattice, samplesBag, isRGActive());
		this.controlPane=createControlPane();
		algoThread.addSignalListener(controlPane);
		getContentPane().add(controlPane,BorderLayout.CENTER);
		getContentPane().add(samplesBag.createUI(this), BorderLayout.EAST);
		getContentPane().add(thermalAveragesSet.createUI(this), BorderLayout.SOUTH);
		thermalAveragesSet.addNewAveragesSet();
		this.viewer.addMouseMotionListener(new StatusHelpMouseHandler(this,Localizer.get("HelpStatus2")));
		//updateGUI();
		showStatus(Localizer.get("initialized")+" !");
	}


	/**
	 * Create the center pane containing the lattice viewer and related controls (eg start/stop/pause,...)  
	 */
	protected ControlPane createControlPane(){
		viewer = new LatticeViewer2D((ILattice2D)lattice);
		viewer.setPreferredSize(new Dimension(300,300));
		ControlPane p = new ControlPane(this);
		p.setBackground(PANELS_BACKGROUND);
		//add(p,"Center");
		return p;
	}

	///////////////////////////////////////////////////////
	//// stand-alone compatibility
	///////////////////////////////////////////////////////
	public String getParameter(String s){
		if (isStandalone) {
			if (this.parameters == null) return null;
			return this.parameters.getProperty(s);
			/*
			try {
				System.out.println(s + "= ?");
				BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
				String line = br.readLine();
				if (line.length()==0) return null;
				return line;
			}
			catch (Exception e){
				e.printStackTrace();
				return null;
			}
			*/
		}
		else return super.getParameter(s);
	}
	
	public void showStatus(String s){
		if (isStandalone) {
			//System.out.println(s);
			//statusLBL.setText(s);
		}
		else super.showStatus(s);
	}
	
	////////////////////////////////////////////////////
	//// UI
	////////////////////////////////////////////////////

	
	public void updateGUI(){
		samplesBag.updateGUI();
	}
	
	public void updateLatticeViewer(){
		viewer.redraw();
	}

	public abstract void toggleConfigurationPanel();
	
	///////////////////////////////////////////////////////////////
	//// Accessors
	///////////////////////////////////////////////////////////////

	public abstract boolean isRGActive();

	public AbstractSimulationThread getSimulationThread(){
		return this.algoThread;
	}
	
	public ILattice getLattice(){
		return lattice;
	}
	
	public SamplesBag getSamplesBag(){
		return samplesBag;
	}
	
	public LatticeViewer2D getLatticeViewer(){
		return viewer;
	}

	public ControlPane getControlPane(){
		return controlPane;
	}

	public ThermalAveragesSet getThermalAveragesSet(){
		return this.thermalAveragesSet;
	}
	
}

