// Fusion Research Driver - Common Module - System Configuration Tools
//
// Copyright 2021 Fusion Research, Inc.
// by Alexa Jade Fanti
//
// Comments:
//   This file provides tools for reading the driver's configuration.
//   It supports error reporting, default value returns and in some
//   cases range enforcement.
//
//   We have tools to read strings, integers and boolean values.
//
// Depends: 
//   fusion_stringutils.js
//   fusion_debugging.js
//
//System.Print("Fusion Driver - Common Module - System Configuration Tools loaded...\r\n");


// This utility reads a string value from the driver's configuration.
// If it's missing (empty string) or can't be read it returns a default.
//
// Parameters:
//		name         - The name of the driver configuration variable
//		defaultvalue - The default value to return if the parameter is not found or empty
//
function ReadConfig_AsString(name, defaultvalue)
{
	// Verify Parameters first...
	// If they didn't specify the name of the parameter, it's a critical error!
	if (name === undefined) {
		Debug_SysConfig("ReadConfig_AsString parameter 'name' is undefined, returning empty string!", g_DEBUG_LEVEL_CRITICAL);
		return ""; // I won't even return the default here... we should HALT at this point!
	}

	// Read the config
	try {
		var value = Config.Get(name); // This ALWAYS returns a string!

		// If the string is empty, then we certainly want the default value. After all, why would we ever configure "nothing"?!!!
		if (value == "") {
			if (defaultvalue === undefined) {
				Debug_SysConfig("ReadConfig_AsString value of '" + name + "' is empty and 'defaultvalue' is undefined, returning empty string!", g_DEBUG_LEVEL_WARN);
				return "";
			}

			Debug_SysConfig("ReadConfig_AsString value of '" + name + "' is empty, returning default value of '" + defaultvalue + "'", g_DEBUG_LEVEL_INFO);
			return defaultvalue;
		}

		// If we get here, we have a value from the configuration...
		value = value.trim(); // Let's trim it, because again, when would we ever want leading/trailing spaces?
		Debug_SysConfig("ReadConfig_AsString value of '" + name + "' is '" + value + "'", g_DEBUG_LEVEL_TRACE);
		return value;

		//return String(value).replace(/^\s+|\s+$/g,''); // Trim the string!
	} catch (err) {
		// This could be thrown when the name does not exist in the config, for example.
		if (defaultvalue === undefined) {
			Debug_SysConfig("ReadConfig_AsString '" + name + "'' failed with exception (" + err + ") and 'defaultvalue' is undefined, returning empty string!", g_DEBUG_LEVEL_ERROR);
			return "";
		}

		Debug_SysConfig("ReadConfig_AsString '" + name + "'' failed with exception (" + err + "), returning default of '" + defaultvalue + "'" , g_DEBUG_LEVEL_ERROR);
		return defaultvalue;
	}
}


// This utility reads a boolean value from the driver's configuration.
// If it can't be read it returns a default.
//
// Parameters:
//		name         - The name of the driver configuration variable
//		defaultvalue - The default value to return if the parameter is not found
//
function ReadConfig_AsBool(name, defaultvalue)
{
	// Verify Parameters first...
	// If they didn't specify the name of the parameter, it's a critical error!
	if (name === undefined) {
		Debug_SysConfig("ReadConfig_AsBool parameter 'name' is undefined, returning FALSE", g_DEBUG_LEVEL_CRITICAL);
		return false;
	}

	// Read the config
	try {
		var value = Config.Get(name); // This ALWAYS returns a string! It appears to be "true" or "" (empty)
		if (value == "true") {
			Debug_SysConfig("ReadConfig_AsBool value of '" + name + "' is TRUE", g_DEBUG_LEVEL_TRACE);
			return true;
		} else {
			Debug_SysConfig("ReadConfig_AsBool value of '" + name + "' is FALSE", g_DEBUG_LEVEL_TRACE);
			return false;
		}
	} catch (err) {
		// This could be thrown when the name does not exist in the config, for example.
		if (defaultvalue === undefined) {
			Debug_SysConfig("ReadConfig_AsBool '" + name + "'' failed with exception (" + err + ") and 'defaultvalue' is undefined, returning FALSE!", g_DEBUG_LEVEL_ERROR);
			return false;
		}

		if (parseBool(defaultvalue)) {
			Debug_SysConfig("ReadConfig_AsBool '" + name + "'' failed with exception (" + err + "), returning default of TRUE (" + defaultvalue + ")", g_DEBUG_LEVEL_ERROR);
			return true;
		} else {
			Debug_SysConfig("ReadConfig_AsBool '" + name + "'' failed with exception (" + err + "), returning default of FALSE (" + defaultvalue + ")", g_DEBUG_LEVEL_ERROR);
			return false;
		}
	}
}


