const express = require("express");
const execSync = require('child_process').execSync;
var parser = require('xml2json');
const fs = require('fs');
const redis = require('redis');
const client = redis.createClient();

const app = express();
const port = 3000;
//client.connect('127.0.0.1', 6379);


const jsn = require("./base.json");
const di = require("./di.json");
const ia = require("./ia.json");
const mach = require("./machinery.json");
const mt = require("./mt.json");

let ns_array = [];


console.log(typeof jsn);
//console.log(jsn.UANodeSet.UAObject.find( record => record.NodeId === "i=84"));

client.on('connect', function(){
	console.log('Connected.');
	});
	
async function redis_set(shorty, data){
	await client.json.set(shorty,'.',data);
}

function inverse(dev){
	var str = '';
	if("IsForward" in dev){
		if(dev.IsForward === "false"){
			str = "<-";
			}
		}else{
			str = "->";
			}
	return str;	
}

function forward(dev){
	var b = true;
	if("IsForward" in dev){
		if(dev.IsForward === "false"){
			b = false;
			}
		}else{
			b = true;
			}
	return b;	
}

function sortNS(files){
	let nsets = [];
	
	for(let x = 0; x<files.length; x++){
		if("RequiredModel" in files[x].UANodeSet.Models.Model){
			if(Array.isArray(files[x].UANodeSet.Models.Model.RequiredModel)){
				var len = files[x].UANodeSet.Models.Model.RequiredModel.length;
				for(let y = 0; y < len; y++){
						files[x].UANodeSet.Models.Model.RequiredModel[y]
				}
			}else{
				
			}
		}else{
			nsets.push(files[x].UANodeSet.Models.Model.ModelUri);
		}
	}
}


function get_Children(jsnob, nid, ret_obj){
	try{
		if(Array.isArray(jsnob.UANodeSet.UAObject)){
			for (let i = 0; i < jsnob.UANodeSet.UAObject.length;i++){
				if(Array.isArray(jsnob.UANodeSet.UAObject[i].References.Reference)){
					for (let x = 0; x < jsnob.UANodeSet.UAObject[i].References.Reference.length;x++){
						if(jsnob.UANodeSet.UAObject[i].References.Reference[x].$t === nid){
							console.log(jsnob.UANodeSet.UAObject[i].BrowseName + inverse(jsnob.UANodeSet.UAObject[i].References.Reference[x]) +jsnob.UANodeSet.UAObject[i].References.Reference[x].ReferenceType);
							let zobj = {
								id: jsnob.UANodeSet.UAObject[i].NodeId,
								ReferenceType: jsnob.UANodeSet.UAObject[i].References.Reference[x].ReferenceType,
								IsForward: forward(jsnob.UANodeSet.UAObject[i].References.Reference[x]),
								}
							ret_obj.push(zobj);
							}
						}
					}else{
						if(jsnob.UANodeSet.UAObject[i].References.Reference.$t === nid){
							console.log(jsnob.UANodeSet.UAObject[i].BrowseName + inverse(jsnob.UANodeSet.UAObject[i].References.Reference) +jsnob.UANodeSet.UAObject[i].References.Reference.ReferenceType);
							let zobj = {
								id: jsnob.UANodeSet.UAObject[i].NodeId,
								ReferenceType: jsnob.UANodeSet.UAObject[i].References.Reference.ReferenceType,
								IsForward: forward(jsnob.UANodeSet.UAObject[i].References.Reference),
								}
							ret_obj.push(zobj);
						}
					}
			}
		}else{
			if(Array.isArray(jsnob.UANodeSet.UAObject.References.Reference)){
				for (let x = 0; x < jsnob.UANodeSet.UAObject.References.Reference.length;x++){
					if(jsnob.UANodeSet.UAObject[i].References.Reference[x].$t === nid){
						console.log(jsnob.UANodeSet.UAObject[i].BrowseName + inverse(jsnob.UANodeSet.UAObject.References.Reference[x]) +jsnob.UANodeSet.UAObject.References.Reference[x].ReferenceType);
						let zobj = {
								id: jsnob.UANodeSet.UAObject.NodeId,
								ReferenceType: jsnob.UANodeSet.UAObject.References.Reference[x].ReferenceType,
								IsForward: forward(jsnob.UANodeSet.UAObject.References.Reference[x]),
								}
							ret_obj.push(zobj);
					}
				}
			}else{
				if(jsnob.UANodeSet.UAObject.References.Reference.$t === nid){
					console.log(jsnob.UANodeSet.UAObject.BrowseName + inverse(jsnob.UANodeSet.UAObject.References.Reference) +jsnob.UANodeSet.UAObject.References.Reference.ReferenceType);
					let zobj = {
								id: jsnob.UANodeSet.UAObject.NodeId,
								ReferenceType: jsnob.UANodeSet.UAObject.References.Reference.ReferenceType,
								IsForward: forward(jsnob.UANodeSet.UAObject.References.Reference),
								}
							ret_obj.push(zobj);
				}
			}		
		}
	}catch(err){
		console.log("NOK");
	}
}


