//
//included modules
//
import { CommonIncludes } from '/sd:common-includes.js'; 
import { ThemeClass } from '/sd:theme-class.js'; 
import { ModbusRequestContainer } from '/sd:modbus-request-container.js'; 
import { BasicContainer } from '/sd:basic-container.js'; 
import { ActionButton } from '/sd:action-button.js'; 
import { NumericPoint } from '/sd:numeric-point.js';
import { NumericSetPoint } from '/sd:numeric-set-point.js';
import { BooleanPoint } from '/sd:boolean-point.js';
import { BooleanSetPoint } from '/sd:boolean-set-point.js';
import { DialogWindow } from '/sd:dialog-window.js';
import { Lexicon } from '/sd:lexicon.js';

//
//global declarations
//
var choosenLexicon = null;
var modbusReader = new Array();
var theme = null;
window.choosenLexicon = choosenLexicon;
window.modbusReader = modbusReader;
window.theme = theme;

var containers = new Array();
var numericPoints = new Array();
var alarmPoints = new Array();
var buttons = new Array();
var booleanSetPoints = new Array();
var numericSetPoints = new Array();
var statusPoints = new Array();
var dateTimePoints = new Array();
var dialogWindow = null;

var myFileName = "";
var userPermission = 0;
var userName = "";
var themeName = null;
var clockMode = null;
var lexiconName = null;
var floatSeparator = null;

const DEBUG_MODE = false;

const numericPointsMax = 30;
const alarmPointsMax = 16;
const buttonsMax = 4;
const setPointsMax = 30;
const statusPointsMax = 16;

/**
 * callback function reads general (eg. HTML title, HTML body settings) properties of template from config XML file and it put these values into HTML file
 * @param {jQuery} attributes 		Attributes of general markup read from XML file
 */
function generalProperties(attributes) {
	ThemeClass.bodyStyleDecode(attributes, "site");
	var tabObj = document.getElementById("webTitle");
	tabObj.innerHTML = attributes['title'].value;
}

/**
 * callback function reads imageContainer properties of template from config XML file and it create this container(with these values) in HTML file. It creates user image inside the continer
 * @param {jQuery} attributes 		Attributes of general markup read from XML file
 */
function imageContainerProperties(attributes) {
	var parentObj = document.getElementById("imageContainer");
	if(attributes['fileName'] != undefined) {
		var customImage = document.createElement("img");
		customImage.setAttribute("id", "customImage");
		
		customImage.setAttribute("src", window.location.protocol + "//" + window.location.host + "/sd:" + themeName + "_" + attributes['fileName'].value);
		customImage.setAttribute("alt", "image centered");
		parentObj.appendChild(customImage);
	}
	else {
		parentObj.setAttribute("style", "display:none;");
	}
}

/**
 * callback function reads numericPointsContainer properties of template from config XML file and it create this container(with these values) in HTML file. It creates all defined (up to 30) numeric points inside the continer
 * @param {jQuery} xmlObject 		Data read from XML file
 */
function numericPointsContainerProperties(xmlObject) {
	//numericPoints
	var numericPointXmlObjects = xmlObject.find("numericPoint");
	var count = Math.round(xmlObject[0].attributes['count'].value);
	if(count > numericPointsMax) {
		count = numericPointsMax;
	}
	var pointPermissions;
	var objPointer = null;
	for(var i = 0; i < count; i++) {
		pointPermissions = numericPointXmlObjects[i].attributes["permissionlevel"];
		pointPermissions = parseInt((pointPermissions != undefined) ? pointPermissions.value : -1);
		if(userPermission >= pointPermissions) {
			objPointer = new NumericPoint(numericPointXmlObjects, "numericPointsContainer", i, enumsDefinitionXmlObject, floatSeparator);
			numericPoints.push(objPointer);
		}
	}
	if(DEBUG_MODE == true) {
		console.log("numeric point only XML:");
		console.log(numericPointXmlObjects);
	}
}

/**
 * callback function reads boolean pointsContainerProperties (e.g. status or alarm points) properties of template from config XML file and it create this container(with these values) in HTML file. It creates all defined (up to 16) status points inside the continer
 * @param {jQuery} xmlObject 			Data read from XML file
 * @param {collection} pointProperties	Point's properties {parentId: "", stylesClass: "", pointsArray: [], pointsMax: ""}
 */
