//
//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 { StandardLabel } from '/sd:standard-label.js'; 
import { SelectableField } from '/sd:selectable-field.js'; 
import { EventField } from '/sd:event-field.js';
import { ActionButton } from '/sd:action-button.js'; 
import { ActionButtonWithValue } from '/sd:action-button-with-value.js'
import { DialogWindow } from '/sd:dialog-window.js';
import { EnumDefinition } from '/sd:enum-definition.js';
import { ContextMenu } from '/sd:context-menu.js';
import { Lexicon } from '/sd:lexicon.js';
import { Point } from '/sd:point.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 buttons = new Array();
var hoursLabels = new Array();
var daysHoursFields = new Array();
var daysEvents = new Array();
var detailsPoints = new Array();
var selectedEventPoints = new Array();
var dateTimePoints = new Array();
var dialogWindow = null;
var contextMenu = null;

var currentDay = 1;
var myFileName = "";
var userPermission = 0;
var userName = "";
var themeName = null;
var schedulers = null;
var general = null;
var addressFactor = 0;
var startModbusAddress = null;
var modbusRegForRestValues = null;
var modbusRegForDefaultValue = null;
var decimalPlaces = null;
var pointRefreshFrequency = null;
var clockMode = null;
var lexiconName = null;
var valueAttributes = null;
var eventsPerDay = 8;
var lastEventsPerDay = -1;
var schedulerType = "unknown";
var schedulerPermissionLevel = 0;
let scheduleConfiguration = { "name": "ConfigurationRegister", "value": "unknown" };
let defaultValue = { "name": "DefaultValue", "value": "unknown" };
let currentOutput = { "name": "CurrentOutput", "value": "unknown" };
let nextEventValue = { "name": "NextEventValue", "value": "unknown" };
let contextMenuOptionsActions = ["openPopupWindow(this.id, window.selectedField);", "openPopupWindow(this.id, window.selectedEvent);", "copyDay(window.selectedEvent, window.selectedField);", "pasteDay(window.selectedEvent, window.selectedField, window.copiedDayToStorage);", "pasteDays(window.selectedEvent, window.selectedField, 5);", "pasteDays(window.selectedEvent, window.selectedField, 7);", "removeAllDayEvents(window.selectedEvent, window.selectedField);", "removeClearAllWeek();", "removeEvent(window.selectedEvent);"];

const DEBUG_MODE = false;

const eventsShift = 12;
const eventsPerDayMax = 8;

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 = "sch" + "ed" + "ule" + "rs";
var cont5 = "No" + "n " + "AA" + "C2" + "0 " + "co" + "nt" + "ro" + "ll" + "er" + " d" + "et" + "ec" + "ted";
var contextMenuXmlObject;
var dialogWindowXmlObject;
var enumsDefinitionXmlObject;

/**
 * function reads general settings of specified schedule file, and sets Title of web site
 * @param {jQuery} xmlObject 		Data read from XML file
 * @param {String} fileName 		Schedule file name without file extension, and without file name suffix (template name and "_" char)
 * @returns {jQuery}				Attributes of chosen scheduler, child of general markup in XML file 
 */
function generalSettingsOfSchedule(xmlObject, fileName)
{
	var tabObj = document.getElementById("webTitle");
	for(var i = 0; i < xmlObject.length; i++) {
		if(xmlObject[i].attributes.filename.value == fileName) {
			tabObj.innerHTML = xmlObject[i].attributes.webtitle.value;
			return xmlObject[i].attributes;
		}
	}
}

/**
 * callback function reads general (eg. 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, "schedulers");
}

/**
 * callback function reads hoursContainerProperties properties of template from config XML file and it create this container(with these values) in HTML file. It creates all 24 hours inside the continer 
 * @param {jQuery} xmlObject 		Collection of hoursContainer markup read from XML file
 */
function hoursContainerProperties(xmlObject) {
	//dayHourOdd
	var dayHourXmlObjects = xmlObject.find("dayHour");
	var count = Math.round(xmlObject[0].attributes['count'].value);
	if(count > 24) {
		count = 24;
	}
	var objPointer = null;
	for(var i = 0; i < count; i++) {
		//Odd - index starts from 0, number of our starts with 1
		objPointer = new SelectableField(dayHourXmlObjects, "hoursContainer", "StaticField", null, null, null, i, "schedulerRowHour", false);
		objPointer.setTextValue(BasicContainer.convertIntTimeToString(i * 60, null, clockMode)); 
		hoursLabels.push(objPointer);
	}
}

/**
 * callback function reads dayContainer 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  		Collection of dayContainer markup read from XML file
 */
function dayContainerProperties(xmlObject) {
	//dayHourOdd
	var dayHourXmlObjects = xmlObject.find("dayHour");
	var scheduleEventXmlObjects = xmlObject.find("scheduleEventOdd, scheduleEventEven");
	var count = Math.round(xmlObject[0].attributes['count'].value);
	
	if(count > 24) {
		count = 24;
	}
	var objPointer = null;
	//hours fields in day
	for(var i = 0; i < count; i++) {
		//Odd - index starts from 0, number of our starts with 1
		objPointer = new SelectableField(dayHourXmlObjects, "dayContainer" + String(currentDay), "DefaultField", "window.contextMenu.setVisibility(false, 'field')", "window.contextMenu.setVisibility(true, 'field')", "findSelectedAndUnselectIt();selectField(this.id);return false", i, "schedulerRowDay" + String(currentDay) + "Hour");
		daysHoursFields.push(objPointer);
	}

	//events in day array
	var events = new Array();
	var eventObjectId = "schedulerDay" + String(currentDay) + "Event";
	for(var i = 0; i < (eventsPerDayMax); i++) {
		//Odd - index starts from 0, number of our starts with 1
		objPointer = new EventField(scheduleEventXmlObjects, "dayContainer" + String(currentDay), "DefaultScheduleEvent", null, "window.contextMenu.setVisibility(true, 'event')", "findSelectedAndUnselectIt();selectScheduleEvent(this.id);return false", i, eventObjectId, valueAttributes, enumsDefinitionXmlObject);
		events.push(objPointer);
	}
	//Add events array of nex day to global array
	daysEvents.push(events);
}

