package ua.ansymo.hintco

import com.opencsv.CSVWriter
import java.io.File
import java.io.FileWriter
import java.util.Map
import org.apache.commons.io.FileUtils
import org.eclipse.core.runtime.Assert
import ua.ansymo.hintco.OutputPortInstance
import ua.ansymo.hintco.RootCandidateScenario
import ua.ansymo.hintco.UnitInstance

class OutputProcessor implements IOutputProcessor {
	
	var String outDirPrefix;
	var Map<UnitInstance, CSVWriter> fmuFileMap 
	var String outDirPath;
	var long outputInterval;
	var long outputCounter;
	
	new (String d){
		outDirPrefix = d
	}
	
	override initialize(RootCandidateScenario scenario, String variantID) {
		Assert.isTrue(scenario.outputStepSize >= scenario.stepSize)
		fmuFileMap = newHashMap()
		
		// Compute output interval
		if (scenario.outputStepSize == 0.0){
			outputInterval = 1
		} else {
			outputInterval = Math.round(scenario.outputStepSize / scenario.stepSize)
		}
		
		outputCounter = outputInterval
		
		// Prepare output directories
		var outDir = new File(outDirPrefix)
		if (!outDir.exists){
			Assert.isTrue(outDir.mkdirs())
		}
		Assert.isTrue(outDir.isDirectory)
		outDirPath = outDir + "/" + variantID
		outDir = new File(outDirPath)
		if (outDir.exists){
			FileUtils.deleteDirectory(outDir)
		}
		Assert.isTrue(outDir.mkdirs())
		
		// Open csv files
		for (u : scenario.eAllContents.filter(UnitInstance).toIterable){
			val f = new CSVWriter(new FileWriter(new File(outDirPath + "/" + u.identifier + ".csv")), ";", CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.DEFAULT_ESCAPE_CHARACTER, CSVWriter.DEFAULT_LINE_END) 
			// Write header
			f.writeNext(#["time"] + u.outputPorts.map[p | p.identifier])
			
			// Record file handler
			fmuFileMap.put(u as UnitInstance, f)
		}
	}
	
	override setOutputs(int step, double time, Map<OutputPortInstance, Double> values) {
		// TODO Account for step 0.
		outputCounter--
		if (outputCounter == 0){
			outputCounter = outputInterval
			for (u : fmuFileMap.keySet){
				val file = fmuFileMap.get(u)
				val outVsString = u.outputPorts
								.map[p | 
										Assert.isTrue(values.containsKey(p))
										Assert.isNotNull(values.get(p)) 
										values.get(p)
								]
								.map[v | String.format("%g", v)]
				file.writeNext(#[String.format("%g",time)] + outVsString)
			}
		}
	}
	
	override terminate() {
		for (u : fmuFileMap.keySet){
			fmuFileMap.get(u).close()
		}
		fmuFileMap.clear()
	}
		
}