package de.tu_darmstadt.tk.SmartHomeNetworkSim.control;

import java.io.File;
import java.util.LinkedList;
import java.util.Observer;

import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Model;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.NetworkManipulationAlgorithm;
import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.SimulationManager;

/**
 * Controller which enables configuration and manipulation of the simulation
 * 
 *
 * @author Andreas T. Meyer-Berg
 */
public class SimulationController {

	/**
	 * Main Controller which can be used internally
	 */
	@SuppressWarnings("unused")
	private Controller controller;
	/**
	 * Model which can be manipulated
	 */
	private Model model;
	/**
	 * Simulation Manager
	 */
	private SimulationManager sim;
	/**
	 * Controller for managing the packet capture
	 */
	private PacketCaptureController captureController;
	/**
	 * Creates a new Simulation
	 * @param model Model to simulate
	 * @param controller Main Controller which should be used for updates etc.
	 */
	public SimulationController(Model model, Controller controller) {
		this.model = model;
		this.controller = controller;
		this.captureController = new PacketCaptureController(model, controller);
		this.sim = model.getSim();
	}

	/**
	 * Returns the Simulation Manager of the Program
	 * 
	 * @return Simulation Manager
	 */
	public SimulationManager getSimulationManager() {
		return model.getSim();
	}
	
	/**
	 * Returns true if the simulations will print the packets
	 * 
	 * @return if the packets are printed
	 */
	public boolean getPrintPackets() {
		return sim.getPacketExportManager().getPrintPackets();
	}

	/**
	 * Sets Print Packets, if true, the simulation will print the packets
	 * @param printPackets true if simulation should print the packets
	 */
	public void setPrintPackets(boolean printPackets) {
		sim.getPacketExportManager().setPrintPackets(printPackets);
		notifyPanels();
	}

	/**
	 * Get BaseFile of packet exports
	 * 
	 * @return ExportFile File, where the packets are written to
	 */
	public File getExportFile() {
		return sim.getPacketExportManager().getExportFile();
	}
	
	/**
	 * Set BaseFile for the packet export
	 * 
	 * @param exportFile File, where the packets are written to
	 */
	public void setExportFile(File exportFile) {
		sim.getPacketExportManager().setExportFile(exportFile);
		notifyPanels();
	}

	/**
	 * True if each links uses a separated File: e.g. exportFile_link.log
	 * @return true, if each links uses a single file for export
	 */
	public boolean isSplitLinkExportFiles() {
		return sim.getPacketExportManager().isSplitLinkExportFiles();
	}

	/**
	 * Set whether packets should be split into different files for each link
	 * @param splitLinkExportFiles true if each link should export to a single file
	 */
	public void setSplitLinkExportFiles(boolean splitLinkExportFiles) {
		sim.getPacketExportManager().setSplitLinkExportFiles(splitLinkExportFiles);
		notifyPanels();
	}
	
	/**
	 * Start the simulation
	 */
	public void startSimulation(){
		sim.startSimulation();
	}
	
	/**
	 * Stop the simulation
	 */
	public void stopSimulation(){
		sim.stopSimulation();
	}
	
	/**
	 * Resets the simulation to the startTime
	 */
	public void resetSimulation(){
		sim.resetSimulation();
	}
	
	/**
	 * Returns true if the simulation is running, false if not
	 * @return true if running
	 */
	public boolean isRunning(){
		return sim.isRunning();
	}
	
	/**
	 * Returns the StartTime of the simulation
	 * @return startTime
	 */
	public long getStartTime(){
		return sim.getStartTime();
	}
	
	/**
	 * Sets the new startTime
	 * @param startTime time the simulations starts
	 */
	public void setStartTime(long startTime){
		sim.setStartTime(startTime);
	}
	
	/**
	 * Returns the end time of the simulation
	 * @return End time of the simulation
	 */
	public long getEndTime(){
		return sim.getEndTime();
	}
	
	/**
	 * Sets the new startTime
	 * @param endTime new EndTime
	 */
	public void setEndTime(long endTime){
		sim.setEndTime(endTime);;
	}
	
	/**
	 * @return the currentTime
	 */
	public long getCurrentTime() {
		return sim.getCurrentTime();
	}

	/**
	 * @param currentTime the currentTime to set
	 */
	public void setCurrentTime(long currentTime) {
		sim.setCurrentTime(currentTime);
	}

	/**
	 * Returns the simulation step duration in milliseconds
	 * @return duration of each simulation step in milliseconds
	 */
	public long getStepDuration(){
		return sim.getStepDuration();
	}
	
	/**
	 * Sets the duration of simulation steps
	 * @param duration duration in milliseconds of a step
	 */
	public void setStepDuration(long duration){
		sim.setStepDuration(duration);
	}
	
	/**
	 * Adds observer, which will receive an notification on each time step
	 * @param o Observer, which should be notified
	 */
	public void addObserver(Observer o){
		sim.addObserver(o);
	}
	
	/**
	 * Removes Observer from the simulation, will no longer be notified on step change
	 * @param o Observer to be removed
	 */
	public void removeObserver(Observer o){
		sim.deleteObserver(o);
	}
	
	/**
	 * Runs all registered algorithms at the currentTimeStep
	 * @param time currentTime of the simulation
	 */
	public void runAlgorithms(long time) {
		sim.runAlgorithms(time);
	}
	/**
	 * Returns all registered algorithms of the simulation
	 * @return all registered algorithms
	 */
	public LinkedList<NetworkManipulationAlgorithm> getAlgorithms(){
		return sim.getAlgorithms();
	}
	/**
	 * Adds an algorithm, which should be executed each timestep
	 * @param algo new algorithm
	 */
	public void addAlgorithm(NetworkManipulationAlgorithm algo, Controller controller){
		sim.addAlgorithm(algo, controller);
	}
	
	/**
	 * Removes algorithms from the simulation
	 * @param algo algorithm to be removed
	 */
	public void removeAlgo(NetworkManipulationAlgorithm algo){
		sim.removeAlgo(algo);
	}
	
	/**
	 * Notify the panels, which could update their GUI
	 */
	public void notifyPanels(){
		sim.notifyPanels();
	}
	
	/**
	 * Returns the PacketCaptureController of the framework
	 * @return PacketCaptureController
	 */
	public PacketCaptureController getPacketCaptureController(){
		return captureController;
	}
}