// This utility reads an integer value from the driver's configuration.
// If the value is read, and min/max values are provided, it will ensure 
// the result is between the min and max (inclusive).
//
// Parameters:
//		name         - The name of the driver configuration variable
//		defaultvalue - The default value to return if the parameter is not found
//		min          - The minimum to make sure we don't go lower than (optional)
//		max          - The maximum to make sure we don't go higher than (optional)
//
function ReadConfig_AsInt(name, defaultvalue, min, max)
{
	// Verify Parameters first...
	// If they didn't specify the name of the parameter, it's a critical error!
	if (name === undefined) {
		Debug_SysConfig("ReadConfig_AsInt parameter 'name' is undefined, returning 0!", g_DEBUG_LEVEL_CRITICAL);
		return 0;
	}

	// Read the config
	try {
		var value = Config.Get(name); // This ALWAYS returns a string!

		value = parseInt(value, 10);
		// I believe this code is unreachable as the integration designer forces the value to be a number, but I'm not certain, so I have this here anyway!
		if (isNaN(value)) {
			defaultvalue = parseInt(defaultvalue, 10);
			if (isNaN(defaultvalue)) {
				Debug_SysConfig("ReadConfig_AsInt parameter 'defaultvalue' is undefined or not a number, returning 0!", g_DEBUG_LEVEL_WARN);
				return 0;
			}

			Debug_SysConfig("ReadConfig_AsInt '" + name + "' is not a number, returning default of " + defaultvalue, g_DEBUG_LEVEL_ERROR);
			return defaultvalue;
		}

		// If we get here then the value IS a number and we want to force it between the min and max (if specified)

		if (min !== undefined) { // If the min is undefined, it's NOT an error (or even a warning)
			min = parseInt(min, 10);
			if (isNaN(min)) {
				Debug_SysConfig("ReadConfig_AsInt '" + name + "' specified minimum value is not a number", g_DEBUG_LEVEL_ERROR);
			} else {
				if (value < min) {
					Debug_SysConfig("ReadConfig_AsInt '" + name + "' is " + value + ", which is below the min of " + min + ". returning minimum", g_DEBUG_LEVEL_INFO);
					return min;
				}
			}
		}

		if (max !== undefined) { // If the min is undefined, it's NOT an error (or even a warning)
			max = parseInt(max, 10);
			if (isNaN(max)) {
				Debug_SysConfig("ReadConfig_AsInt '" + name + "' specified maximum value is not a number", g_DEBUG_LEVEL_ERROR);
			} else {
				if (value > max) {
					Debug_SysConfig("ReadConfig_AsInt '" + name + "' is " + value + ", which is above the max of " + max + ". returning maximum", g_DEBUG_LEVEL_WARN);
					return max;
				}
			}
		}

		Debug_SysConfig("ReadConfig_AsInt value of '" + name + "' is " + value, g_DEBUG_LEVEL_TRACE);
		return value;
	} catch (err) {
		// This could be thrown when the name does not exist in the config, for example.
		if (defaultvalue === undefined) {
			Debug_SysConfig("ReadConfig_AsInt '" + name + "'' failed with exception (" + err + ") and 'defaultvalue' is undefined, returning 0!", g_DEBUG_LEVEL_ERROR);
			return 0;
		}
		
		defaultvalue = parseInt(defaultvalue, 10);
		if (isNaN(defaultvalue)) {
			Debug_SysConfig("ReadConfig_AsInt '" + name + "'' failed with exception (" + err + ") and 'defaultvalue' is not a number, returning 0!", g_DEBUG_LEVEL_ERROR);
			return 0;
		}

		Debug_SysConfig("ReadConfig_AsInt '" + name + "'' failed with exception (" + err + "), returning default of " + defaultvalue , g_DEBUG_LEVEL_ERROR);
		return defaultvalue;
	}
}


