import { BasicContainer } from '/sd:basic-container.js'; 
import { DynamicImage } from '/sd:dynamic-image.js'; 
import { StandardLabel } from '/sd:standard-label.js'; 
import { ModbusRequestContainer } from '/sd:modbus-request-container.js'; 
//import { modbusReader } from '/sd:common-includes.js';

/**
 * class to create instance of boolean value displayer. It allows for define text or imgage value. In text mode it allows to define falseText and trueText. In image mode it allows to define type of active image (alarm or status). Class keeps the pointRefreshFrequency name, and assigns value to bit of Register of ModbusTCP Network according to the name of pointRefreshFrequency
 */
export class BooleanPoint extends BasicContainer {	
	/**
	 * Constructor
	 * @param {jQuery} xmlObject 		Data loaded from XML - accept boolean points part only
	 * @param {String} parentId 		HTML ID of the object, which has to be a parent of constructing boolean point
	 * @param {Integer} itemNumber 		Number of object constructing boolean point
	 * @param {String} pointMainClass 	Name of the CSS style's class of boolean point
	 * @param {String} valueType 		Type of boolean point value - "text" if falseText and trueText represent value, "image" if images represent value
	 * @param {String} falseText 		Text, which represents false value - needed for valueType equal to "text" - if null, then "false" will be displayed
	 * @param {String} trueText 		Text, which represents true value - needed for valueType equal to "text" - if null, then "true" will be displayed
	 * @param {String} themeName 		Name of chosen theme - needed for valueType equal to "image"
	 */
	constructor(xmlObject, parentId, itemNumber = 0, pointMainClass, valueType = "image", falseText = null, trueText = null, themeName = null) {
		super(xmlObject, parentId, pointMainClass, null, pointMainClass.charAt(0).toLowerCase() + pointMainClass.slice(1) + "sContainer" + String(itemNumber));
		var xmlMarker = pointMainClass.charAt(0).toLowerCase() + pointMainClass.slice(1);
		var num = (itemNumber == null) ? 0 : itemNumber;
		//TODO - alarm status saving as a variable
		//set holdingRegister, pointRefreshFrequency, and  bitNumber
		if(xmlObject.selector == "alarmPointsContainer" || xmlObject.selector == "statusPointsContainer") {
			this.holdingRegister = Math.round(xmlObject[0].attributes['holdingRegister'].value);
			this.pointRefreshFrequency = xmlObject[0].attributes['pointRefreshFrequency'].value;
			if(xmlObject.selector == "alarmPointsContainer") {
				var alarmPointXmlObject = $(xmlObject[0]).find("alarmPoint");
				this.bitNumber = Math.round(alarmPointXmlObject[num].attributes['bitNumber'].value)
			}
			else if(xmlObject.selector == "statusPointsContainer") {
				var statusPointXmlObject = $(xmlObject[0]).find("statusPoint");
				this.bitNumber = Math.round(statusPointXmlObject[num].attributes['bitNumber'].value)
			}
		}
		else {
			this.holdingRegister = Math.round(xmlObject[num].attributes['holdingRegister'].value);
			this.pointRefreshFrequency = xmlObject[num].attributes['pointRefreshFrequency'].value;
			this.bitNumber = (xmlObject[num].attributes['bitNumber'] != undefined) ? xmlObject[num].attributes['bitNumber'].value : num;
		}

		this.valueType = valueType.toLowerCase();
		this.mainClass = pointMainClass;
		this.childLabel = null;
		if(this.valueType == "image") {
			this.childUnactiveImage = null;
			this.childActiveImage = null;
		}
		else if(this.valueType == "text") {
			this.childValue = null;
		}
		this.themeName = themeName;
		this.initObject(xmlObject, xmlMarker, pointMainClass, num);

		this.falseText = falseText;
		this.trueText = trueText;
		this.value = false;
		this.setState(false);		
		window.modbusReader[ModbusRequestContainer.findModbusNetworkIndex(this.pointRefreshFrequency, window.modbusReader)].initRegister(this.holdingRegister, this, "int", this.bitNumber);
	}

	/**
	 * Gets bit number of boolean value
	 * @returns {String}		"All" or biut number
	 */
	getBitNumber() {
		return this.bitNumber;
	}

	/**
	 * Gets false text value
	 * @returns {String}	False text of the point
	 */
	getFalseText() {
		return this.falseText;
	}

	/**
	 * Gets label text of the boolean point
	 * @returns {String}	Label text
	 */
	getLabelText() {
		return this.childLabel.getTextValue("string");
	}
	