function booleanPointsContainerProperties(xmlObject, pointProperties) {
	//statusPoints
	var count = Math.round(xmlObject[0].attributes['count'].value);
	if(count > pointProperties.pointsMax) {
		count = pointProperties.pointsMax;
	}
	var pointPermissions;
	var objPointer = null;
	for(var i = 0; i < count; i++) {
		pointPermissions = xmlObject[0].children[i].attributes["permissionlevel"];
		pointPermissions = parseInt((pointPermissions != undefined) ? pointPermissions.value : -1);
		if(userPermission >= pointPermissions) {
			objPointer = new BooleanPoint(xmlObject, pointProperties.parentId, i, pointProperties.stylesClass, "image", null, null, themeName);
			pointProperties.pointsArray.push(objPointer);
		}
	}
}

//callback function reads buttonsContainer properties of template from config XML file and it create this container(with these values) in HTML file. It creates all defined (up to 3) buttons inside the continer
function buttonsContainerProperties(xmlObject) {
	//buttons
	var buttonXmlObjects = xmlObject.find("button");
	var count = Math.round(xmlObject[0].attributes['count'].value);
	if(count > buttonsMax) {
		count = buttonsMax;
	}
	var pointPermissions;
	var objPointer = null;
	var link = null;

	var parentObj = document.getElementById("buttonsContainer");
	//create image
	var scheduleImage = document.createElement("img");
	scheduleImage.setAttribute("id", "scheduleIcon");
	scheduleImage.setAttribute("src", window.location.protocol + "//" + window.location.host+ "/sd:" + themeName + "_schedule-icon.png");
	scheduleImage.setAttribute("alt", "image centered");
	parentObj.appendChild(scheduleImage);
	//define
	for(var i = 0; i < count; i++) {
		pointPermissions = buttonXmlObjects[i].attributes["permissionlevel"];
		pointPermissions = parseInt((pointPermissions != undefined) ? pointPermissions.value : -1);
		if(userPermission >= pointPermissions) {
			link = "'" + window.location.protocol + "//" + window.location.host + "/" + myFileName + "_schedule" + String(i + 1) + ".html'"
			objPointer = new ActionButton(buttonXmlObjects, "buttonsContainer", "window.location.href = " + link, i);
			buttons.push(objPointer);
		}
	}
	//set absolute left position
	for(var i=1; i < buttons.length; i++) {
		buttons[i].mainObj.style.left = String(160 + (260 * (i - 1))) + "px";
	}
}

//callback function reads setpointsContainer properties of template from config XML file and it create this container(with these values) in HTML file. It creates all defined (up to 30) set points inside the continer
function setPointsContainerProperties(xmlObject) {
	var falseText;
	var trueText;
	var attributes;
	var pointPermissions;
	//setpoints
	var booleanSetPointXmlObjects = xmlObject.find("booleanSetPoint");
	var boolItem = 0;
	
	var numericSetPointXmlObjects = xmlObject.find("numericSetPoint");
	var numItem = 0;	
	
	var count = Math.round(xmlObject[0].attributes['count'].value);
	if(count > setPointsMax) {
		count = setPointsMax;
	}	
	var objPointer = null;
	var localName = null;
	//for each setPoint
	for(var i = 0; i < count; i++) {
		localName = xmlObject[0].children[i].localName;
		if(localName == "numericsetpoint") {
			pointPermissions = numericSetPointXmlObjects[numItem].attributes["permissionlevel"];
			pointPermissions = parseInt((pointPermissions != undefined) ? pointPermissions.value : -1);
			if(userPermission >= pointPermissions) {
				objPointer = new NumericSetPoint(numericSetPointXmlObjects, "setPointsContainer", numItem, enumsDefinitionXmlObject, floatSeparator, "NumericSetPoint");
				numericSetPoints.push(objPointer);
			}
			numItem++;
		}
		else if(localName == "booleansetpoint") {
			pointPermissions = booleanSetPointXmlObjects[boolItem].attributes["permissionlevel"];
			pointPermissions = parseInt((pointPermissions != undefined) ? pointPermissions.value : -1);
			if(userPermission >= pointPermissions) {
				attributes = booleanSetPointXmlObjects[boolItem].children[1].attributes;
				falseText = (attributes['falseText'] != undefined) ? attributes['falseText'].value : "false";
				trueText = (attributes['trueText'] != undefined) ? attributes['trueText'].value : "true";
				objPointer = new BooleanSetPoint(booleanSetPointXmlObjects, "setPointsContainer", boolItem, "BooleanSetPoint", "text", falseText, trueText, themeName);
				booleanSetPoints.push(objPointer);
			}
			boolItem++;
		}
		else {
			console.log("Unknown XML object name inside setpointsContainer was ignored");
		}
	}
}