/* Testing - What beeds to be in 

	<category name="Test Read" description="Settings to test reading the config data" hidden="false">
		<setting type="string" name="Test String 1" variable="TestString1" default=""/>
		<setting type="string" name="Test String 2" variable="TestString2" default=""/>
		<setting type="string" name="Test String 3" variable="TestString3" default="Something"/>
		<setting type="integer" name="Test Integer 1" variable="TestInteger1" default="5"/>
		<setting type="boolean" name="Test Boolean 1" variable="TestBoolean1" default="false"/>
		<setting type="boolean" name="Test Boolean 2" variable="TestBoolean2" default="true"/>
    </category>


	System.Print("-----Test Read Config String");
	System.Print("TestString-1 = " + ReadConfig_AsString());
	System.Print("-----");
	System.Print("TestString0 = " + ReadConfig_AsString('TestString0'));
	System.Print("-----");
	System.Print("TestString0 = " + ReadConfig_AsString('TestString0', 'Fallback'));
	System.Print("-----");
	System.Print("TestString1 = " + ReadConfig_AsString('TestString1'));
	System.Print("-----");
	System.Print("TestString1 = " + ReadConfig_AsString('TestString1', 'Fallback'));
	System.Print("-----");
	System.Print("TestString2 = " + ReadConfig_AsString('TestString2'));
	System.Print("-----");
	System.Print("TestString2 = " + ReadConfig_AsString('TestString2', 'Fallback'));
	System.Print("-----");
	System.Print("TestString3 = " + ReadConfig_AsString('TestString3'));
	System.Print("-----");
	System.Print("TestString3 = " + ReadConfig_AsString('TestString3', 'Fallback'));
	System.Print("-----");

	System.Print("-----Test Read Config Boolean");
	System.Print("TestBoolean-1 = " + ReadConfig_AsBool());
	System.Print("-----");
	System.Print("TestBoolean0 = " + ReadConfig_AsBool('TestBoolean0'));
	System.Print("-----");
	System.Print("TestBoolean0 = " + ReadConfig_AsBool('TestBoolean0', "apple"));
	System.Print("-----");
	System.Print("TestBoolean0 = " + ReadConfig_AsBool('TestBoolean0', true));
	System.Print("-----");
	System.Print("TestBoolean1 = " + ReadConfig_AsBool('TestBoolean1'));
	System.Print("-----");
	System.Print("TestBoolean1 = " + ReadConfig_AsBool('TestBoolean1', true));
	System.Print("-----");
	System.Print("TestBoolean2 = " + ReadConfig_AsBool('TestBoolean2'));
	System.Print("-----");
	System.Print("TestBoolean2 = " + ReadConfig_AsBool('TestBoolean2', true));
	System.Print("-----");

	System.Print("-----Test Read Config Integer");
	System.Print("TestInteger-1 = " + ReadConfig_AsInt());
	System.Print("-----");
	System.Print("TestInteger0 = " + ReadConfig_AsInt('TestInteger0'));
	System.Print("-----");
	System.Print("TestInteger0 = " + ReadConfig_AsInt('TestInteger0', 'Alpha'));
	System.Print("-----");
	System.Print("TestInteger0 = " + ReadConfig_AsInt('TestInteger0', 45));
	System.Print("-----");
	System.Print("TestInteger1 = " + ReadConfig_AsInt('TestInteger1'));
	System.Print("-----");
	System.Print("TestInteger1 = " + ReadConfig_AsInt('TestInteger1', 6));
	System.Print("-----");
	System.Print("TestInteger1 = " + ReadConfig_AsInt('TestInteger1', 6, 'A1', 'A2'));
	System.Print("-----");
	System.Print("TestInteger1 = " + ReadConfig_AsInt('TestInteger1', 6, 10));
	System.Print("-----");
	System.Print("TestInteger1 = " + ReadConfig_AsInt('TestInteger1', 6, 1, 2));
	System.Print("-----");
	System.Print("TestInteger1 = " + ReadConfig_AsInt('TestInteger1', 6, 3, 8));
	System.Print("-----");

*/