/**
 * callback function reads schedulerDetailsContainerProperties properties of template from config XML file and it create this container(with these values) in HTML file.
 * @param {jQuery} xmlObject 		Collection of schedulerDetailsContainer markup read from XML file
 */
function schedulerDetailsContainerProperties(xmlObject) {
	var count = Math.round(xmlObject[0].attributes['count'].value);
	
	if(count > 3) {
		count = 3;
	}
	//schedulerDetail
	makeDetail(xmlObject, "currentOutput", "schedulerDetailsContainer", "SchedulerDetail");
	makeDetail(xmlObject, "defaultValue", "schedulerDetailsContainer", "SchedulerDetail", false, "openPopupWindow(this.id);findSelectedAndUnselectIt();return false;");
	makeDetail(xmlObject, "nextEventValue", "schedulerDetailsContainer", "SchedulerDetail");

	if(detailsPoints.length < count)
		console.log("Too less quantity of points define in XML file for schedulerDetailsContainer !!!");
	else if(detailsPoints.length > count)
		console.log("Too many quantity of points define in XML file for schedulerDetailsContainer !!!");
}

/**
 * callback function reads selectedEventDetailsContainerProperties of template from config XML file and it create this container(with these values) in HTML file.
 * @param {jQuery} xmlObject 		Collection of selectedEventDetailsContainer markup read from XML file
 */
function selectedEventDetailsContainerProperties(xmlObject) {
	var count = Math.round(xmlObject[0].attributes['count'].value);
	
	if(count > 3) {
		count = 3;
	}
	//eventDetail
	makeDetail(xmlObject, "currentEventStartTime", "selectedEventDetailsContainer", "EventDetail");
	makeDetail(xmlObject, "currentEventStopTime", "selectedEventDetailsContainer", "EventDetail");
	makeDetail(xmlObject, "currentEventValue", "selectedEventDetailsContainer", "EventDetail");

	if(selectedEventPoints.length < count)
		console.log("Too less quantity of points define in XML file for selectedEventDetailsContainer !!!");
	else if(selectedEventPoints.length > count)
		console.log("Too many quantity of points define in XML file for selectedEventDetailsContainer !!!");
}

/**
 * makes schedulerDetail or selectedEventDetail
 * @param {jQuery} xmlObject 				Collection of parent of eventDetail/schedulerDetail markup read from XML file
 * @param {String} id 						ID of eventDetail/schedulerDetail markup; ID for the new append HTML object
 * @param {String} parentId 				ID of the object, wich will be a parent (container) of the new HTML object ("detail" element)
 * @param {String} className 				Class anme of the new HTML object ("detail" element)
 * @param {Boolean} readOnly 				If true, then new HTML object will be readOnly, if false, then it also will be able to click
 * @param {String} lmbClickAction 			If is neccessary if readOnly is equal to false only; it specifies action invoked "onclick" the HTML object
 */
function makeDetail(xmlObject, id, parentId, className, readOnly=true, lmbClickAction=null) {
	var eventDetailXmlObjects = xmlObject.find("#" + id);
	var objPointer = null;
	objPointer = new BasicContainer(eventDetailXmlObjects, parentId, className, null, id);
	objPointer = new StandardLabel(eventDetailXmlObjects, id, className + "TopLabel", null, id + "topLabel");
	objPointer.setTextValue(window.choosenLexicon.getLexiconMarkupText(id + "Label"));
	
	objPointer = (readOnly) ? new StandardLabel(eventDetailXmlObjects, id, className + "Value", null, id + "value") : new ActionButtonWithValue(eventDetailXmlObjects, id, lmbClickAction, null, className + "Value", id + "value", pointRefreshFrequency, null, "all", valueAttributes, enumsDefinitionXmlObject);
	//TODO - for boolean need to have setBitNumber and it needs to be updated in each polling
	if(className == "SchedulerDetail") {
		detailsPoints.push(objPointer);
	}
	else if(className == "EventDetail") {
		selectedEventPoints.push(objPointer);
	}
}

/**
 * updates value of scheduler detail 
 * @param {Object} val 			Value read from Modbus, which has to be saved schedulerDetail element 
 * @param {Integer} index 		Determines, which element of detailsPoints Array has to be updated with new value
 */
function updateSchedulerDetailValue(val, index) {
	var outputValue = null;
	if(schedulerType == "numeric") {
		var value = parseFloat(val) * parseFloat(valueAttributes.scale);
		outputValue = Point.useChosenSeparator(String((value).toFixed(decimalPlaces)), valueAttributes.floatSeparator) + "&nbsp;&nbsp;" + String(valueAttributes.unit);
	}
	else if(schedulerType == "enum") {
		var enumObj = new EnumDefinition(enumsDefinitionXmlObject, valueAttributes.enum);
		outputValue = enumObj.getLabelByVal(val);
	}
	else if(schedulerType == "boolean") {
		outputValue = (val == 0) ? ((valueAttributes.falseText != "" && valueAttributes.falseText != null) ? valueAttributes.falseText : "false") : ((valueAttributes.trueText != "" && valueAttributes.trueText != null) ? valueAttributes.trueText : "true");
	}
	else
		console.log("Wrong type of scheduler: " + String(schedulerType));
	detailsPoints[index].setTextValue(outputValue);
}

/**
 * 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
 * @param {jQuery} xmlObject  			Collection of buttonsContainer markup read from XML file
 */
function buttonsContainerProperties(xmlObject) {
	//buttons
	var buttonXmlObjects = xmlObject.find("addEventButton");
	var objPointer =  new ActionButton(buttonXmlObjects, "buttonsContainer", "openPopupWindow(this.id, window.selectedField);return false;");
	objPointer.setLabelText(window.choosenLexicon.getLexiconMarkupText("addEventButtonLabel"));
	buttons.push(objPointer);
}

/**
 * function invoked by SelectableField class instances (e.g. hours of the days in weekly calendar) to select that field
 * @param {String} id 		ID of SelectableField instance
 */
function selectField(id) {
	window.selectedField = id;
	for(var i = 0; i < daysHoursFields.length; i++) {
		if(daysHoursFields[i].getId() == id) {
			daysHoursFields[i].selectField();
			break;
		}
	}
}

