package bsearch.app;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.JButton;
import javax.swing.JCheckBox;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;

import org.nlogo.util.MersenneTwisterFast;



public class RunOptionsDialog extends javax.swing.JDialog {

	private static final long serialVersionUID = 1L;
	private JPanel jPanelNorth;
	private JPanel jPanelSouth;
	private JButton jButtonCancel;
	private JLabel jLabelNumSearches;
	private JSpinner jSpinnerThreads;
	private JLabel jLabelThreads;
	private JSpinner jSpinnerNumSearches;
	private JPanel jPanelCenter;
	private JButton jButtonStartSearch;
	
	private boolean dialogCanceled = true;
	private JCheckBox jCheckBoxBriefOutput;
	private JButton jButtonNewSeed;
	private JPanel jPanel1;
	private JSpinner jSpinnerFirstSearchNumber;
	private JLabel jLabelFirstSearchNumber;
	private JSpinner jSpinnerRandomSeed;
	private JLabel jLabelRandomSeed;
	private JButton jButtonBrowseStem;
	private JTextField jTextFieldOutputStem;
	private JLabel jLabelOutputStem;

	public RunOptionsDialog(JFrame frame, BehaviorSearch.RunOptions runOptions) {
		super(frame, "Choose experiment running options");

		{
			jPanelNorth = new JPanel();
			BorderLayout jPanelNorthLayout = new BorderLayout();
			jPanelNorth.setLayout(jPanelNorthLayout);
			getContentPane().add(jPanelNorth, BorderLayout.NORTH);
			{
				jLabelOutputStem = new JLabel();
				jPanelNorth.add(jLabelOutputStem, BorderLayout.WEST);
				jLabelOutputStem.setText("Output file stem:  ");
				jLabelOutputStem.setFont(new java.awt.Font("Dialog",1,12));
			}
			{
				jTextFieldOutputStem = new JTextField();
				jPanelNorth.add(jTextFieldOutputStem, BorderLayout.CENTER);
				jTextFieldOutputStem.setText("/path/to/some/filename/stem");
				jTextFieldOutputStem.setToolTipText("All of the output files will start with the same filename \"stem\" (e.g.  MYSTEM.bestHistory.csv, MYSTEM.finalBests.csv)");
			}
			{
				jButtonBrowseStem = new JButton();
				jPanelNorth.add(jButtonBrowseStem, BorderLayout.EAST);
				jButtonBrowseStem.setText("Browse...");
				jButtonBrowseStem.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent e) {
					    JFileChooser chooser = new JFileChooser("./experiments/");
				    	chooser.setSelectedFile(new File(jTextFieldOutputStem.getText()));
					    int returnVal = chooser.showSaveDialog(RunOptionsDialog.this);
					    if(returnVal == JFileChooser.APPROVE_OPTION) 
					    {
					    	jTextFieldOutputStem.setText(chooser.getSelectedFile().getPath());
					    }	    

					}
				});

			}
			jPanelNorth.setPreferredSize(new java.awt.Dimension(190, 35));
		}
		{
			jPanelSouth = new JPanel();
			FlowLayout jPanelSouthLayout = new FlowLayout();
			jPanelSouthLayout.setAlignment(FlowLayout.RIGHT);
			jPanelSouth.setLayout(jPanelSouthLayout);
			getContentPane().add(jPanelSouth, BorderLayout.SOUTH);
			jPanelSouth.setPreferredSize(new java.awt.Dimension(190, 35));
			{
				jButtonStartSearch = new JButton("Start Search");
				jPanelSouth.add(jButtonStartSearch);
				jButtonStartSearch.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						dialogCanceled = false;
						setVisible(false);
					}					
				});
			}
			{
				jButtonCancel = new JButton();
				jPanelSouth.add(jButtonCancel);
				jButtonCancel.setText("Cancel");
				jButtonCancel.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent arg0) {
						setVisible(false);
					}					
				});

			}
		}
		{
			jPanelCenter = new JPanel();
			getContentPane().add(jPanelCenter, BorderLayout.CENTER);
			GridBagLayout jPanel2Layout = new GridBagLayout();
			jPanel2Layout.columnWidths = new int[] {7, 7};
			jPanel2Layout.rowHeights = new int[] {7, 7, 7, 7, 7};
			jPanel2Layout.columnWeights = new double[] {0.1, 0.1};
			jPanel2Layout.rowWeights = new double[] {0.1, 0.1, 0.1, 0.1, 0.1};
			jPanelCenter.setLayout(jPanel2Layout);
			{
				jLabelNumSearches = new JLabel();
				jPanelCenter.add(jLabelNumSearches, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
				jLabelNumSearches.setText("Number of searches:");
				jLabelNumSearches.setFont(new java.awt.Font("Dialog",1,12));
			}
			{
				SpinnerNumberModel jSpinnerNumSearchesModel = 
					new SpinnerNumberModel(1,1,10000,1);
				jSpinnerNumSearches = new JSpinner();
				jPanelCenter.add(jSpinnerNumSearches, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 10, 0, 0), 0, 0));
				jSpinnerNumSearches.setModel(jSpinnerNumSearchesModel);
				jSpinnerNumSearches.setToolTipText("How many times should this search be repeated?");
			}
			{
				jLabelThreads = new JLabel();
				jPanelCenter.add(jLabelThreads, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
				jLabelThreads.setText("Number of threads:");
				jLabelThreads.setToolTipText("(only affects search time performance, not search results)");
				jLabelThreads.setFont(new java.awt.Font("SansSerif",1,12));
			}
			{
				SpinnerNumberModel jSpinnerThreadsModel = 
					new SpinnerNumberModel(1,1,32,1);
				jSpinnerThreads = new JSpinner();
				jPanelCenter.add(jSpinnerThreads, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 10, 0, 0), 0, 0));
				jSpinnerThreads.setModel(jSpinnerThreadsModel);
				jSpinnerThreads.setToolTipText("(only affects search time performance, not search results)");
			}
			{
				jLabelRandomSeed = new JLabel();
				jPanelCenter.add(jLabelRandomSeed, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
				jLabelRandomSeed.setText("Initial random seed:");
				jLabelRandomSeed.setFont(new java.awt.Font("SansSerif",1,12));
			}
			{
				jPanel1 = new JPanel();
				BorderLayout jPanel1Layout = new BorderLayout();
				jPanel1.setLayout(jPanel1Layout);
				jPanelCenter.add(jPanel1, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 10, 0, 0), 0, 0));
				{
					SpinnerNumberModel jSpinnerRandomSeedModel = 
						new SpinnerNumberModel(1,Integer.MIN_VALUE,Integer.MAX_VALUE,1);
					
					jSpinnerRandomSeed = new JSpinner();
					jPanel1.add(jSpinnerRandomSeed, BorderLayout.CENTER);
					jSpinnerRandomSeed.setModel(jSpinnerRandomSeedModel);
					jSpinnerRandomSeed.setToolTipText("random seed to be used for the first search (additional searches will be seeded with following consecutive numbers)");
				}
				{
					jButtonNewSeed = new JButton();
					jPanel1.add(jButtonNewSeed, BorderLayout.EAST);
					jButtonNewSeed.setText("New");
					jButtonNewSeed.addActionListener(new ActionListener() {
						public void actionPerformed(ActionEvent e) {
							jSpinnerRandomSeed.setValue(new MersenneTwisterFast().nextInt());
						}
					});
				}
			}
			{
				jLabelFirstSearchNumber = new JLabel();
				jPanelCenter.add(jLabelFirstSearchNumber, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
				jLabelFirstSearchNumber.setText("Starting at search ID:");
				jLabelFirstSearchNumber.setFont(new java.awt.Font("Dialog",1,12));
			}
			{
				SpinnerNumberModel jSpinnerFirstSearchNumberModel = new SpinnerNumberModel(1,0,10000,1);
							
				jSpinnerFirstSearchNumber = new JSpinner();
				jPanelCenter.add(jSpinnerFirstSearchNumber, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 10, 0, 0), 0, 0));
				jSpinnerFirstSearchNumber.setModel(jSpinnerFirstSearchNumberModel);
				jSpinnerFirstSearchNumber.setToolTipText("What number should the \"search ID\" numbers start at, in the output files?");
			}
			{
				jCheckBoxBriefOutput = new JCheckBox();
				jPanelCenter.add(jCheckBoxBriefOutput, new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
				jCheckBoxBriefOutput.setText("Brief Output?");
				jCheckBoxBriefOutput.setToolTipText("Do not create the two largest files, with ALL of the model run and objective function data.");
				jCheckBoxBriefOutput.setFont(new java.awt.Font("Dialog",1,12));
			}
		}
		// make sure the OK button always gets focus, so it's easy to close the help dialog.
		this.addWindowFocusListener(new java.awt.event.WindowAdapter() {
		    @Override
			public void windowGainedFocus(java.awt.event.WindowEvent e) {
		        jButtonStartSearch.requestFocusInWindow();
		    }
		});

		init(runOptions);
		this.setPreferredSize(new java.awt.Dimension(600,280));
		this.pack();  // size the window based on the textpane's contents
	}
	///////////////////////////////////////////////////////////////////////////////////////////////
	//the special comment on the next line marks the remaining code so the Jigloo gui builder won't try to parse it.  
	//$hide>>$
	
	public void init(BehaviorSearch.RunOptions runOptions)
	{
		jTextFieldOutputStem.setText(runOptions.outputStem);
		jSpinnerNumSearches.setValue(runOptions.numSearches);
		jSpinnerFirstSearchNumber.setValue(runOptions.firstSearchNumber);
		jSpinnerThreads.setValue(runOptions.numThreads);
		jSpinnerRandomSeed.setValue(runOptions.randomSeed.intValue());
		jCheckBoxBriefOutput.setSelected(runOptions.briefOutput);
		
	}
	public void updateOptions(BehaviorSearch.RunOptions runOptions)
	{
		//TODO: input validation for this dialog, and don't let them press OK to close unless it's valid. 
		runOptions.outputStem = jTextFieldOutputStem.getText();
		runOptions.numSearches = (Integer) jSpinnerNumSearches.getValue();
		runOptions.firstSearchNumber = (Integer) jSpinnerFirstSearchNumber.getValue();
		runOptions.numThreads = (Integer) jSpinnerThreads.getValue();
		runOptions.randomSeed = (Integer) jSpinnerRandomSeed.getValue();
		runOptions.briefOutput = jCheckBoxBriefOutput.isSelected();
	}
	
	/**
	 * @param parent - parent Frame
	 * @param runOptions - search options object, which will be modified by this dialog
	 * @return true if OK was pressed, false if dialog was canceled.
	 */
	public static boolean showDialog(JFrame parent, BehaviorSearch.RunOptions runOptions)
	{
		//TODO: make GUI options for shortened output, and suppressing all model results... 
    	//TODO: make the GENERATE-random-seed button!
		
		RunOptionsDialog dialog = new RunOptionsDialog(parent, runOptions);
		dialog.setLocationRelativeTo(null);
		dialog.setModalityType(ModalityType.APPLICATION_MODAL);
		dialog.setVisible(true);
		if (dialog.dialogCanceled)
		{
			return false;
		}
		dialog.updateOptions(runOptions);
		return true;
	}
	
	//$hide<<$	
}