	/**
	 * Gets starting Modbus register address of point
	 * @returns {Integer}		Register address
	 */
	getModbusRegisterAddress() {
		return this.holdingRegister;
	}

	/**
	 * Gets name of pointRefreshFrequency
	 * @returns {String}	Name of point refresh frequency tunning
	 */
	getPointRefreshFrequency() {
		return this.pointRefreshFrequency;
	}
	
	/**
	 * Gets type of the point
	 * @returns {String}		Type of the point ("numeric", "enum", "boolean" or "unknown")
	 */
	getPointType() {
		return this.type;
	}

	/**
	 * Gets current state of the boolean point
	 * @returns {Boolean}	Current state of the boolean point
	 */
	getState() {
		return this.value;
	}
	
	/**
	 * Gets true text value
	 * @returns {String}	True text of the point
	 */
	getTrueText() {
		return this.trueText;
	}
	
	/**
	 * Inits label text of the boolean point
	 * @param {jQuery} xmlObject 		Data loaded from XML - accept status points or alarm points part only
	 * @param {Integer} num 			Bit number of BooleanPoint in 16-bits Holding Register
	 */
	initLabelText(xmlObject, num) {
		this.childLabel.setTextValue(xmlObject[num].attributes['label'].value);
	}
	
	/**
	 * Inits HTML object releated to boolean point
	 * @param {jQuery} xmlObject 		Data loaded from XML - accept boolean points part only
	 * @param {String} xmlMarker 		XML marker of "alarmpoint" or "statuspoint"
	 * @param {String} pointMainClass 	Name of the CSS style's class of boolean point
	 * @param {Integer} itemNumber 		Number of object constructing boolean point
	 */
	initObject(xmlObject, xmlMarker, pointMainClass, itemNumber) {
		var pointXmlObjects = xmlObject.find(xmlMarker);
		this.childLabel = new StandardLabel(pointXmlObjects, this.id, pointMainClass + "Label", itemNumber, this.id + "label");
		this.initLabelText(pointXmlObjects, itemNumber);
		if(this.valueType == "image") {
			this.childUnactiveImage = new DynamicImage(pointXmlObjects, this.id, itemNumber, this.id + "unactive", this.themeName);
			if(this.mainClass == "AlarmPoint")
				this.childActiveImage = new DynamicImage(pointXmlObjects, this.id, itemNumber, this.id + "activeAlarm", this.themeName);
			else if(this.mainClass == "StatusPoint")
				this.childActiveImage = new DynamicImage(pointXmlObjects, this.id, itemNumber, this.id + "activeStatus", this.themeName);
		}
		else if(this.valueType == "text") {
			this.childValue = new StandardLabel(pointXmlObjects, this.id, pointMainClass + "Value", itemNumber, this.id + "value");
		}
	}
	
	/**
	 * Converts String true/false text to boolean true/false value
	 * @param {String} value 	Input value text - "true" or "false"
	 * @returns {Boolean}		Value as Boolean type
	 */
	static parseBoolean(value) {
		var val = value.toLowerCase();
		return (val == "true") ? true : ((val == "false") ? false : null);
	}
	
	/**
	 * Prints falseText or trueText dependent on current state value of boolean point
	 */
	printTextValue() {
		this.childValue.setTextValue((this.getFalseText() != null && this.getTrueText() != null) ? ((this.getState()) ? this.getTrueText() : this.getFalseText()) : String(this.value));
	}
	
	/**
	 * Reads bit state of the numeric value
	 * @param {Integer} value		Numeric input value
	 * @param {Integer} bitNumber	Chosen bit number (if value is 16-bits, then bit number need to be in range <0; 15>)
	 * @returns {Boolean}			Bit state
	 */
	static readBitValue(value, bitNumber) {
		return ((value & (1<<bitNumber)) != 0x0000);
	}
	
	/**
	 * Sets label of the boolean point
	 * @param {String} value 	Text to set
	 */
	setLabelText(value) {
		this.childLabel.setTextValue(value);
	}
	
	/**
	 * Sets state - it is saved in current state value
	 * @param {Boolean} value 	Value to set
	 */
	setState(value) {
		if(this.valueType == "image") {
			this.value = value;
			this.childUnactiveImage.setVisibility(!value);
			this.childActiveImage.setVisibility(value);
		}
		else if(this.valueType == "text") {
			this.value = value;
			this.printTextValue();
		}
	}
}