/**
 * function invoked by EventField class instances to highlight selected event and show its details in Event detail container
 * @param {String} id 		ID of EventField instance
 */
function selectScheduleEvent(id) {
	window.selectedEvent = id;
	console.log("window.selectedEvent: " + String(window.selectedEvent));
	var day = id.substring(12,13);
	day = parseInt(day) - 1;
	for(var i = 0; i < daysEvents[day].length; i++) {
		if(daysEvents[day][i].getId() == id) {
			//select event
			daysEvents[day][i].selectField();
			//set Details of selected event
			selectedEventPoints[0].setTextValue(BasicContainer.convertIntTimeToString(daysEvents[day][i].getStartTime(), null, clockMode));
			selectedEventPoints[1].setTextValue(BasicContainer.convertIntTimeToString(daysEvents[day][i].getStopTime(), null, clockMode));
			selectedEventPoints[2].setTextValue(daysEvents[day][i].getValueWithFacets());
			break;
		}
	}
}

/**
 * function searches all selected SelectableFields and EventFields, and then unselects them
 */
function findSelectedAndUnselectIt() {
	//reset Details of selected event
	for(var i = 0; i < 3; i++) {
		selectedEventPoints[i].setTextValue("");
	}
	//unselect hour fields
	for(var i = 0; i < daysHoursFields.length; i++) {
		if(daysHoursFields[i].getSelectionStatus()) {
			daysHoursFields[i].unselectField();
			window.selectedField = null;
			break;
		}
	}
	//unselect events
	for(var i = 0; i < daysEvents.length; i++) {
		for(var j = 0; j < daysEvents[i].length; j++) {
			if(daysEvents[i][j].selected == true) {
				daysEvents[i][j].unselectField();
				window.selectedEvent = null;
				break;
			}
		}
	}
}

/**
 * opens popup window (DialogWindow)
 * @param {String} id 					ID of HTML object, which invoked this function
 * @param {String} idSelectedElement 	ID of selected hour field or event field
 */
function openPopupWindow(id, idSelectedElement) {
	if(id == "defaultValuevalue") { // standard value
		window.dialogWindow.show(detailsPoints[1]);
	}
	else { // Event
		var notOpened = true;
		console.log(id);
		var minute = 0;
		//decode dayIndex and hour of selected HTML object
		if(id == "addEventButton") {
			var hour = 0;
			var dayIndex = 0;
			if(daysEvents[dayIndex][0].getDefault() == false && daysEvents[dayIndex][0].getStartTime() == 0) {
				for(var i=1; i < eventsPerDay; i++) {
					if(daysEvents[dayIndex][i].getDefault()) {
						hour = daysEvents[dayIndex][i-1].getStopTime() / 60;
						minute = daysEvents[dayIndex][i-1].getStopTime() % 60;
						break;
					}
				}
			}
		}
		else {
			var hour = BasicContainer.decodeFieldNumber(idSelectedElement);
			var dayIndex = BasicContainer.decodeDayNumber(idSelectedElement) - 1;
		}
		//console.log("hour: " + String(hour) + ", minute: " + String(minute) + ", dayIndex: " + String(dayIndex));

		if(id == "contextMenuAdd" || id == "addEventButton") { //Add option in Context Menu or Add Event button
			console.log("contextMenuAdd or addEventButton");
			for(var i=0; i < eventsPerDay; i++) {
				if(daysEvents[dayIndex][i].getDefault() && daysEvents[dayIndex][i].getStartTime() == 1500 && daysEvents[dayIndex][i].getStopTime() == 1500) {//Changes
					daysEvents[dayIndex][i].setPointType(schedulerType);
					if(schedulerType != "boolean")
						daysEvents[dayIndex][i].setDecimalPlaces(decimalPlaces);

					var stopTime = (EventField.freeEventsQuantity(daysEvents[dayIndex], eventsPerDay)) ? (hour + 1) * 60 + minute : 1500;
					EventField.setEvent(daysEvents[dayIndex], i, eventsPerDay, hour * 60 + minute, stopTime, true, 0, schedulerType);

					//TODO verify 
					//daysEvents[dayIndex][i].setModbusRegisterAddress(window.modbusReader[ModbusRequestContainer.findModbusNetworkIndex(pointRefreshFrequency, window.modbusReader)], startModbusAddress + addressFactor * (dayIndex * eventsPerDay + i));
					//console.log("eventIndex: " + String(i));
					DialogWindow.ShowDialogWindow("schedulerDay" + String(dayIndex+1) + "Event" + String(i), window.dialogWindow, daysEvents, eventsPerDay, true);
					notOpened = false;
					break;
				}
				/*else {
					console.log("ind: " + String(daysEvents[dayIndex][i].getDefault()) + ", start: " + String(daysEvents[dayIndex][i].getStartTime()) + ", stop: " + String(daysEvents[dayIndex][i].getStopTime()));
				}*/
			}
		}
		else if(id == "contextMenuEdit") { //Edit option in Context Menu
			console.log("contextMenuEdit");
			DialogWindow.ShowDialogWindow(idSelectedElement, window.dialogWindow, daysEvents, eventsPerDay);
			notOpened = false;
		}
		if(notOpened) {	//if any of above
			var eventIndex = EventField.findFirstFreeDefaultEvent(daysEvents[dayIndex], 0, hour * 60 + minute, (hour + 1) * 60 + minute);
			if(eventIndex >= 0) {
				daysEvents[dayIndex][eventIndex].setPointType(schedulerType);
				if(schedulerType != "boolean")
					daysEvents[dayIndex][eventIndex].setDecimalPlaces(decimalPlaces);
				EventField.setEvent(daysEvents[dayIndex], eventIndex, eventsPerDay, hour * 60 + minute, (hour + 1) * 60 + minute, false, 0, schedulerType);
				DialogWindow.ShowDialogWindow("schedulerDay" + String(dayIndex+1) + "Event" + String(eventIndex), window.dialogWindow, daysEvents, eventsPerDay);
			}
			else {
				var newEventIndex = EventField.findTheClostestDefaultEvent(daysEvents[dayIndex], hour * 60 + minute);
				if(newEventIndex >= 0) {
					DialogWindow.ShowDialogWindow("schedulerDay" + String(dayIndex+1) + "Event" + String(newEventIndex), window.dialogWindow, daysEvents, eventsPerDay);
				}
				else {
					var arrayOfFields = ["none", "none", "none", "block", "block", "block"];
					if(schedulerType == "enum")
						arrayOfFields[1] = "block";
					else if(schedulerType == "numeric")
						arrayOfFields[2] = "block";
					else if(schedulerType == "boolean")
						arrayOfFields[0] = "block";
					window.dialogWindow.showDialogWithError("dialogWindowWarning", "dialogWindowStartTime", arrayOfFields, (id == "addEventButton") ? "schedulerRowDay1Hour0" : idSelectedElement);
					var firstDefault = EventField.findFirstDefaultEvent(daysEvents[dayIndex]);
					DialogWindow.ShowDialogWindow("schedulerDay"  + String(dayIndex+1) + "Event" + String((id == "addEventButton" && firstDefault >= 0) ? firstDefault : eventIndex), window.dialogWindow, daysEvents, eventsPerDay);
				}
			}
		}
	}
}

