//@ts-check

var fs = require("fs")
var path = require("path")
var reverseLineReader = require("reverse-line-reader")

module.exports = class StratasysFortus{
	emptyWarned = false
	
	constructor(options){
		this.logDirectory = options.logDirectory
		if(!options.logDirectory){
			throw new Error("option logDirectory is not defined")
		}
		// override type to match others
		this.type = "3d-printer"
	}
	
	async getDeviceInfo(){
		//var initialPath = path.join(this.logDirectory, "Initial")
		var jobsPath = path.join(this.logDirectory, "BuildJobs")
		var jobDirs = []
		try{
			jobDirs = await fs.promises.readdir(jobsPath)
		}catch(err){
			if(process.env.VERBOSE){
				console.error(err)
				console.error("Failed to read log directory " + jobsPath)
			}
		}
		var jobLogs = []
		for(var x in jobDirs){
			try{
				var jobDirname = jobDirs[x]
				var logPath = path.join(jobsPath, jobDirname, "Program.log")
				var fileStats = await fs.promises.stat(logPath)
				var obj = {}
				obj.logPath = logPath
				obj.date = fileStats.mtime
				try{
					var sensorPath = path.join(jobsPath, jobDirname, "Sensor.csv")
					// stat file to check if it exists
					await fs.promises.stat(sensorPath)
					obj.sensorPath = sensorPath
				}catch(e){}
				jobLogs.push(obj)
			}catch(e){}
		}
		
		var out = {}
		out.title = "SLM Printer"
		
		if(jobLogs.length == 0){
			if(!this.emptyWarned){
				this.emptyWarned = true
				console.error("No log files found, check logDirectory option")
			}
			out.status = "No data"
			out.values_overview = {}
			out.values_overview.status = {
				type: "value",
				title: "Status",
				value: out.status,
			}
			return [out]
		}
		jobLogs.sort(function (a,b){
			if(a.date > b.data){
				return -1
			}else if(a.date < b.data){
				return 1
			}else{
				return 0
			}
		})
		var lastJob = jobLogs[jobLogs.length - 1]
		var linecount = 0
		var lastLine = ""
		
		var lastError = ""
		var status = "Idle"
		var layer = NaN
		await new Promise((resolve)=>{
			reverseLineReader.eachLine(lastJob.logPath,function(line, last) {
				//console.log(line);
				//return true
				var dateEnd = line.indexOf(" ")
				var timeEnd = line.indexOf(" ",dateEnd + 1)
				var typeEnd = line.indexOf(" ",timeEnd + 1)
				var type = line.substring(timeEnd + 1, typeEnd)
				var message = line.substring(typeEnd + 1)
				//console.log(type)
				if(type == "ERROR"){
					lastError = message
				}
				var doReturn = false
				var parseLayer = false
				if(message.indexOf("Starting exposure") == 0){
					parseLayer = true
					status = "Exposing"
					doReturn = true
				}
				if(message.indexOf("Starting recoating") == 0){
					parseLayer = true
					status = "Recoating"
					doReturn = true
				}
				if(message.indexOf("Start Build Job") == 0){
					status = "Starting"
					doReturn = true
				}
				if(type == "INFO" && message.indexOf("Finished:") == 0){
					parseLayer = true
					status = "Idle"
					doReturn = true
				}
				if(type == "ERROR" ){
					lastError = message
				}
				if(parseLayer){
					var layerLoc = message.indexOf("(layer")
					layer = parseInt(message.substring(layerLoc + 7))
				}
				lastLine = line
				linecount++
				return !doReturn
			}).then(resolve)
		})
		//console.log(linecount, lastLine)
		
		var sensors = Object.create(null)
		var sensorsDate = new Date()
		if(lastJob.sensorPath){
			// parse last line of sensors
			var fileHandle = await fs.promises.open(lastJob.sensorPath)
			var size = (await fileHandle.stat()).size
			var buffer = Buffer.alloc(4096)
			var head = (await fileHandle.read({
				buffer: buffer,
				position: 0
			})).buffer.toString()
			var tail = (await fileHandle.read({
				buffer: buffer,
				position: Math.max(size - 4096, 0)
			})).buffer.toString()
			var header = head.split("\r\n")[0]?.split(";")
			var line = tail.split("\r\n")
			line = line[line.length - 2]?.split(";")
			if(header && line){
				for(var x in header){
					sensors[header[x].toLowerCase()] = line[x]
				}
				if(sensors.time){
					var split = sensors.time.split(" ")
					var date = split[0].split("/")
					var time = split[1].split(":")
					var yearPrefix = sensorsDate.getFullYear().toString()
					yearPrefix = yearPrefix.substring(0, yearPrefix.length - 2)
					sensorsDate.setFullYear(parseInt(yearPrefix + date[2]))
					sensorsDate.setMonth(parseInt(date[0]) - 1)
					sensorsDate.setDate(parseInt(date[1]))
					sensorsDate.setHours(parseInt(time[0]))
					sensorsDate.setMinutes(parseInt(time[1]))
					sensorsDate.setSeconds(parseInt(time[2]))
					sensorsDate.setMilliseconds(0)
					//console.log(sensorsDate.toLocaleString())
				}
				//console.log(sensors)
			}
			fileHandle.close()
		}
		
		
		out.status = status
		
		out.values_overview = {}
		
		if(out.status){
			out.values_overview.status = {
				type:"value",
				title:"Status",
				value: out.status,
			}
		}
		
		out.values = {}
		if(isFinite(layer)){
			out.values.layer = {
				type: "value",
				title: "Layer",
				value: layer,
				decimals: 0,
			}
		}
		if(lastError){
			out.values.last_error = {
				type: "value",
				title: "Last Error",
				value: lastError,
			}
		}
		
		var outArray = []
		outArray.push(out)
		
		if(Object.keys(sensors).length > 0){
			var outSensors = {}
			outSensors.title = "Sensors"
			outSensors.values = {}
			if(sensors["oxygen 1"]){
				var oxygen = parseFloat(sensors["oxygen 1"])
				if(sensors["oxygen 2"]){
					oxygen = (oxygen + parseFloat(sensors["oxygen 2"])) / 2
				}
				outSensors.values.oxygen = {
					type: "value",
					title: "Oxygen",
					decimals: 2,
					value: oxygen,
				}
			}
			if(sensors["pressure"]){
				outSensors.values.pressure = {
					type: "value",
					title: "Pressure",
					value: parseFloat(sensors["pressure"]),
				}
			}
			if(sensors["laser on flags"]){
				outSensors.values.laser = {
					type: "value",
					title: "Laser",
					value: sensors["laser on flags"] == "0" ? "Off" : "On",
				}
			}
			if(sensors["gas flow speed"]){
				outSensors.values.flow = {
					type: "value",
					title: "Gas Flow",
					value: parseFloat(sensors["gas flow speed"]),
				}
			}
			outArray.push(outSensors)
		}
		//process.exit()
		//console.log(jobLogs)
		
		return outArray
	}
}