async function redis_get(){
	try{
	const val = await client.json.get('mt',{
		path:'.UANodeSet.Models.Model.Version',
		});
	console.log(`Value is: ${val}`);}catch(err){
				console.log("NOK");
		}
}

async function redis_flush(){
	await client.sendCommand(['FLUSHALL']);
}

function p2json(name, shorty){
	try{
	const nn = name+".xml";
	var nnn = shorty+".json";

	fs.readFile( nn, function(err, data){
	//fs.readFile( "Opc.Ua.NodeSet2.xml", function(err, data){
		let jsn = parser.toJson(data);
		fs.writeFileSync(nnn, jsn);
	});
	}catch(err){
		console.log('not work');}

}

app.get('/setredis/:ident',(req, res) =>{
	try{
		var shorty = req.params["ident"];
		const id = './'+shorty+".json";
		const fl = require(id);
		redis_set(shorty, fl);	
		res.json({result:"OK"});
	}catch(err){
		console.log("NOK");
		res.json({result:"NOK"});
		}

})

app.get('/requirejson/:ident/:name',(req, res) =>{
	try{
		var namejs = req.params["name"];
		var shorty = req.params["ident"];
		const id = "./"+namejs+".json";
		const fl = require(id);
		for(let i = 0; i < ns_array.length; i++){
			if(ns_array[i][1] === shorty){
				return res.json({result:"Array already includes element."}) 
				}
			}

		ns_array.push([fl, shorty]);	
		res.json({result:"OK"});
		
	}catch(err){
		console.log("NOK");
		res.json({result:"NOK", error: "Json file may not be available. Call list json files."});
		}

})

app.get('/shownsarray',(req, res) =>{
	try{ let str = '';
		for(let i = 0; i < ns_array.length; i++){
			str += '('+i+': '+ns_array[i][1]+')';
			}
		res.json({result:str});
		console.log(ns_array);
	}catch(err){
		console.log("NOK");
		res.json({result:"NOK", error: "Json file may not be available. Call list json files."});
		}

})

app.get('/getredis',(req, res) =>{
	try{
		redis_get();
		res.json({result:"OK"});
	}catch(err){
		console.log("NOK");
		res.json({result:"NOK"});
	}

})

app.get('/get_root',(req, res) =>{
	try{
		let rt = jsn.UANodeSet.UAObject.find( record => record.NodeId === "i=84");
		let resj = {
			id: rt.NodeId,
			parent: "#",
			text: rt.DisplayName};
		res.json(resj);
	}catch(err){
		console.log("NOK");
		res.json({result:"NOK"});
	}

})

app.get('/get_children/base/:id',(req, res) =>{
	var nid = req.params["id"];
	try{
		if(Array.isArray(jsn.UANodeSet.UAObject)){
			for (let i = 0; i < jsn.UANodeSet.UAObject.length;i++){
				if(Array.isArray(jsn.UANodeSet.UAObject[i].References.Reference)){
					for (let x = 0; x < jsn.UANodeSet.UAObject[i].References.Reference.length;x++){
						if(jsn.UANodeSet.UAObject[i].References.Reference[x].$t === nid){
							console.log(jsn.UANodeSet.UAObject[i].BrowseName + inverse(jsn.UANodeSet.UAObject[i].References.Reference[x]) +jsn.UANodeSet.UAObject[i].References.Reference[x].ReferenceType);
							}
						}
					}else{
						if(jsn.UANodeSet.UAObject[i].References.Reference.$t === nid){
							console.log(jsn.UANodeSet.UAObject[i].BrowseName + inverse(jsn.UANodeSet.UAObject[i].References.Reference) +jsn.UANodeSet.UAObject[i].References.Reference.ReferenceType);
						}
					}
			}
		}else{
			if(Array.isArray(jsn.UANodeSet.UAObject.References.Reference)){
				for (let x = 0; x < jsn.UANodeSet.UAObject.References.Reference.length;x++){
					if(jsn.UANodeSet.UAObject[i].References.Reference[x].$t === nid){
						console.log(jsn.UANodeSet.UAObject[i].BrowseName + inverse(jsn.UANodeSet.UAObject.References.Reference[x]) +jsn.UANodeSet.UAObject.References.Reference[x].ReferenceType);
					}
				}
			}else{
				if(jsn.UANodeSet.UAObject.References.Reference.$t === nid){
					console.log(jsn.UANodeSet.UAObject.BrowseName + inverse(jsn.UANodeSet.UAObject.References.Reference) +jsn.UANodeSet.UAObject.References.Reference.ReferenceType);
				}
			}		
		}
		console.log('');
		res.json({result:"OK"});
	}catch(err){
		console.log("NOK");
		res.json({result:"NOK"});
	}
})

