package de.tu_darmstadt.tk.SmartHomeNetworkSim.core;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;

import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.util.PacketComparator;

/**
 * Manager which handles the exports of packets during the simulation
 *
 * @author Andreas T. Meyer-Berg
 */
public class PacketExportManager {

	/**
	 * Model
	 */
	private Model model;
	
	/**
	 * True if packets should be printed
	 */
	private boolean printPackets = false;

	/**
	 * Writer to write the packets to a file
	 */
	private BufferedWriter writer;

	/**
	 * Base File for the exported Packages
	 */
	private File exportFile = new File("testPackets.log");

	/**
	 * Split Links into differentFiles
	 */
	private boolean splitLinkExportFiles = false;

	/**
	 * Creates a new PacketExportManager
	 * @param model main model, which links should be exported
	 */
	public PacketExportManager(Model model) {
		this.model = model;
	}
	
	/**
	 * Exports the packets which were sent during the last time step according
	 * to the settings (whether packages should be printed, specified export
	 * File, splitLinks setting etc.)
	 */
	public void exportPacketsOfLastTimeStep() {
		if (printPackets) {
			if (!splitLinkExportFiles) {
				/**
				 * Packets of all links, merged together
				 */
				LinkedList<Packet> packets = new LinkedList<Packet>();
				model.getConnectionNetworks().forEach(a->packets.addAll(a.getPackets()));
				packets.sort(new PacketComparator());
				
				writePacketsToFile(packets, exportFile);
			}else{
				for(Link link:model.getConnectionNetworks()){
					/**
					 * File name:
					 * test.log
					 * to
					 * test_linkName.log
					 */
					String fileName = exportFile.getName();
					//Add linkName
					if(fileName.contains(".")){
						String baseName = fileName.substring(0, fileName.lastIndexOf('.'));
						String ending = fileName.substring(fileName.lastIndexOf('.')+1, fileName.length());
						fileName = baseName +"_"+link.getName()+"."+ending;
					}else{
						fileName = fileName +"_"+link.getName();
					}
					/**
					 * Path to parent directory
					 */
					String parent = exportFile.getParent();
					/**
					 * File with the fileName
					 */
					File linkExportFile = new File((parent == null?"":parent)+fileName);
					/**
					 * Write Packets
					 */
					writePacketsToFile(link.getPackets(), linkExportFile);
				}
			}
		}
	}

	/**
	 * Writes all packets of the given Collection to the specified file
	 * @param packets packets which should be written
	 * @param file file the packets should be written to
	 */
	private void writePacketsToFile(Collection<Packet> packets, File file){
		if(file == null || packets == null)
			return;
		try {
			//Check if file exists, if not create
			file.createNewFile();
			//Start Writing
			writer = new BufferedWriter(new FileWriter(file.getAbsolutePath(), true));
			//Write all packets
			packets.forEach(p -> {
				try {
					writer.append(p.getTextualRepresentation() + "\n");
				} catch (Exception e) {
					System.err.println("Warning: Error on exporting packets: "+e.toString());
				}
			});
		} catch (Exception e) {
			System.err.println("Warning: Writing failed on file "+file.getPath()+"\n"+e.toString());
		} finally {
			//Close open writer
			if (writer != null)
				try {
					writer.close();
				} catch (IOException e) {}
		}
	}

	/**
	 * Returns true if the simulations will print the packets
	 * 
	 * @return if the packets are printed
	 */
	public boolean getPrintPackets() {
		return printPackets;
	}

	/**
	 * 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) {
		this.printPackets = printPackets;
	}

	/**
	 * Get BaseFile of packet exports
	 * 
	 * @return ExportFile File, where the packets are written to
	 */
	public File getExportFile() {
		return exportFile;
	}

	/**
	 * Set BaseFile for the packet export
	 * 
	 * @param exportFile
	 *            File, where the packets are written to
	 */
	public void setExportFile(File exportFile) {
		this.exportFile = exportFile;
	}

	/**
	 * 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 splitLinkExportFiles;
	}

	/**
	 * 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) {
		this.splitLinkExportFiles = splitLinkExportFiles;
	}
}