/**
 * removes selected Event
 * function attached to Remove Event option of Context Menu
 * @param {String} idSelectedElement 	ID of selected hour field or event field
 */
function removeEvent(idSelectedElement) {
	var dayIndex = BasicContainer.decodeDayNumber(idSelectedElement) - 1;
	var eventIndex = BasicContainer.decodeFieldNumber(idSelectedElement);
	var curEvent = daysEvents[dayIndex][eventIndex];
	curEvent.setDefault(true);
	curEvent.setValue(0);
	console.log("eventIndex: " + String(eventIndex));
	if(eventIndex == 0) {	//if removing first event
		//delete current event
		EventField.setEvent(daysEvents[dayIndex], eventIndex, eventsPerDay, 1500, 1500, true, 0, schedulerType);
		if(daysEvents[dayIndex][eventIndex + 1].getDefault() == true) {	//if next is default, then move it to the botow of events array
			EventField.setEvent(daysEvents[dayIndex], eventIndex + 1, eventsPerDay, 1500, 1500, null, null, schedulerType);
			if(daysEvents[dayIndex][eventIndex + 2].getDefault() == true) { //if two next event is also default, then it means, that all events are default
				//just send
				daysEvents[dayIndex][eventIndex].sendCurrentValuesByModbus();
				daysEvents[dayIndex][eventIndex+1].sendCurrentValuesByModbus();
			}
			else {
				//sort and send
				EventField.dayEventsSorting(daysEvents[dayIndex], eventsPerDay, eventsPerDayMax);
			}
		}
		else {
			//sort and send
			EventField.dayEventsSorting(daysEvents[dayIndex], eventsPerDay, eventsPerDayMax);
		}
	}
	else if(eventIndex < (eventsPerDayMax - 1)) {	//if it isn't first event, and isn't last
		if(daysEvents[dayIndex][eventIndex + 1].getDefault() == true || daysEvents[dayIndex][eventIndex - 1].getDefault() == true) { //if one of previous or next events is default
			if((daysEvents[dayIndex][eventIndex + 1].getDefault() == true) && (daysEvents[dayIndex][eventIndex - 1].getDefault() == true)) {//if both (previous and next) are default
				EventField.setEvent(daysEvents[dayIndex], eventIndex - 1, eventsPerDay, null, daysEvents[dayIndex][eventIndex + 1].getStopTime(), null, null, schedulerType);
				EventField.setEvent(daysEvents[dayIndex], eventIndex + 1, eventsPerDay, 1500, 1500, true, 0, schedulerType);
				EventField.setEvent(daysEvents[dayIndex], eventIndex, eventsPerDay, 1500, 1500, true, 0, schedulerType);
				//send
				daysEvents[dayIndex][eventIndex - 1].sendCurrentValuesByModbus();
				daysEvents[dayIndex][eventIndex + 1].sendCurrentValuesByModbus();
				daysEvents[dayIndex][eventIndex].sendCurrentValuesByModbus();
			}
			else if(daysEvents[dayIndex][eventIndex + 1].getDefault() == true) { //if next only is default
				daysEvents[dayIndex][eventIndex + 1].setStartTime(curEvent.getStartTime());
				EventField.setEvent(daysEvents[dayIndex], eventIndex, eventsPerDay, 1500, 1500, true, 0, schedulerType);
				//send
				EventField.dayEventsSorting(daysEvents[dayIndex], eventsPerDay, eventsPerDayMax, true);
			}
			else if(daysEvents[dayIndex][eventIndex - 1].getDefault() == true) { //if previous only is default
				daysEvents[dayIndex][eventIndex - 1].setStopTime(curEvent.getStopTime());
				EventField.setEvent(daysEvents[dayIndex], eventIndex, eventsPerDay, 1500, 1500, true, 0, schedulerType);
				//send
				EventField.dayEventsSorting(daysEvents[dayIndex], eventsPerDay, eventsPerDayMax, true);
			}
			else { //send changes in current event only
				EventField.setEvent(daysEvents[dayIndex], eventIndex, eventsPerDay, 1500, 1500, true, 0, schedulerType);
				EventField.dayEventsSorting(daysEvents[dayIndex], eventsPerDay, eventsPerDayMax, true);
			}
		}
		else {//if event is a sibling of 2 not default event, then don't change start and stop times, but change it to default
			daysEvents[dayIndex][eventIndex].sendCurrentValuesByModbus();
		}
	}
	else {//if it is last event, then 
		if(daysEvents[dayIndex][eventIndex - 1].getDefault() == true) {//if previous event is default, then change its stoptime, and set times for this event to 1500
			EventField.setEvent(daysEvents[dayIndex], eventIndex, eventsPerDay, 1500, 1500, null, null, schedulerType);
			daysEvents[dayIndex][eventIndex - 1].setStopTime(1500);
			daysEvents[dayIndex][eventIndex - 1].sendCurrentValuesByModbus();
		}
		else {

		}
		daysEvents[dayIndex][eventIndex].sendCurrentValuesByModbus();
	}
	findSelectedAndUnselectIt();
}

/**
 * removes all Events in selected day
 * function attached to Clear Day option of Context Menu
 * @param {String} idSelectedEvent 	ID of selected event field
 * @param {String} idSelectedField 	ID of selected hour field
 */