app.get('/get_children/all/:ns/:id',(req, res) =>{
	var ret_obj = [];
	var ns = req.params["ns"];
	var id = req.params["id"];
	var nid = ns+';'+id;
	get_Children(di, nid, ret_obj);
	get_Children(ia, nid, ret_obj);
	get_Children(mach, nid, ret_obj);
	get_Children(mt, nid, ret_obj);
	
	res.json(ret_obj);
})


app.get('/flushall',(req, res) =>{
	redis_flush();
	res.json({result:"OK"});

})


app.get('/p2json/:nodeset/:ident',(req, res) =>{
	var name = req.params["nodeset"];
	var shorty = req.params["ident"];
	p2json(name, shorty);
	res.json({result:"OK"});

})

app.get('/list_projects', (req, res) => { //reacts to requests -> /list_projects
	const output = execSync("cd .. && cd Projects && ls", { encoding: 'utf-8' });
	var out = output.split("\n");
	if(out[out.length-1] === ""){
		out.splice(-1,1);
		}
	console.log("Response: ", out);
	res.json({result:out});
	})
	
	
app.get('/list_nodesets', (req, res) => { //reacts to requests -> /list_nodesets
	const output = execSync("cd .. && cd nodesets && ls", { encoding: 'utf-8' });
	var out = output.split("\n");
	var result = [];
	for(let i = 0; i < out.length; i++){
		if(out[i].includes(".xml")){
			result.push(out[i]);
			}
		}
	console.log("Response: ", result);
	res.json({result:result});
	})


app.get('/new_project', (req, res) => { //reacts to requests -> /new_project?name=myproject
	const name = req.query.name; //project name
	const output = execSync("cd .. && cd Projects && ls", { encoding: 'utf-8' });
	var out = output.split("\n");
	var result = "";
	var err = "Error - Project already exists.";
	for(let i = 0; i < out.length; i++){
		if(out[i] === name){
			return res.json({result:err});
			}
		}
	const dir = execSync("cd .. && cd Projects && mkdir "+name, { encoding: 'utf-8' });
	
	var cp = execSync("sudo cp /home/pi/ModelingTool/nodesets/Opc.Ua.NodeSet2.xml /home/pi/ModelingTool/Projects/"+name+"/Opc.Ua.NodeSet2.xml", { encoding: 'utf-8' });
	cp = execSync("sudo cp /home/pi/ModelingTool/nodesets/Opc.Ua.NodeSet2.json /home/pi/ModelingTool/Projects/"+name+"/Opc.Ua.NodeSet2.json", { encoding: 'utf-8' });
	const cur_dir = execSync("cd .. && cd Projects && cd "+name+" && ls", { encoding: 'utf-8' });
	console.log("New Project was created.");
	res.json({result:cur_dir});
	})
	

app.get('/save_project', (req, res) => { //reacts to requests -> /save_project?name=myproject
	const name = req.query.name; //project name
	const output = execSync("sudo cp /var/www/html/root.json /home/pi/ModelingTool/Projects/"+name+"/"+name+".json", { encoding: 'utf-8' });
	console.log("Project "+name+" was saved.");
	res.json({result:"Project saved"});
	})
	

app.get('/load_json', (req, res) => { //reacts to requests -> /load_json?name=myproject
	const name = req.query.name; //project name
	var output = execSync("cd .. && cd Projects && ls", { encoding: 'utf-8' });
	var out = output.split("\n");
	var result = "";
	var err = "Error - Project or file not available.";
	for(let i = 0; i < out.length; i++){
		if(out[i] === name){
				var output1 = execSync("cd .. && cd Projects && cd "+name+" && ls", { encoding: 'utf-8' });
				var out1 = output1.split("\n");
				var chk = name+".json"
					for(let y = 0; y < out1.length; y++){
						if(out1[y] === chk){
							result = execSync("sudo cp /home/pi/ModelingTool/Projects/"+name+"/"+name+".json /var/www/html/root.json", { encoding: 'utf-8' });
							console.log("Project has been loaded.");
							return res.json({result:"Project loaded"});
							}
						}
			}
		}
	
	res.json({result:err});
	})
	
	
app.get('/root', (req, res) => { //reacts to requests -> /root
	
	console.log("Return root.");
	res.json([{id:1,text:"Root node",children:[{id:2,text:"Child node 1",children:true},{id:3,text:"Child node 2"}]}]);
	})
	
	
app.listen(port, () => {
	console.log("Server listening at http://localhost:", port);
	})