/**
 * 
 * @param {*} configXmlObject 
 * @param {*} pointName 
 * @param {*} sharedContainer 
 * @param {*} callbackFunctionPointContainerProperties 
 * @param {*} containerProperties 
 */
function printHeaderWithContainer(configXmlObject, pointName, sharedContainer, callbackFunctionPointContainerProperties, callbackAttributes = false, parentNode = "site", containerProperties=null) {
	var containerName = pointName + "PointsContainer";
	var headerContainerName = pointName + "PointsHeaderContainer";
	var headerContainerXmlObject = $(configXmlObject).find(headerContainerName);
	var containerXmlObject = $(configXmlObject).find(containerName);

	//header
	var objPointer = new BasicContainer(headerContainerXmlObject, sharedContainer);
	containers.push(objPointer);
	CommonIncludes.checkContainerAndReadProperties(headerContainerXmlObject, headerContainerName, CommonIncludes.headerContainerProperties, false, "site", {parentId: headerContainerName, id: pointName + "PointsHeaderLabel", itemNumber: null});
	//container
	objPointer = new BasicContainer(containerXmlObject, sharedContainer);
	containers.push(objPointer);

	CommonIncludes.checkContainerAndReadProperties(containerXmlObject, containerName, callbackFunctionPointContainerProperties, callbackAttributes, parentNode, containerProperties);
	console.log(containerName + " inited");
}

var cont1 = "ma" + "in" + "Co" + "nt" + "ai" + "ner";
var cont2 = "di" + "al" + "og" + "Wi" + "nd" + "ow";
var cont3 = "AA" + "C2" + "0d" + "ev" + "ic" + "eE" + "rr" + "or";
var cont4 = "si" + "te";
var cont5 = "No" + "n " + "AA" + "C2" + "0 " + "co" + "nt" + "ro" + "ll" + "er" + " d" + "et" + "ec" + "ted";
var dialogWindowXmlObject;
var enumsDefinitionXmlObject;

/**
 * 
 */
function checkDevice() {
	$.ajax({
		url:'do',
		type:'POST',
		data: {
			actions: [
					{action: "get", what: "int", id: "time"},
					{action: "get", what: "int", id: "sn"},
			]
		},
		success: function(res) {
			var val = res[0].val;
			if(val.length == 19 && val.substring(4).indexOf(".") == 0 && val.substring(7).indexOf(".") == 0 && val.substring(10).indexOf(" ") == 0 && val.substring(13).indexOf(":") == 0 && val.substring(16).indexOf(":") == 0) {
				DialogWindow.setBackground((!dialogWindow.getVisibility()) ? cont1 : cont2, 1.0, "auto");
				document.getElementById(cont3).style.setProperty("display", "none");
			}
			else {
				DialogWindow.setBackground(cont1, 0.4, "none");
				DialogWindow.setBackground(cont2, 0.4, "none");
				document.getElementById(cont3).style.setProperty("display", "block");
			}
			setTimeout(checkDevice, 60000);
		},//end success
		error : function() {
			console.log("Modbus TCP timeout request!");
			setTimeout(checkDevice, 10000);
		}
	});
}