function removeAllDayEvents(idSelectedEvent, idSelectedField) {
	var idSelectedElement = (idSelectedEvent != null) ? idSelectedEvent : idSelectedField;
	var dayIndex = EventField.decodeDayNumber(idSelectedElement) - 1;
	removingDaysEvents(dayIndex, dayIndex);
	console.log("Day " + String(dayIndex) + " cleared");
	updateEvents(dayIndex);
	findSelectedAndUnselectIt();
}

/**
 * removes all Events in the week
 * function attached to Clear All option of Context Menu
 */
function removeClearAllWeek() {
	removingDaysEvents(0, 6);
	console.log("All week cleared");
	updateEvents();
	findSelectedAndUnselectIt();
}

/**
 * Sets all events in indicated day as default events, and sets their start and stop Times as 1500 
 * @param {Integer} dayIndex 		Index of choosen day to clear all events
 */
function removingDaysEvents(startDayIndex, endDayIndex, disablePolling = true) {
	if(disablePolling)
		setPollingInModbusDrivers(false);
	for(var dayIndex = startDayIndex; dayIndex <= endDayIndex; dayIndex++) {
		for(var i = 0; i < eventsPerDay; i++) {
			EventField.setEvent(daysEvents[dayIndex], i, eventsPerDay, 1500, 1500, true, 0, schedulerType);
		}
	}
	EventField.sendMultipleEventsByModbus(daysEvents, startDayIndex, endDayIndex, 0, (eventsPerDay - 1), eventsPerDay);
	if(disablePolling)
		setPollingInModbusDrivers(true);
}

/**
 * copy day index to the storage
 * function attached to Copy Day option of Context Menu
 * @param {String} idSelectedEvent 	ID of selected event field
 * @param {String} idSelectedField 	ID of selected hour field
 */
function copyDay(idSelectedEvent, idSelectedField) {
	var idSelectedElement = (idSelectedEvent != null) ? idSelectedEvent : idSelectedField;
	window.copiedDayToStorage = EventField.decodeDayNumber(idSelectedElement) - 1;
	console.log("Day with index: " + String(window.copiedDayToStorage) + " was copied");
}

/**
 * paste day from the storage to the selected day
 * function attached to Paste Day option of Context Menu
 * @param {String} idSelectedEvent 	ID of selected event field
 * @param {String} idSelectedField 	ID of selected hour field
 */
function pasteDay(idSelectedEvent, idSelectedField, sourceDay, disablePolling = true) {
	if(disablePolling)
		setPollingInModbusDrivers(false);
	if(sourceDay >= 0 && sourceDay < 7) {
		var idSelectedElement = (idSelectedEvent != null) ? idSelectedEvent : idSelectedField;
		if(idSelectedElement != null) {
			var dayIndex = EventField.decodeDayNumber(idSelectedElement) - 1;
			if(dayIndex != sourceDay && (dayIndex >= 0 && dayIndex < 7)) {
				for(var i = 0; i < eventsPerDay; i++) {
					EventField.setEvent(daysEvents[dayIndex], i, eventsPerDay, daysEvents[sourceDay][i].getStartTime(), daysEvents[sourceDay][i].getStopTime(), daysEvents[sourceDay][i].getDefault(), daysEvents[sourceDay][i].getValue(), daysEvents[sourceDay][i].getPointType());
				}
				EventField.sendMultipleEventsByModbus(daysEvents, dayIndex, dayIndex, 0, (eventsPerDay - 1), eventsPerDay);
			}
			else {
				console.log("Wrong day index! " + String(dayIndex));
			}
		}
		else {
			console.log("Wrong selected element!");
		}
	}
	else {
		console.log("Illegal sourceDay");
	}
	if(disablePolling)
		setPollingInModbusDrivers(true);
}

//
/**
 * paste selected day from Monday to each day until count-1
 * function attached to "Paste Day to Monday-Friday", and "Paste Day to All" option of Context Menu
 * @param {String} idSelectedEvent 	ID of selected event field
 * @param {String} idSelectedField 	ID of selected hour field
 */
function pasteDays(idSelectedEvent, idSelectedField, count) {
	var idSelectedElement = (idSelectedEvent != null) ? idSelectedEvent : idSelectedField;
	if(idSelectedElement != null) {
		var sourceDay = EventField.decodeDayNumber(idSelectedElement) - 1;
		if(sourceDay >= 0 && sourceDay < 7) {
			setPollingInModbusDrivers(false);
			//for all selectede days
			for(var dayIndex = 0; dayIndex < count; dayIndex++) {
				//for all events in the day
				for(var i = 0; i < eventsPerDay; i++) {
					EventField.setEvent(daysEvents[dayIndex], i, eventsPerDay, daysEvents[sourceDay][i].getStartTime(), daysEvents[sourceDay][i].getStopTime(), daysEvents[sourceDay][i].getDefault(), daysEvents[sourceDay][i].getValue(), daysEvents[sourceDay][i].getPointType());
				}
			}
			EventField.sendMultipleEventsByModbus(daysEvents, 0, (count - 1), 0, (eventsPerDay - 1), eventsPerDay);
			console.log(String(count) + " days starting from Monday were pasted");
		}
		else {
			console.log("Illegal sourceDay");
		}
	}
	else {
		console.log("Wrong selected element!");
	}
	setPollingInModbusDrivers(true);
}

/**
 * decodes value of first Modbus register address, sest scheduler to work as a Numeric or Boolean, and defines schedulerEvent array and modbus addresses of events
 */
