content: package aima.gui.swing.applications.robotics;
  
  import java.awt.event.WindowAdapter;
  import java.awt.event.WindowEvent;
  import java.io.File;
  
  import javax.swing.JFrame;
  
  import aima.core.robotics.MonteCarloLocalization;
  import aima.core.robotics.impl.datatypes.AbstractRangeReading;
  import aima.core.robotics.impl.datatypes.Angle;
  import aima.core.robotics.impl.map.MclCartesianPlot2D;
  import aima.core.util.JavaRandomizer;
  import aima.core.util.math.geom.SVGGroupParser;
  import aima.gui.swing.applications.robotics.components.AnglePanel;
  import aima.gui.swing.applications.robotics.components.AnglePanel.ChangeListener;
  import aima.gui.swing.applications.robotics.simple.SimpleMove;
  import aima.gui.swing.applications.robotics.simple.SimplePose;
  import aima.gui.swing.applications.robotics.simple.SimplePoseFactory;
  import aima.gui.swing.applications.robotics.simple.SimpleRangeReading;
  import aima.gui.swing.applications.robotics.simple.SimpleRangeReadingFactory;
  import aima.gui.swing.applications.robotics.simple.SimpleSettingsListener;
  import aima.gui.swing.applications.robotics.simple.VirtualRobot;
  import aima.gui.swing.applications.robotics.simple.VirtualRobotGui;
  import aima.gui.swing.framework.util.GuiBase;
  import aima.gui.swing.applications.robotics.components.IRobotGui;
  import aima.gui.swing.applications.robotics.components.Settings;
  
  /**
   * Provides the {@link GenericMonteCarloLocalization2DApp} for the simple environment in {@code aima.gui.swing.demo.robotics.simple}.
   * This environment is intended for a {@link VirtualRobot}.<br/>
   * It can be used for other 2D environments by overriding {@code initialize()} and using a main method with the inheriting class.
   * 
   * @author Arno von Borries
   * @author Jan Phillip Kretzschmar
   * @author Andreas Walscheid
   *
   */
  public class MonteCarloLocalizationApp {
  
  	protected static final File DEFAULT_SETTINGS_FILE = new File(System.getProperty("user.dir"),"mcl_settings.cache");
  	protected static final String RANGE_READING_ANGLES_KEY = "RANGE_READING_ANGLES";
  	protected static final String RANGE_READING_ANGLES_TITLE = "Range reading angles";
  	protected Settings settingsGui;
  	protected IRobotGui robotGui;
  	protected GenericMonteCarloLocalization2DApp<?,?,?> app;
  	
  	private File settingsFile;
  	
  	/**
  	 * Starts the application.
  	 * @param args a path to a file containing settings may be passed as the first argument. Otherwise the default settings file {@code mcl_settings.cache} in the working directory is used.
  	 */
  	public static void main(String[] args) {
  		File settingsFile = args.length > 0 ? new File(args[0]) : DEFAULT_SETTINGS_FILE;
  		MonteCarloLocalizationApp app = new MonteCarloLocalizationApp(settingsFile);
  		app.constructBasicApplicationFrame();
  		app.notifyAllListeners();
  		app.show();
  	}
  	
  	protected void notifyAllListeners() {
  		settingsGui.notifyAllListeners();
  	}
  
  	/**
  	 * Loads the provided settings file into a new {@link Settings} object.
  	 * @param settingsFile the file containing the settings to be loaded. 
  	 * @return the {@link Settings} that were loaded.
  	 */
  	protected static Settings buildSettings(File settingsFile) {
  		Settings settingsGui = new Settings();
  		if(settingsFile != null) {
  			if(settingsFile.isFile() && settingsFile.canRead()) {
  				settingsGui.loadSettings(settingsFile);
  			}
  		}
  		return settingsGui;
  	}
  	
  	/**
  	 * This Constructor creates a application that does not loads settings from or saves settings to a file.
  	 */
  	public MonteCarloLocalizationApp() {
  		this(null);
  	}
  	
  	/**
  	 * @param settingsFile the file containing the settings for this Monte-Carlo-Localization. To that file the settings will be stored when exiting the application.
  	 */
  	public MonteCarloLocalizationApp(File settingsFile) {
  		GuiBase.activateSystemStyle();
  		GuiBase.setUIColors();
  		this.settingsFile = settingsFile;
  		settingsGui = buildSettings(settingsFile);
  		initialize();
  		robotGui.loadSettings(settingsGui);
  		settingsGui.buildGui();
  	}
  	
  	/**
  	 * Creates a {@link GenericMonteCarloLocalization2DApp} and stores it in {@code app}.<br/>
  	 * In addition the corresponding {@link IRobotGui} is created and stored in {@code robotGui}. The function {@code robotGui.destructRobot()} will be called when the application window closes to allow closing any open connections gracefully.
  	 */
  	protected void initialize() {
  		SimpleSettingsListener settingsListener = new SimpleSettingsListener(settingsGui);
  		settingsListener.createSettings();
  		
  		AnglePanel angles = new AnglePanel(RANGE_READING_ANGLES_TITLE);
  		settingsGui.registerSpecialSetting(RANGE_READING_ANGLES_KEY, angles);
  		
  		MclCartesianPlot2D<SimplePose, SimpleMove, AbstractRangeReading> map = new MclCartesianPlot2D<SimplePose,SimpleMove,AbstractRangeReading>(new SVGGroupParser(),new SVGGroupParser(),new SimplePoseFactory(),new SimpleRangeReadingFactory());
  		VirtualRobot robot = new VirtualRobot(map);
  		robotGui = new VirtualRobotGui(robot);
  		
  		MonteCarloLocalization<SimplePose,Angle,SimpleMove,AbstractRangeReading> mcl = new MonteCarloLocalization<SimplePose, Angle, SimpleMove, AbstractRangeReading>(map, new JavaRandomizer());
  		app = new GenericMonteCarloLocalization2DApp<SimplePose,SimpleMove,SimpleRangeReading>(mcl, map, robot, robotGui, settingsGui);
  		
  		angles.setChangeListener((ChangeListener) robotGui);
  		settingsListener.setMap(map);
  		settingsListener.setMcl(mcl);
  		settingsListener.setRobot(robot);
  	}
  	
  	/**
  	 * Makes the application visible.
  	 */
  	public void show() {
  		app.show();
  	}
  	
  	/**
  	 * Creates the {@code JFrame} for the {@link AimaDemoApp}. {@code constructBasicApplicationFrame} should be called in any other case. 
  	 * @return the main frame of the application.
  	 */
  	public JFrame constructApplicationFrame() {
  		JFrame frame = constructBasicApplicationFrame();
  		//Load the virtual environment resource:
  		try {
  			app.map.loadMap(this.getClass().getResourceAsStream("virtual_environment.svg"),this.getClass().getResourceAsStream("virtual_environment.svg"));
  			app.settingsGui.notifyAllListeners();
  			app.gui.createMap();
  			app.gui.enableButtons(app.gui.buttonStateNormal);
  			/* This is bad style.
  			 * On the other hand this is the only situation in which the GUI
  			 * is modified from outside of GenericMonteCarloLocalization to load a map from the resources.
  			 */
  		} catch (Exception e) {
  			/* A Exception may be thrown when this example program is not launched from within a jar file.
  			 * This happens because the ClassLoader does not find the requested resource.
  			 */
  		}
  		return frame;
  	}
  	
  	/**
  	 * Creates the {@code JFrame} for the application. A window listener is registered. 
  	 * @return the main frame of the application.
  	 */
  	public JFrame constructBasicApplicationFrame() {
  		JFrame frame = app.constructApplicationFrame();
  		frame.addWindowListener(new WindowAdapter() {
  			@Override
  			public void windowClosing(WindowEvent e) {
  				robotGui.saveSettings(settingsGui);
  				if(settingsFile != null) settingsGui.saveSettings(settingsFile);
  				robotGui.destructRobot();
  			}
  		});
  		return frame;
  	}
  }
  