//function initialize the template	
function initialisation() {
	//get the current file name
	var path = window.location.pathname;
	myFileName = path.split("/").pop();
	myFileName = myFileName.slice(0, -5);
	myFileName = myFileName.replace("/sd:", "");
	
	var xmlFileName = window.location.protocol + "//" + window.location.host + "/" + myFileName + String("_config.xml");
	//var xmlFileName = window.location.protocol + "//" + window.location.host + "/sd:" + myFileName + String("_config.xml");

	//userPermission:
	userPermission = CommonIncludes.readHeader("priv");
	if(userPermission == 101) {
		console.log("Permission level not supported in this FW and kits version!");
	}

	//userName:
	userName = CommonIncludes.readHeader("usr");
	
	//load configuration XML
	$.ajax({
		type: "GET",
		url: xmlFileName,
		datatype: "xml",
		success: function(data) {
			for(var i =0; i < $(data).length; i++) {
				//load site XML
				if($(data)[i].localName == "site") {
					var configXmlObject = $(data)[i];
					if(DEBUG_MODE == true) {
						console.log("configXmlObject:");
						console.log($(configXmlObject));
					}
				}
				//load themes XML
				else if($(data)[i].localName == "themes") {
					var themeXmlObject = $(data)[i];
					if(DEBUG_MODE == true) {
						console.log("themeXmlObject:");
						console.log($(themeXmlObject));
					}
				}
				//load network XML
				else if($(data)[i].localName == "network") {
					var networkXmlObject = $(data)[i];
					if(DEBUG_MODE == true) {
						console.log("networkXmlObject:");
						console.log($(networkXmlObject));
					}
				}
				//load lexicons XML
				else if($(data)[i].localName == "lexicons") {
					var lexiconsXmlObject = $(data)[i];
					if(DEBUG_MODE == true) {
						console.log("lexiconsXmlObject:");
						console.log($(lexiconsXmlObject));
					}
				}
				//load enumsDefinition XML
				else if($(data)[i].localName == "enumsdefinition") {
					enumsDefinitionXmlObject = $(data)[i];
					if(DEBUG_MODE == true) {
						console.log("enumsDefinitionXmlObject:");
						console.log($(enumsDefinitionXmlObject));
					}
				}
			}
			var parentObj = document.getElementById(cont4);
			var mainObj = document.createElement("div");
			mainObj.setAttribute("id", cont3);
			mainObj.setAttribute("style", "position: fixed; height: 130px; width: 600px; top: 50%; left: 50%; margin-left: -300px; margin-top: -65px; color: red; font-size: 40px; display: none;");
			
			//read choosen theme name
			themeName = $(configXmlObject).find('general')[0].attributes['themeName'].value;
			window.themeName = themeName;
			window.theme = new ThemeClass($($(themeXmlObject).find(themeName)[0]), themeName);
			
			//read lexicon name
			lexiconName = $(configXmlObject).find('general')[0].attributes['lexicon'].value;
			window.choosenLexicon = new Lexicon(lexiconsXmlObject, lexiconName);
			
			//read clock mode
			clockMode = Math.round($(configXmlObject).find('general')[0].attributes['clockMode'].value);
			
			//read type of Float separator
			floatSeparator = $(configXmlObject).find('general')[0].attributes['floatSeparator'].value;

			//read dialog window
			dialogWindowXmlObject = $(configXmlObject).find('dialogWindow');
			
			//read network policies - create ModbusRequestContainer foreach policy
			var network = $(networkXmlObject).find("readPolicy");	
			if(Math.round(network.length) > 0) {
				for(var i = 0; i < Math.round(network.length); i++) {
					if(network[i].parentNode.localName == "network") {
						var pointerOnObject = new ModbusRequestContainer(network[i].attributes.name.value, network[i].attributes.poll.value, clockMode);
						window.modbusReader.push(pointerOnObject);
					}
					else {
						console.log("'networkPolicy' XML object found inside bad parent: '" + network[i].parentNode.localName + "'. Proper parent is 'network'.");
					}
				}
			}
			else {
				console.log("no 'networkPolicy' found in XML file!!!");
			}	
			
			//
			//build view
			//
			
			//body
			CommonIncludes.checkContainerAndReadProperties($(configXmlObject).find("general"), null, generalProperties);
			
			//logoContainer
			var reducedConfigXmlObject = $(configXmlObject).find("logoContainer");
			var objPointer = new BasicContainer(reducedConfigXmlObject, "mainContainer");
			containers.push(objPointer);
			CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "logoContainer", CommonIncludes.imageWithHyperlinkContainerProperties, true, "site", {parentId: "logoContainer", id: "logo", alt: "image centered", type: "a"});
		console.log("logoContainer inited");
		
			//topTextContainer
			reducedConfigXmlObject = $(configXmlObject).find("topTextContainer");
			objPointer = new BasicContainer(reducedConfigXmlObject, "mainContainer");
			containers.push(objPointer);
			CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "topTextContainer", CommonIncludes.topTextContainerProperties, true, "site", "label");
		console.log("topTextContainer inited");
		
			//dateTimeContainer
			reducedConfigXmlObject = $(configXmlObject).find("dateTimeContainer");
			objPointer = new BasicContainer(reducedConfigXmlObject, "mainContainer");
			containers.push(objPointer);
			CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "dateTimeContainer", CommonIncludes.dateTimeContainerProperties, false, "site", {dateTimePoints: dateTimePoints, buttons: buttons, clockMode: clockMode, userName: userName});
		console.log("dateTimeContainer inited");
		
			//sharedContainer for setPointsHeaderContainer and setPointsContainer
			CommonIncludes.createSharedContainer("sharedSetPointsContainer", "BasicContainer", "mainContainer");
			
			//setPointsContainer
			printHeaderWithContainer(configXmlObject, "set", "sharedSetPointsContainer", setPointsContainerProperties);
		
			//sharedContainer for numericPointsHeaderContainer and numerictPointsContainer
			CommonIncludes.createSharedContainer("sharedNumericPointsContainer", "BasicContainer", "mainContainer");
			
			//numericPointsContainer
			printHeaderWithContainer(configXmlObject, "numeric", "sharedNumericPointsContainer", numericPointsContainerProperties);
		
			//sharedContainer for statusPointsHeaderContainer and statusPointsContainer
			CommonIncludes.createSharedContainer("sharedStatusPointsContainer", "BasicContainer", "mainContainer");//sharedAlarmPointsContainer
		
			//statusPointsContainer
			printHeaderWithContainer(configXmlObject, "status", "sharedStatusPointsContainer", booleanPointsContainerProperties, false, "site", {parentId: "statusPointsContainer", stylesClass: "StatusPoint", pointsArray: statusPoints, pointsMax: statusPointsMax});
		
			//sharedContainer for imageContainer, alarmPointsHeaderContainer and alarmPointsContainer
			CommonIncludes.createSharedContainer("sharedImageAlarmPointsContainer", "BasicContainer", "mainContainer");//sharedImageStatusPointsContainer
			
			//imageContainer
			reducedConfigXmlObject = $(configXmlObject).find("imageContainer");
			objPointer = new BasicContainer(reducedConfigXmlObject, "sharedImageAlarmPointsContainer");
			containers.push(objPointer);
			CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "imageContainer", imageContainerProperties);
		console.log("imageContainer inited");
			
			//alarmPointsContainer
			printHeaderWithContainer(configXmlObject, "alarm", "sharedImageAlarmPointsContainer", booleanPointsContainerProperties, false, "site", {parentId: "alarmPointsContainer", stylesClass: "AlarmPoint", pointsArray: alarmPoints, pointsMax: alarmPointsMax});

			//buttonsContainer
			reducedConfigXmlObject = $(configXmlObject).find("buttonsContainer");
			objPointer = new BasicContainer(reducedConfigXmlObject, "mainContainer");
			containers.push(objPointer);
			CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "buttonsContainer", buttonsContainerProperties, false);
		console.log("buttonsContainer inited");

			//dialogWindow
			var valueAttributes = {"unit": "", "scale": 1.0, "floatSeparator": floatSeparator, "enum": "", "falseText": "false", "trueText": "true", "clockMode": clockMode};
			dialogWindow = new DialogWindow(dialogWindowXmlObject, "site", valueAttributes, enumsDefinitionXmlObject);
			window.dialogWindow = dialogWindow;
			parentObj.appendChild(mainObj);
			mainObj.innerHTML = cont5;
		console.log("dialogWindow inited");
			
		// Run Modbus netwosks (fast, normal and low)
			runModbusDriver0();
			runModbusDriver1();
			runModbusDriver2();
			checkDevice();
		}
	}); //end of config read
}