function decodeConfigurationSavedInModbusFrame() {
	var registerValue = parseInt(scheduleConfiguration.value);
	addressFactor = 0;
	//decode type of scheduler - Numeric (Enum) or Boolean
	if((registerValue & 0x8000) == 0) {
		schedulerType = (valueAttributes.enum != null && valueAttributes.enum != "") ? "enum" : "numeric";
		addressFactor = 2;// 2 registers per event - first for startTime and second for value
		decimalPlaces = registerValue & 0x0003;
	}
	else {
		schedulerType = "boolean"
		addressFactor = 1;// 1 register per event - startTime and value in the same register
		//Default Value
		defaultValue.value = registerValue & 0x0001;
		//CurrentOutput
		currentOutput.value = registerValue & 0x0002;
		//NextEventValue
		nextEventValue.value = registerValue & 0x0004;
	}
	//set type for Default Value
	detailsPoints[1].setPointType(schedulerType);
	//decode events per day count
	eventsPerDay = ((0x7000 & registerValue) >> eventsShift) + 1;

	//if there was any change in eventsPerDay value
	if(lastEventsPerDay != eventsPerDay) {
		console.log("Update configuration");
		window.dialogWindow.setType(schedulerType);
		//delete old events' registers assignment if there was any assignment
		if(lastEventsPerDay != -1) {
			for(var i = 0; i < 7; i++) {
				//for each event of day
				for(var j = 0; j < eventsPerDayMax; j++) {
					daysEvents[i][j].removeModbusRegisterAddress(window.modbusReader[ModbusRequestContainer.findModbusNetworkIndex(pointRefreshFrequency, window.modbusReader)]);
				}
			}
		}

		//delete registers addresses dedicated for Default Value, CurrentOutput and NextEventValue for numeric and enum schedulers from ModbusRequestContainer
		window.modbusReader[ModbusRequestContainer.findModbusNetworkIndex(pointRefreshFrequency, window.modbusReader)].removeRegister(modbusRegForDefaultValue, 3);

		//for each day of week
		for(var i = 0; i < 7; i++) {
			//for each event of day
			for(var j = 0; j < eventsPerDay; j++) {
				daysEvents[i][j].setPointType(schedulerType);
				var status = daysEvents[i][j].setModbusRegisterAddress(window.modbusReader[ModbusRequestContainer.findModbusNetworkIndex(pointRefreshFrequency, window.modbusReader)], startModbusAddress + addressFactor * (i * eventsPerDay + j));
				daysEvents[i][j].setDecimalPlaces(decimalPlaces);

				if(!status)
					console.log("Day " + String(i+1) + ", Event " + String(j+1) + " register wasn't inited")
				//get stop time from next event
			}
		}

		//if scheduler is numeric or enum now, then set new modbus register addresses for Default Value, CurrentOutput and NextEventValue
		if(schedulerType == "numeric" || schedulerType == "enum") { 
			//init new registers
			//Default Value
			modbusRegForDefaultValue = startModbusAddress + 7 * 2 * eventsPerDay;
			detailsPoints[1].setModbusRegisterAddress(window.modbusReader[ModbusRequestContainer.findModbusNetworkIndex(pointRefreshFrequency, window.modbusReader)], modbusRegForDefaultValue, defaultValue, "int", "all", null, "object");
			detailsPoints[1].setDecimalPlaces(decimalPlaces);
			//CurrentOutput
			window.modbusReader[ModbusRequestContainer.findModbusNetworkIndex(pointRefreshFrequency, window.modbusReader)].initRegister(modbusRegForDefaultValue + 1, currentOutput, "int", "all", null, "object");
			//NextEventValue
			window.modbusReader[ModbusRequestContainer.findModbusNetworkIndex(pointRefreshFrequency, window.modbusReader)].initRegister(modbusRegForDefaultValue + 2, nextEventValue, "int", "all", null, "object");
		}
		else if(schedulerType == "boolean") {
			//init new registers
			//Default Value
			detailsPoints[1].setModbusRegisterAddress(window.modbusReader[ModbusRequestContainer.findModbusNetworkIndex(pointRefreshFrequency, window.modbusReader)], modbusRegForRestValues, defaultValue, "uint", "all", null, "object");
			//CurrentOutput
			window.modbusReader[ModbusRequestContainer.findModbusNetworkIndex(pointRefreshFrequency, window.modbusReader)].initRegister(modbusRegForRestValues, currentOutput, "uint", "all", null, "object");
			//NextEventValue
			window.modbusReader[ModbusRequestContainer.findModbusNetworkIndex(pointRefreshFrequency, window.modbusReader)].initRegister(modbusRegForRestValues, nextEventValue, "uint", "all", null, "object");
		}
	}
	lastEventsPerDay = eventsPerDay;

	var startTimeOfNextEvent;
	//update events
	for(var i = 0; i < 7; i++) {
		//for each event of day
		for(var j = 0; j < eventsPerDayMax; j++) {
			daysEvents[i][j].decodeModbusValues();
			if(j + 1 < eventsPerDay) {
				startTimeOfNextEvent = daysEvents[i][j+1].getStartTime();
				daysEvents[i][j].setStopTime((startTimeOfNextEvent >= 1440) ? 1500 : startTimeOfNextEvent);
			}
			daysEvents[i][j].setTextValue();
			daysEvents[i][j].updateHeight();
		}
	}

	//Update general values
	//CurrentOutput
	updateSchedulerDetailValue(currentOutput.value, 0);
	//Default Value
	detailsPoints[1].setValue(parseFloat(defaultValue.value) * parseFloat(valueAttributes.scale));
	updateSchedulerDetailValue(defaultValue.value, 1);
	//NextEventValue
	updateSchedulerDetailValue(nextEventValue.value, 2);
}

/**
 * updates (Text and Height) the indicated event or all events
 * @param {Object} day		Integer number in range <0-6> or String "all" for all days
 */
function updateEvents(day="all") {
	if(day == "all") {
		for(var i = 0; i < 7; i++) {
			//for each event of day
			for(var j = 0; j < eventsPerDayMax; j++) {
				daysEvents[i][j].setTextValue();
				daysEvents[i][j].updateHeight();
			}
		}
	}
	else {
		//for each event of day
		for(var j = 0; j < eventsPerDayMax; j++) {
			daysEvents[day][j].setTextValue();
			daysEvents[day][j].updateHeight();
		}
	}
}

/**
 * checks if host is iSMA-B-AAC20
 */
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 setPollingInModbusDrivers(value) {
	for(var i = 0; i < window.modbusReader.length; i++) {
		window.modbusReader[0].setPollMode(value);
	}
}

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

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

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

//
/**
 * function runs Modbus TCP Network instance as a cycle task
 * @param {ModbusRequestContainer} modbusReaderInstance 	Instance of ModbusRequestContainer
 * @param {Function} callBackFunction 						Callback function name
 */