//callback function for  Modbus TCP Network number 0
function runModbusDriver0() {
	runModbusDriver(window.modbusReader[0], runModbusDriver0);
}

//callback function for  Modbus TCP Network number 1
function runModbusDriver1() {
	runModbusDriver(window.modbusReader[1], runModbusDriver1);
}

//callback function for Modbus TCP Network number 2
function runModbusDriver2() {
	runModbusDriver(window.modbusReader[2], runModbusDriver2);
}

//function runs Modbus TCP Network instance as a cycle task
function runModbusDriver(modbusReaderInstance, callBackFunction) {
	//static var i = 0;
	if(modbusReaderInstance.requestList.length > 0 && modbusReaderInstance.getPollMode() == true) {
		var request = modbusReaderInstance.requestList;
		$.ajax({
			url:'do',
			type:'POST',
			data: {
				actions: request
			},
			success: function(res) {
				for(var i in res) {
					modbusReaderInstance.setRegisterValue(res[i]);
				}
				setTimeout(callBackFunction, modbusReaderInstance.pointRefreshFrequency);
			},//end success
			error : function() {
				//on error retry after 1 seconds
				console.log("Timeout request for " + modbusReaderInstance.name);
				setTimeout(callBackFunction, modbusReaderInstance.pointRefreshFrequency);
			},//end error
			async: false
		});//end AJAX
	}//end if
}

initialisation();

window.booleanSetPoints = booleanSetPoints;
window.numericSetPoints = numericSetPoints;
window.CommonIncludes = CommonIncludes;