function runModbusDriver(modbusReaderInstance, callBackFunction) {
	if(modbusReaderInstance.requestList.length > 0 && modbusReaderInstance.getPollMode() == true) {
		var request = modbusReaderInstance.requestList;
		//read all points in this polling configuration
		$.ajax({
			url:'do',
			type:'POST',
			data: {
				actions: request
			},
			success: function(res) {
				if(modbusReaderInstance.getPollMode() == true) {
					console.log(res);
					//if values will be read, then set registers values
					for(var i in res) {
						modbusReaderInstance.setRegisterValue(res[i]);
					}
					//Decode schedule configuration if configuration was read
					for(var i in res) {
						if(res[i].id == modbusRegForRestValues) {
							modbusReaderInstance.setPollMode(false);
							decodeConfigurationSavedInModbusFrame();
							modbusReaderInstance.setPollMode(true);
							break;
						}
					}
				}
				//set next polling time
				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
	else {
		setTimeout(callBackFunction, modbusReaderInstance.pointRefreshFrequency);
	}
}

/**
 * function initialize the schedule template	
 */
function initialisation() {
	//get the current file name
	var path = window.location.pathname;
	myFileName = path.split("/").pop();
	myFileName = (myFileName == "") ? "index" : myFileName.slice(0, -5);
	var templateName = myFileName.substring(0, myFileName.indexOf("schedule"));
	
	myFileName = myFileName.substring(myFileName.indexOf("schedule"));
	console.log("myFileName: " + String(myFileName));
	//var xmlFileName = window.location.protocol + "//" + window.location.host + "/sd:" + templateName + "config.xml";
	var xmlFileName = window.location.protocol + "//" + window.location.host + "/" + templateName + "config.xml";
	//var xmlFileName = window.location.protocol + "//" + window.location.host + "/" + templateName + "main_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 schedulers XML
				if($(data)[i].localName == "schedulers") {
					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 generalXmlObject = $(configXmlObject).find("general");
			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 = generalXmlObject[0].attributes['themeName'].value;
			window.themeName = themeName;
			window.theme = new ThemeClass($($(themeXmlObject).find(themeName)[0]), themeName);

			//get all schedulers
			schedulers = $(configXmlObject).find('scheduler');
			
			//read lexicon name
			lexiconName = generalXmlObject[0].attributes['lexicon'].value;
			console.log("lexiconName: " + String(lexiconName));
			window.choosenLexicon = new Lexicon(lexiconsXmlObject, lexiconName);
			
			//read clock mode
			clockMode = Math.round(generalXmlObject[0].attributes['clockMode'].value);
			console.log("clockMode: " + String(clockMode));
			

			//read type of Float separator
			var floatSeparator = generalXmlObject[0].attributes['floatSeparator'].value;
			console.log("floatSeparator: " + String(floatSeparator));
			
			var unit = "";
			var scale = 1.0;
			var enumName = "";
			var falseText = "";
			var trueText = "";
			//read data of specific scheduler
			for(var i = 0; i < 4; i++) {
				if(schedulers[i].attributes.fileName.value == myFileName) {
					//schedulerPermissionLevel
					schedulerPermissionLevel = (schedulers[i].attributes["permissionlevel"] != undefined) ? parseInt(schedulers[i].attributes["permissionlevel"].value) : parseInt(-1);
					if(schedulers[i].children[0].attributes.unit != undefined)		//unit
						unit = schedulers[i].children[0].attributes.unit.value;
					if(schedulers[i].children[0].attributes.scale != undefined) {	//scale
						scale = schedulers[i].children[0].attributes.scale.value;
						scale = scale.replace(",", ".");
					}
					if(schedulers[i].children[0].attributes.enum != undefined)		//enumName
						enumName = schedulers[i].children[0].attributes.enum.value;
					if(schedulers[i].children[0].attributes.falseText != undefined)	//falseText
						falseText = schedulers[i].children[0].attributes.falseText.value;
					if(schedulers[i].children[0].attributes.trueText != undefined)	//trueText
						trueText = schedulers[i].children[0].attributes.trueText.value;
					break;
				}
			}

			if(userPermission >= schedulerPermissionLevel) {
				valueAttributes = {"unit": unit, "scale": scale, "floatSeparator": floatSeparator, "enum": enumName, "falseText": falseText, "trueText": trueText, "clockMode": clockMode};

				//read context menu
				contextMenuXmlObject = $(configXmlObject).find('contextMenu');

				//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
				//

				//save functions in the window
				window.selectField = selectField;
				window.findSelectedAndUnselectIt = findSelectedAndUnselectIt;
				window.selectScheduleEvent = selectScheduleEvent;
				window.openPopupWindow = openPopupWindow;
				window.removeEvent = removeEvent;
				window.removeAllDayEvents = removeAllDayEvents;
				window.removeClearAllWeek = removeClearAllWeek;
				window.copyDay = copyDay;
				window.pasteDay = pasteDay;
				window.pasteDays = pasteDays;
				window.setPollingInModbusDrivers = setPollingInModbusDrivers;
				
				//body
				CommonIncludes.checkContainerAndReadProperties(generalXmlObject, null, generalProperties, true, "schedulers");
				general = generalSettingsOfSchedule(schedulers, myFileName);

				modbusRegForRestValues = parseInt(general.startingholdingregister.value);
				startModbusAddress = modbusRegForRestValues + 1;
				pointRefreshFrequency = general.pointRefreshFrequency.value;
				window.modbusReader[ModbusRequestContainer.findModbusNetworkIndex(pointRefreshFrequency, window.modbusReader)].initRegister(modbusRegForRestValues, scheduleConfiguration, "uint", "all", null, "object");

				//logoContainer
				var reducedConfigXmlObject = $(configXmlObject).find("logoContainer");
				var objPointer = new BasicContainer(reducedConfigXmlObject, "mainContainer");
				containers.push(objPointer);
				CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "logoContainer", CommonIncludes.imageWithHyperlinkContainerProperties, true, "schedulers", {parentId: "logoContainer", id: "logo", alt: "image centered", type: "a"});
			console.log("logoContainer inited");
			
				//topTextContainer
				objPointer = new BasicContainer($(configXmlObject).find("topTextContainer"), "mainContainer");
				containers.push(objPointer);
				CommonIncludes.topTextContainerProperties(general, "topTextContainerLabel");
			console.log("topTextContainer inited");
			
				//dateTimeContainer
				reducedConfigXmlObject = $(configXmlObject).find("dateTimeContainer");
				objPointer = new BasicContainer(reducedConfigXmlObject, "mainContainer");
				containers.push(objPointer);
				CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "dateTimeContainer", CommonIncludes.dateTimeContainerProperties, false, "schedulers", {dateTimePoints: dateTimePoints, buttons: buttons, clockMode: clockMode, userName: userName});
			console.log("dateTimeContainer inited");
			
				//sharedContainer for hoursHeaderContainer and hoursContainer
				CommonIncludes.createSharedContainer("sharedScheduleHoursContainer", "BasicContainer", "mainContainer");
				
				//hoursContainer
				//header
				reducedConfigXmlObject = $(configXmlObject).find("hoursHeaderContainer");
				objPointer = new BasicContainer(reducedConfigXmlObject, "sharedScheduleHoursContainer", "BasicContainer", null, null, true, null);
				containers.push(objPointer);
				
				CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "hoursHeaderContainer", CommonIncludes.imageWithHyperlinkContainerProperties, true, "schedulers", {parentId: "hoursHeaderContainer", id: "backImage", alt: "Previous page", type: "onclick"});
				//container
				reducedConfigXmlObject = $(configXmlObject).find("hoursContainer");
				objPointer = new BasicContainer(reducedConfigXmlObject, "sharedScheduleHoursContainer");
				containers.push(objPointer);
				CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "hoursContainer", hoursContainerProperties, false, "schedulers");
			console.log("hours inited");
				
				//make for each week day
				var sharedContainerName = null;
				var headerContainerName = null;
				var containerName = null;
				for(var i = 1; i <= 7; i++) {
					currentDay = i;
					sharedContainerName = "sharedScheduleDayContainer" + String(i);
					headerContainerName = "dayHeaderContainer" + String(i);
					containerName = "dayContainer" + String(i);
					//sharedContainer for dayHeaderContainer and dayContainer
					CommonIncludes.createSharedContainer(sharedContainerName, "BasicContainer", "mainContainer");
					
					//dayContainer
					//header
					reducedConfigXmlObject = $(configXmlObject).find(headerContainerName);
					objPointer = new BasicContainer(reducedConfigXmlObject, sharedContainerName);
					containers.push(objPointer);
					CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, headerContainerName, CommonIncludes.headerContainerProperties, false, "schedulers", {parentId: headerContainerName, id: "dayHeaderLabel", itemNumber: i, label: window.choosenLexicon.getLexiconMarkupText("day" + String(i))});
					
					//container
					reducedConfigXmlObject = $(configXmlObject).find(containerName);
					objPointer = new BasicContainer(reducedConfigXmlObject, sharedContainerName);
					CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, containerName, dayContainerProperties, false, "schedulers");
					console.log("day" + String(i) + " inited");
				}

				//schedulerDetailsContainer
				//header
				reducedConfigXmlObject = $(configXmlObject).find("schedulerDetailsHeaderContainer");
				objPointer = new BasicContainer(reducedConfigXmlObject, "mainContainer", "BasicContainer", null, null, true, null);
				containers.push(objPointer);
				CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "schedulerDetailsHeaderContainer", CommonIncludes.headerContainerProperties, false, "schedulers", {parentId: "schedulerDetailsHeaderContainer", id: "schedulerDetailsHeaderLabel", itemNumber: null, label: window.choosenLexicon.getLexiconMarkupText("schedulerDetailsHeader")});
				//container
				reducedConfigXmlObject = $(configXmlObject).find("schedulerDetailsContainer");
				objPointer = new BasicContainer(reducedConfigXmlObject, "mainContainer");
				containers.push(objPointer);
				CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "schedulerDetailsContainer", schedulerDetailsContainerProperties, false, "schedulers");
			console.log("scheduleDetails inited");

				//schedulerDetailsContainer
				//header
				reducedConfigXmlObject = $(configXmlObject).find("selectedEventDetailsHeaderContainer");
				objPointer = new BasicContainer(reducedConfigXmlObject, "mainContainer", "BasicContainer", null, null, true, null);
				containers.push(objPointer);
				CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "selectedEventDetailsHeaderContainer", CommonIncludes.headerContainerProperties, false, "schedulers", {parentId: "selectedEventDetailsHeaderContainer", id: "selectedEventDetailsHeaderLabel", itemNumber: null, label: window.choosenLexicon.getLexiconMarkupText("selectedEventDetailsHeader")});
				//container
				reducedConfigXmlObject = $(configXmlObject).find("selectedEventDetailsContainer");
				objPointer = new BasicContainer(reducedConfigXmlObject, "mainContainer");
				containers.push(objPointer);
				CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "selectedEventDetailsContainer", selectedEventDetailsContainerProperties, false, "schedulers");
			console.log("selectedEventDetails inited");
			
				//buttonsContainer
				reducedConfigXmlObject = $(configXmlObject).find("buttonsContainer");
				objPointer = new BasicContainer(reducedConfigXmlObject, "mainContainer");
				containers.push(objPointer);
				CommonIncludes.checkContainerAndReadProperties(reducedConfigXmlObject, "buttonsContainer", buttonsContainerProperties, false, "schedulers");
			console.log("buttonsContainer inited");
				
				//contextMenu
				contextMenu = new ContextMenu(contextMenuXmlObject, "schedulers", "contextMenu", "ContextMenu", ["event", "field"], contextMenuOptionsActions);
				contextMenu.setVisibility(false, null);
				window.contextMenu = contextMenu;
			console.log("contextMenu inited");

				//dialogWindow
				dialogWindow = new DialogWindow(dialogWindowXmlObject, "schedulers", 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();
				//check if AAC20
				checkDevice();
			}
			else { //if user permission level is too low
				var warningLabel = new StandardLabel(null, "mainContainer", "BasicContainer", null, "scheduleUserPermissionLevelTooLow", true);
				warningLabel.setTextValue(window.choosenLexicon.getLexiconMarkupText("scheduleUserPermissionLevelTooLow"));
			}
		}
	}); //end of config read
}
//start
initialisation();

window.CommonIncludes = CommonIncludes;