Fix in SetCentury for SetInternational(#Windows)

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING System.Collections.Generic
USING System.Threading
USING XSharp.RDD
USING XSharp.RDD.Enums

///
/// Container Class that holds the XSharp Runtime state
///
/// <remarks>
/// Please note that unlike in Visual Objects and Vulcan.NET every thread has its own copy of the runtime state.

/// The runtime state from a new thread is a copy of the state of the main thread at that moment.
/// </remarks>

CLASS XSharp.RuntimeState
	// Static Fields
	PRIVATE INITONLY STATIC initialState  AS RuntimeState
	// Static Methods and Constructor
	PRIVATE STATIC currentState := ThreadLocal<RuntimeState>{ {=>  initialState:Clone()} }  AS ThreadLocal<RuntimeState>
	STATIC CONSTRUCTOR
		initialState	:= RuntimeState{TRUE}

	/// Retrieve the runtime state for the current thread
	PUBLIC STATIC METHOD GetInstance() AS RuntimeState
		RETURN currentState:Value

	PRIVATE oSettings AS Dictionary<INT, OBJECT>

	PRIVATE CONSTRUCTOR(initialize AS LOGIC)
		VAR oThread := Thread.CurrentThread
		SELF:Name := "ThreadState for "+oThread:ManagedThreadId:ToString()
		oSettings := Dictionary<INT, OBJECT>{}
		IF initialize
			SELF:BreakLevel := 0
			SELF:_SetThreadValue(Set.DateFormat ,"MM/DD/YYYY")
			SELF:_SetThreadValue(Set.Epoch, 1900U)
			SELF:_SetThreadValue(Set.EpochYear, 0U)
			SELF:_SetThreadValue(Set.EpochCent, 1900U)
			// Initialize the values that are not 'blank'
			// RDD Settings
			SELF:_SetThreadValue(Set.Ansi , TRUE)
			SELF:_SetThreadValue(Set.AutoOpen , TRUE)
			SELF:_SetThreadValue(Set.AutoOrder , TRUE)
			SELF:_SetThreadValue(Set.Optimize , TRUE)
			SELF:_SetThreadValue(Set.AutoShare, AutoShareMode.Auto)
			SELF:_SetThreadValue(Set.LOCKTRIES , 1)
			SELF:_SetThreadValue(Set.MemoBlockSize , 32)
			SELF:_SetThreadValue(Set.DefaultRDD , "DBFNTX")
			SELF:_SetThreadValue(Set.Exclusive , TRUE)
			// Console Settings
			SELF:_SetThreadValue(Set.Bell , TRUE)
			SELF:_SetThreadValue(Set.Color , "W/N,N/W,N/N,N/N,N/W")
			SELF:_SetThreadValue(Set.Decimals , (DWORD) 2)
			SELF:_SetThreadValue(Set.Digits , (DWORD) 10 )
			SELF:_SetThreadValue(Set.Exact , FALSE)
			SELF:_SetThreadValue(Set.FLoatDelta , 0.0000000000001)
			SELF:_SetThreadValue(Set.DOSCODEPAGE, Win32.GetDosCodePage())
			SELF:_SetThreadValue(Set.WINCODEPAGE, Win32.GetWinCodePage())
			// Add null value for Clipper collation
			SELF:_SetThreadValue<BYTE[]>(Set.CollationTable, NULL )
			SELF:_SetThreadValue(Set.CollationMode, CollationMode.Windows)
			// Date and time settings
			SELF:_SetInternationalWindows()

		ENDIF
		RETURN

	DESTRUCTOR()
		// What do we need to clean ?
		IF oSettings != NULL
			oSettings:Clear()
		ENDIF

	PRIVATE METHOD Clone() AS RuntimeState
		LOCAL oNew AS RuntimeState
		oNew := RuntimeState{FALSE}
		BEGIN LOCK oSettings
			// Copy all values from Current State to New state
			FOREACH VAR element IN oSettings
				oNew:oSettings[element:Key] := element:Value
			NEXT
		END LOCK
		RETURN oNew

	/// Retrieve state name
	/// <returns>String value, such as "State for Thread 123"</returns>
	PUBLIC PROPERTY Name AS STRING AUTO
	/// Current Break Level. Gets set by compiler generated code for BEGIN SEQUENCE .. END constructs.
	PUBLIC PROPERTY BreakLevel AS INT AUTO
	/// ToString() override
	/// <returns>String value, such as "State for Thread 123"</returns>
	PUBLIC VIRTUAL METHOD ToString() AS STRING
		RETURN SELF:Name

	/// Retrieve a value from the state of the current Thread.
	/// <param name="nSetting">Setting number to retrieve. Must be defined in the SET enum.</param>
	/// <typeparam name="T">The return type expected for this setting.</typeparam>
	/// <returns>The current value, or a default value of type T.</returns>
	PUBLIC STATIC METHOD GetValue<T> (nSetting AS INT) AS T
		RETURN currentState:Value:_GetThreadValue<T>(nSetting);

	/// Set a value for the state of the current Thread.
	/// <param name="nSetting">Setting number to retrieve. Must be defined in the SET enum.</param>
	/// <param name="oValue">The new value for the setting.</param>
	/// <typeparam name="T">The return type expected for this setting.</typeparam>
	/// <returns>The previous value, or a default value of type T when the setting was not yetr defined.</returns>
	PUBLIC STATIC METHOD SetValue<T> (nSetting AS INT, oValue AS T) AS T
		RETURN currentState:Value:_SetThreadValue<T>(nSetting, oValue)

	PRIVATE METHOD _GetThreadValue<T> (nSetting AS INT) AS T
		BEGIN LOCK oSettings
			IF oSettings.ContainsKey(nSetting)
				RETURN (T) oSettings[nSetting]
			ENDIF
		END LOCK
		RETURN DEFAULT(T)

	PRIVATE METHOD _SetThreadValue<T>(nSetting AS INT, oValue AS T) AS T
		LOCAL result AS T
		BEGIN LOCK oSettings
			IF oSettings.ContainsKey(nSetting)
				result := (T) oSettings[nSetting]
			ELSE
				result := DEFAULT(T)
			ENDIF
			oSettings[nSetting] := oValue
		END LOCK
		RETURN	result

	#region properties FROM the Vulcan RuntimeState that are emulated

	/// The current compiler setting for the VO11 compiler option as defined when compiling the main application.
	/// This value gets assigned in the startup code for applications in the VO or Vulcan dialect.
	STATIC PROPERTY CompilerOptionVO11 AS LOGIC ;
        GET GetValue<LOGIC>(Set.OPTIONVO11);
        SET SetValue<LOGIC>(Set.OPTIONVO11, VALUE)

	/// The current compiler setting for the VO13 compiler option as defined when compiling the main application.
	/// This value gets assigned in the startup code for applications in the VO or Vulcan dialect.
	STATIC PROPERTY CompilerOptionVO13 AS LOGIC ;
        GET GetValue<LOGIC>(Set.OPTIONVO13);
        SET SetValue<LOGIC>(Set.OPTIONVO13, VALUE)

    /// The current compiler setting for the OVF compiler option as defined when compiling the main application.
	/// This value gets assigned in the startup code for applications in the VO or Vulcan dialect.
	STATIC PROPERTY CompilerOptionOVF AS LOGIC ;
        GET GetValue<LOGIC>(Set.OPTIONOVF);
        SET SetValue<LOGIC>(Set.OPTIONOVF, VALUE)

	/// The current compiler setting for the FOVF compiler option as defined when compiling the main application.
	/// This value gets assigned in the startup code for applications in the VO or Vulcan dialect.
	STATIC PROPERTY CompilerOptionFOVF AS LOGIC ;
        GET GetValue<LOGIC>(Set.OPTIONOVF);
        SET SetValue<LOGIC>(Set.OPTIONOVF, VALUE)

	/// The System.Reflection.Module for the main application.
	/// This value gets assigned in the startup code for applications in the VO or Vulcan dialect.
    STATIC PROPERTY AppModule AS  System.Reflection.Module;
        GET GetValue<System.Reflection.Module>(Set.AppModule);
        SET SetValue<System.Reflection.Module>(Set.AppModule, VALUE)
	#endregion

	/// The current ANSI setting
    STATIC PROPERTY @@Ansi AS LOGIC ;
        GET GetValue<LOGIC>(Set.Ansi);
        SET SetValue<LOGIC>(Set.Ansi, VALUE)

	/// The current AutoOrder setting (used by the RDD system).
    STATIC PROPERTY AutoOrder AS LOGIC ;
        GET GetValue<LOGIC>(Set.AutoOrder);
        SET SetValue<LOGIC>(Set.AutoOrder, VALUE)

	/// The current AutoOpen setting (used by the RDD system).
    STATIC PROPERTY AutoOpen AS LOGIC ;
        GET GetValue<LOGIC>(Set.AutoOpen);
        SET SetValue<LOGIC>(Set.AutoOpen, VALUE)

	/// The current AutoShareMode setting (used by the RDD system).
    STATIC PROPERTY AutoShareMode AS AutoShareMode ;
        GET GetValue<AutoShareMode>(Set.AutoShare);
        SET SetValue<AutoShareMode>(Set.AutoShare, VALUE)

	/// The current Century setting (used in DATE <-> STRING conversions).
   STATIC PROPERTY Century AS LOGIC ;
        GET GetValue<LOGIC>(Set.Century);
        SET SetValue<LOGIC>(Set.Century, VALUE)

	/// The current Collation mode (used by the RDD system).
   STATIC PROPERTY CollationMode AS CollationMode
        GET
			RETURN GetValue<CollationMode>(Set.CollationMode)
		END GET
        SET
			SetValue<CollationMode>(Set.CollationMode, VALUE)
			IF OnCollationChanged != NULL
				OnCollationChanged(GetInstance(), EVentArgs{})
			ENDIF
		END SET
	END PROPERTY

	/// The current DateCountry setting mode (used in DATE <-> STRING conversions).
   STATIC PROPERTY DateCountry AS DWORD ;
        GET GetValue<DWORD>(Set.DateCountry);
        SET _SetDateCountry(VALUE)

	/// The current Date format
	/// <remarks>This string should contain a combination of DD MM and either YY or YYYY characters.

	/// For example DD-MM-YYYY for italian date format, MM/DD/YYYY for American date format or DD/MM/YYYY for British Date format.
	/// Note that all other characters except the four groups mentioned above are copied to the output string verbatim.
	/// </remarks>
    STATIC PROPERTY DateFormat AS STRING ;
        GET GetValue<STRING>(Set.DateFormat);
        SET _SetDateFormat(VALUE)

	/// The default number of decimals for new FLOAT values that are created without explicit decimals

    STATIC PROPERTY Decimals AS DWORD ;
        GET GetValue<DWORD>(Set.DECIMALS);
        SET SetValue<DWORD>(Set.DECIMALS, VALUE)

	/// The default number of decimals for new FLOAT values that are created without explicit decimals
    STATIC PROPERTY DecimalSep AS DWORD ;
        GET GetValue<DWORD>(Set.DecimalSep);
        SET SetValue<DWORD>(Set.DecimalSep, VALUE)

	/// RDD Deleted Flag that determines whether to ignore or include records that are marked for deletion.
    STATIC PROPERTY Deleted AS LOGIC ;
        GET GetValue<LOGIC>(Set.DELETED);
        SET SetValue<LOGIC>(Set.DELETED, VALUE)

	/// The default number of digits for new FLOAT values that are created without explicit decimals
    STATIC PROPERTY Digits AS DWORD ;
        GET GetValue<DWORD>(Set.DIGITS);
        SET SetValue<DWORD>(Set.DIGITS, VALUE)

    /// Logical setting that fixes the number of digits used to display numeric output.
    STATIC PROPERTY DigitsFixed AS LOGIC ;
        GET GetValue<LOGIC>(Set.DigitFixed);
        SET SetValue<LOGIC>(Set.DigitFixed, VALUE)

	/// The DOS Codepage. This gets read at startup from the OS().
    STATIC PROPERTY DosCodePage AS LONG
        GET
			RETURN GetValue<LONG>(Set.DOSCODEPAGE)
		END GET
        SET
			SetValue<LONG>(Set.DOSCODEPAGE, VALUE)
			IF OnCodePageChanged != NULL
				OnCodePageChanged(GetInstance(), EventArgs{})
			ENDIF
		END SET
	END PROPERTY

	/// Date Epoch value that determines how dates without century digits are interpreted.
    STATIC PROPERTY Epoch AS DWORD ;
        GET GetValue<DWORD>(Set.EPOCH);
        SET SetValue<DWORD>(Set.EPOCH, VALUE)

	/// Date Epoch Year value. This gets set by the SetEpoch() function to the Epoch year % 100.
    STATIC PROPERTY EpochYear AS DWORD ;
        GET GetValue<DWORD>(Set.EPOCHYEar)

	/// Date Epoch Century value. This gets set by the SetEpoch() function to the century in which the Epoch year falls.
    STATIC PROPERTY EpochCent AS DWORD ;
        GET GetValue<DWORD>(Set.EPOCHCent)

	/// String comparison Exact flag that determines how comparisons with the single '=' characters should be done.
    STATIC PROPERTY Exact AS LOGIC ;
        GET GetValue<LOGIC>(Set.EXACT);
        SET SetValue<LOGIC>(Set.EXACT, VALUE)

    /// Logical setting that fixes the number of decimal digits used to display numbers.
    STATIC PROPERTY Fixed AS LOGIC ;
        GET GetValue<LOGIC>(Set.Fixed);
        SET SetValue<LOGIC>(Set.Fixed, VALUE)

	/// Numeric value that controls the precision of Float comparisons.
   STATIC PROPERTY FloatDelta AS REAL8 ;
        GET GetValue<REAL8>(Set.FloatDelta);
        SET SetValue<REAL8>(Set.FloatDelta, VALUE)

	/// Current SetInternational Setting.
     STATIC PROPERTY International AS CollationMode ;
        GET GetValue<CollationMode>(Set.Intl);
        SET SetValue<CollationMode>(Set.Intl, VALUE)

	/// Last error that occurred in the RDD subsystem.
    STATIC PROPERTY LastRddError AS Exception ;
        GET GetValue<Exception>(Set.LastRddError);
        SET SetValue<Exception>(Set.LastRddError, VALUE)

	/// Number of tries that were done when the last lock operation failed.
    STATIC PROPERTY LockTries AS DWORD ;
        GET GetValue<DWORD>(Set.LOCKTRIES);
        SET SetValue<DWORD>(Set.LOCKTRIES, VALUE)

	/// The current default MemoBlock size.
    STATIC PROPERTY MemoBlockSize AS DWORD;
        GET GetValue<DWORD>(Set.MEMOBLOCKSIZE);
        SET SetValue<DWORD>(Set.MEMOBLOCKSIZE, VALUE)

	/// Did the last RDD operation cause a Network Error ?
    STATIC PROPERTY NetErr AS LOGIC;
        GET GetValue<LOGIC>(Set.NETERR);
        SET SetValue<LOGIC>(Set.NETERR, VALUE)

	/// RDD Optimize Flag
    STATIC PROPERTY Optimize AS LOGIC ;
        GET GetValue<LOGIC>(Set.OPTIMIZE);
        SET SetValue<LOGIC>(Set.OPTIMIZE, VALUE)

	/// The current SetSoftSeek flag.
    STATIC PROPERTY SoftSeek AS LOGIC ;
        GET GetValue<LOGIC>(Set.SOFTSEEK);
        SET SetValue<LOGIC>(Set.SOFTSEEK, VALUE)

	/// The Thousand separator
    STATIC PROPERTY ThousandSep AS DWORD ;
        GET GetValue<DWORD>(Set.THOUSANDSEP);
        SET SetValue<DWORD>(Set.THOUSANDSEP, VALUE)

	/// Number of tries that were done when the last lock operation failed.
    STATIC PROPERTY Unique AS LOGIC ;
        GET GetValue<LOGIC>(Set.UNIQUE);
        SET SetValue<LOGIC>(Set.UNIQUE, VALUE)

	/// The Windows Codepage. This gets read at startup from the OS().
    STATIC PROPERTY WinCodePage AS LONG
	GET
        RETURN GetValue<LONG>(Set.WINCODEPAGE)
	END GET
	SET
        SetValue<LONG>(Set.WINCODEPAGE, VALUE)
			IF OnCodePageChanged != NULL
				OnCodePageChanged(GetInstance(), EventArgs{})
			ENDIF
	END SET
	END PROPERTY

	/// The name of the method that was called in the last late bound method call.
    STATIC PROPERTY NoMethod AS STRING ;
        GET GetValue<STRING>(Set.NoMethod);
        SET SetValue<STRING>(Set.NoMethod, VALUE)

	INTERNAL METHOD _SetInternationalClipper() AS VOID
		SELF:_SetThreadValue(Set.AMEXT, "")
		SELF:_SetThreadValue(Set.PMEXT, "")
		SELF:_SetThreadValue(Set.AMPM, FALSE)
		SELF:_SetThreadValue(Set.Century, FALSE)
		SELF:_SetThreadValue(Set.DateCountry, (DWORD)1)
		SELF:_SetThreadValue(Set.Decimals, (DWORD) 2)
		SELF:_SetThreadValue(Set.DECIMALSEP,  (DWORD) 46)		// DOT .
		SELF:_SetThreadValue(Set.THOUSANDSEP, (DWORD) 44)	// COMMA ,
		SELF:_SetThreadValue(Set.DateFormat, "MM/DD/YY")
		SELF:_SetThreadValue(Set.Intl, CollationMode.Clipper)

	INTERNAL METHOD _SetInternationalWindows() AS VOID
		VAR dtInfo	    := System.Globalization.DateTimeFormatInfo.CurrentInfo
		SELF:_SetThreadValue(Set.AMEXT, dtInfo:AMDesignator)
		SELF:_SetThreadValue(Set.PMEXT, dtInfo:PMDesignator)
		VAR separator := dtInfo:TimeSeparator
		IF String.IsNullOrEmpty(separator)
			SELF:_SetThreadValue(Set.TimeSep, (DWORD) 0)
		ELSE
			SELF:_SetThreadValue(Set.TimeSep, (DWORD) separator[0])
		ENDIF
		SELF:_SetThreadValue(Set.AMPM, dtInfo:ShortDatePattern:IndexOf("tt") != -1)
		VAR dateformat  := dtInfo:ShortDatePattern:ToLower()
		// reduce to single m and d
		DO WHILE (dateformat.IndexOf("mm") != -1)
			dateformat		:= dateformat:Replace("mm", "m")
		ENDDO
		// make sure we have a double mm to get double digit dates

		DO WHILE dateformat.IndexOf("dd") != -1
			dateformat		:= dateformat:Replace("dd", "d")
		ENDDO
		// change dates to dd and mm and then everything to upper case
		dateformat := dateformat:Replace("d", "dd"):Replace("m","mm"):ToUpper()
		SELF:_SetThreadValue(Set.Century, dateformat:IndexOf("YYYY",StringComparison.OrdinalIgnoreCase) != -1)
		SELF:_SetThreadValue(Set.DateFormatNet, dateformat:ToUpper():Replace("D","d"):Replace("Y","y"):Replace("/","'/'"))
		SELF:_SetThreadValue(Set.DateFormatEmpty, dateformat:ToUpper():Replace("D"," "):Replace("Y"," "):Replace("M"," "))
		SELF:_SetThreadValue(Set.DateFormat,  dateformat)
		SELF:_SetThreadValue(Set.DateCountry, (DWORD) 1)
		SELF:_SetThreadValue(Set.DECIMALS , (DWORD) 2)
		VAR numberformat := System.Globalization.NumberFormatInfo.CurrentInfo
		SELF:_SetThreadValue(Set.DECIMALSEP, (DWORD) numberformat:NumberDecimalSeparator[0])
		SELF:_SetThreadValue(Set.THOUSANDSEP, (DWORD) numberformat:NumberGroupSeparator[0])
		SELF:_SetThreadValue(Set.EPOCH, (DWORD) 1910)
		SELF:_SetThreadValue(Set.EpochYear, (DWORD) 10)
		SELF:_SetThreadValue(Set.EpochCent, (DWORD) 2000)
		SELF:_SetThreadValue(Set.Intl, CollationMode.Windows)
		RETURN

	INTERNAL STATIC METHOD _SetDateFormat(format AS STRING) AS VOID
		format := format:ToUpper()
		// ensure we have dd, mm and yy
		IF format:IndexOf("DD") == -1 .OR. format:IndexOf("MM") == -1 .OR. format:IndexOf("YY") == -1
			RETURN
		ENDIF
		SetValue(Set.DateFormatNet, format:Replace("D","d"):Replace("Y","y"):Replace("/","'/'"))
		SetValue(Set.DateFormatEmpty, format:Replace("D"," "):Replace("Y"," "):Replace("M"," "))
		SetValue(SET.CENTURY, format:Contains("YYYY"))
		SetValue(Set.DATEFORMAT, format)
		SWITCH format
			CASE "MM/DD/YY"
			CASE "MM/DD/YYYY"
				SetValue(Set.DATECOUNTRY, (DWORD) 1)	// American
			CASE "YY.MM.DD"
			CASE "YYYY.MM.DD"
				SetValue(Set.DATECOUNTRY, (DWORD)2)	// Ansi
			CASE "DD/MM/YY"
			CASE "DD/MM/YYYY"
				SetValue(Set.DATECOUNTRY, (DWORD)3)	// British & french
			CASE "DD.MM.YY"
			CASE "DD.MM.YYYY"
				SetValue(Set.DATECOUNTRY, (DWORD)5)	// German
			CASE "DD-MM-YY"
			CASE "DD-MM-YYYY"
				SetValue(Set.DATECOUNTRY, (DWORD)6)	// Italian
			CASE "YY/MM/DD"
			CASE "YYYY/MM/DD"
				SetValue(Set.DATECOUNTRY, (DWORD)7)	// Japanese
			CASE "MM-DD-YY"
			CASE "MM-DD-YYYY"
				SetValue(Set.DATECOUNTRY, (DWORD)8)	// USA
			OTHERWISE
				SetValue(Set.DATECOUNTRY, (DWORD)0)
		END SWITCH

	INTERNAL STATIC METHOD _SetDateCountry(country AS DWORD) AS VOID
		IF country > 8
			RETURN
		END IF

		SetValue<DWORD>(Set.DateCountry, country)

		LOCAL format, year AS STRING
		year := IIF(Century , "YYYY" , "YY")
		SWITCH country
			CASE 1 // American
				format := "MM/DD/" + year
			CASE 2 // Ansi
				format := year + ".MM.DD"
			CASE 3 // British & french
			CASE 4 // British & french
				format := "DD/MM/" + year
			CASE 5 // German
				format := "DD.MM." + year
			CASE 6 // Italian
				format := "DD-MM-" + year
			CASE 7 // Japanese
				format := year + "/MM/DD"
			CASE 8 // USA
				format := "MM-DD-" + year
			OTHERWISE
				format := "MM/DD/" + year
		END SWITCH
		// this will adjust DateFormatNet, DateFormatEmpty etc, but also DateCountry again
		_SetDateFormat(format)

	PRIVATE _workareas AS WorkAreas
	/// The workarea information for the current Thread.
	PUBLIC PROPERTY Workareas AS WorkAreas
	GET
		IF _workareas == NULL_OBJECT
			_workareas := WorkAreas{}
		ENDIF
		RETURN _workareas
	END GET
	END PROPERTY
	PRIVATE _collationTable AS BYTE[]
	PUBLIC STATIC PROPERTY CollationTable AS BYTE[]
	GET
		LOCAL coll AS BYTE[]
		coll := GetInstance():_collationTable
		IF coll == NULL .OR. coll :Length < 256
			_SetCollation("Generic")
			coll := GetInstance():_collationTable := GetValue<BYTE[]>(SET.CollationTable)
		ENDIF
		RETURN coll
	END GET
	SET
		GetInstance():_collationTable  := VALUE
		SetValue(Set.CollationTable, VALUE)
		IF OnCollationChanged != NULL
			OnCollationChanged(GetInstance(), EventArgs{})
		ENDIF
	END SET
	END PROPERTY

	STATIC INTERNAL _macrocompilerType   AS System.Type
    STATIC INTERNAL _macrocompiler       AS IMacroCompiler
	PUBLIC STATIC PROPERTY MacroCompiler AS IMacroCompiler
        GET
            IF _macrocompiler == NULL
                _LoadMacroCompiler()
            ENDIF
            RETURN _macrocompiler
        END GET
        SET
            _macrocompiler := VALUE
        END SET
    END PROPERTY

	PUBLIC STATIC EVENT OnCodePageChanged AS EventHandler
	PUBLIC STATIC EVENT OnCollationChanged AS EventHandler

    PRIVATE STATIC METHOD _LoadMacroCompiler() AS VOID
        IF _macroCompilerType == NULL_OBJECT
            VAR oMacroAsm := AssemblyHelper.Load("XSharp.MacroCompiler")
		    IF oMacroAsm != NULL_OBJECT
			    LOCAL oType AS System.Type
			    oType := oMacroAsm:GetType("XSharp.MacroCompiler",FALSE,TRUE)
			    IF oType != NULL_OBJECT
				    // create instance of this type
				    IF TYPEOF(IMacroCompiler):IsAssignableFrom(oType)
					    _macroCompilerType := oType
				    ELSE
					    THROW Error{EG_CORRUPTION, "", "Could not create the macro compiler from the type "+ otype:Fullname+" in the assembly "+oMacroAsm:Location}
				    ENDIF
			    ELSE
				    THROW Error{EG_CORRUPTION, "", "Could not load the macro compiler class in the assembly "+oMacroAsm:Location}
                ENDIF
            ELSE
                // AssemblyHelper.Load will throw an exception
                NOP
		    ENDIF
        ENDIF
        IF _macroCompilerType != NULL_OBJECT
			_macroCompiler := Activator:CreateInstance(_macroCompilerType) ASTYPE IMacroCompiler
		ENDIF
		RETURN

END CLASS

//
// Copyright (c) XSharp B.V.  All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
// See License.txt in the project root for license information.
//

USING System.Collections.Generic
USING System.Threading
USING XSharp.RDD
USING XSharp.RDD.Enums

///
/// Container Class that holds the XSharp Runtime state
///
/// <remarks>
/// Please note that unlike in Visual Objects and Vulcan.NET every thread has its own copy of the runtime state.

/// The runtime state from a new thread is a copy of the state of the main thread at that moment.
/// </remarks>

CLASS XSharp.RuntimeState
	// Static Fields
	PRIVATE INITONLY STATIC initialState  AS RuntimeState
	// Static Methods and Constructor
	PRIVATE STATIC currentState := ThreadLocal<RuntimeState>{ {=>  initialState:Clone()} }  AS ThreadLocal<RuntimeState>
	STATIC CONSTRUCTOR
		initialState	:= RuntimeState{TRUE}

	/// Retrieve the runtime state for the current thread
	PUBLIC STATIC METHOD GetInstance() AS RuntimeState
		RETURN currentState:Value

	PRIVATE oSettings AS Dictionary<INT, OBJECT>

	PRIVATE CONSTRUCTOR(initialize AS LOGIC)
		VAR oThread := Thread.CurrentThread
		SELF:Name := "ThreadState for "+oThread:ManagedThreadId:ToString()
		oSettings := Dictionary<INT, OBJECT>{}
		IF initialize
			SELF:BreakLevel := 0
			SELF:_SetThreadValue(Set.DateFormat ,"MM/DD/YYYY")
			SELF:_SetThreadValue(Set.Epoch, 1900U)
			SELF:_SetThreadValue(Set.EpochYear, 0U)
			SELF:_SetThreadValue(Set.EpochCent, 1900U)
			// Initialize the values that are not 'blank'
			// RDD Settings
			SELF:_SetThreadValue(Set.Ansi , TRUE)
			SELF:_SetThreadValue(Set.AutoOpen , TRUE)
			SELF:_SetThreadValue(Set.AutoOrder , TRUE)
			SELF:_SetThreadValue(Set.Optimize , TRUE)
			SELF:_SetThreadValue(Set.AutoShare, AutoShareMode.Auto)
			SELF:_SetThreadValue(Set.LOCKTRIES , 1)
			SELF:_SetThreadValue(Set.MemoBlockSize , 32)
			SELF:_SetThreadValue(Set.DefaultRDD , "DBFNTX")
			SELF:_SetThreadValue(Set.Exclusive , TRUE)
			// Console Settings
			SELF:_SetThreadValue(Set.Bell , TRUE)
			SELF:_SetThreadValue(Set.Color , "W/N,N/W,N/N,N/N,N/W")
			SELF:_SetThreadValue(Set.Decimals , (DWORD) 2)
			SELF:_SetThreadValue(Set.Digits , (DWORD) 10 )
			SELF:_SetThreadValue(Set.Exact , FALSE)
			SELF:_SetThreadValue(Set.FLoatDelta , 0.0000000000001)
			SELF:_SetThreadValue(Set.DOSCODEPAGE, Win32.GetDosCodePage())
			SELF:_SetThreadValue(Set.WINCODEPAGE, Win32.GetWinCodePage())
			// Add null value for Clipper collation
			SELF:_SetThreadValue<BYTE[]>(Set.CollationTable, NULL )
			SELF:_SetThreadValue(Set.CollationMode, CollationMode.Windows)
			// Date and time settings
			SELF:_SetInternationalWindows()

		ENDIF
		RETURN

	DESTRUCTOR()
		// What do we need to clean ?
		IF oSettings != NULL
			oSettings:Clear()
		ENDIF

	PRIVATE METHOD Clone() AS RuntimeState
		LOCAL oNew AS RuntimeState
		oNew := RuntimeState{FALSE}
		BEGIN LOCK oSettings
			// Copy all values from Current State to New state
			FOREACH VAR element IN oSettings
				oNew:oSettings[element:Key] := element:Value
			NEXT
		END LOCK
		RETURN oNew

	/// Retrieve state name
	/// <returns>String value, such as "State for Thread 123"</returns>
	PUBLIC PROPERTY Name AS STRING AUTO
	/// Current Break Level. Gets set by compiler generated code for BEGIN SEQUENCE .. END constructs.
	PUBLIC PROPERTY BreakLevel AS INT AUTO
	/// ToString() override
	/// <returns>String value, such as "State for Thread 123"</returns>
	PUBLIC VIRTUAL METHOD ToString() AS STRING
		RETURN SELF:Name

	/// Retrieve a value from the state of the current Thread.
	/// <param name="nSetting">Setting number to retrieve. Must be defined in the SET enum.</param>
	/// <typeparam name="T">The return type expected for this setting.</typeparam>
	/// <returns>The current value, or a default value of type T.</returns>
	PUBLIC STATIC METHOD GetValue<T> (nSetting AS INT) AS T
		RETURN currentState:Value:_GetThreadValue<T>(nSetting);

	/// Set a value for the state of the current Thread.
	/// <param name="nSetting">Setting number to retrieve. Must be defined in the SET enum.</param>
	/// <param name="oValue">The new value for the setting.</param>
	/// <typeparam name="T">The return type expected for this setting.</typeparam>
	/// <returns>The previous value, or a default value of type T when the setting was not yetr defined.</returns>
	PUBLIC STATIC METHOD SetValue<T> (nSetting AS INT, oValue AS T) AS T
		RETURN currentState:Value:_SetThreadValue<T>(nSetting, oValue)

	PRIVATE METHOD _GetThreadValue<T> (nSetting AS INT) AS T
		BEGIN LOCK oSettings
			IF oSettings.ContainsKey(nSetting)
				RETURN (T) oSettings[nSetting]
			ENDIF
		END LOCK
		RETURN DEFAULT(T)

	PRIVATE METHOD _SetThreadValue<T>(nSetting AS INT, oValue AS T) AS T
		LOCAL result AS T
		BEGIN LOCK oSettings
			IF oSettings.ContainsKey(nSetting)
				result := (T) oSettings[nSetting]
			ELSE
				result := DEFAULT(T)
			ENDIF
			oSettings[nSetting] := oValue
		END LOCK
		RETURN	result

	#region properties FROM the Vulcan RuntimeState that are emulated

	/// The current compiler setting for the VO11 compiler option as defined when compiling the main application.
	/// This value gets assigned in the startup code for applications in the VO or Vulcan dialect.
	STATIC PROPERTY CompilerOptionVO11 AS LOGIC ;
        GET GetValue<LOGIC>(Set.OPTIONVO11);
        SET SetValue<LOGIC>(Set.OPTIONVO11, VALUE)

	/// The current compiler setting for the VO13 compiler option as defined when compiling the main application.
	/// This value gets assigned in the startup code for applications in the VO or Vulcan dialect.
	STATIC PROPERTY CompilerOptionVO13 AS LOGIC ;
        GET GetValue<LOGIC>(Set.OPTIONVO13);
        SET SetValue<LOGIC>(Set.OPTIONVO13, VALUE)

    /// The current compiler setting for the OVF compiler option as defined when compiling the main application.
	/// This value gets assigned in the startup code for applications in the VO or Vulcan dialect.
	STATIC PROPERTY CompilerOptionOVF AS LOGIC ;
        GET GetValue<LOGIC>(Set.OPTIONOVF);
        SET SetValue<LOGIC>(Set.OPTIONOVF, VALUE)

	/// The current compiler setting for the FOVF compiler option as defined when compiling the main application.
	/// This value gets assigned in the startup code for applications in the VO or Vulcan dialect.
	STATIC PROPERTY CompilerOptionFOVF AS LOGIC ;
        GET GetValue<LOGIC>(Set.OPTIONOVF);
        SET SetValue<LOGIC>(Set.OPTIONOVF, VALUE)

	/// The System.Reflection.Module for the main application.
	/// This value gets assigned in the startup code for applications in the VO or Vulcan dialect.
    STATIC PROPERTY AppModule AS  System.Reflection.Module;
        GET GetValue<System.Reflection.Module>(Set.AppModule);
        SET SetValue<System.Reflection.Module>(Set.AppModule, VALUE)
	#endregion

	/// The current ANSI setting
    STATIC PROPERTY @@Ansi AS LOGIC ;
        GET GetValue<LOGIC>(Set.Ansi);
        SET SetValue<LOGIC>(Set.Ansi, VALUE)

	/// The current AutoOrder setting (used by the RDD system).
    STATIC PROPERTY AutoOrder AS LOGIC ;
        GET GetValue<LOGIC>(Set.AutoOrder);
        SET SetValue<LOGIC>(Set.AutoOrder, VALUE)

	/// The current AutoOpen setting (used by the RDD system).
    STATIC PROPERTY AutoOpen AS LOGIC ;
        GET GetValue<LOGIC>(Set.AutoOpen);
        SET SetValue<LOGIC>(Set.AutoOpen, VALUE)

	/// The current AutoShareMode setting (used by the RDD system).
    STATIC PROPERTY AutoShareMode AS AutoShareMode ;
        GET GetValue<AutoShareMode>(Set.AutoShare);
        SET SetValue<AutoShareMode>(Set.AutoShare, VALUE)

	/// The current Century setting (used in DATE <-> STRING conversions).
   STATIC PROPERTY Century AS LOGIC ;
        GET GetValue<LOGIC>(Set.Century);
        SET SetValue<LOGIC>(Set.Century, VALUE)

	/// The current Collation mode (used by the RDD system).
   STATIC PROPERTY CollationMode AS CollationMode
        GET
			RETURN GetValue<CollationMode>(Set.CollationMode)
		END GET
        SET
			SetValue<CollationMode>(Set.CollationMode, VALUE)
			IF OnCollationChanged != NULL
				OnCollationChanged(GetInstance(), EVentArgs{})
			ENDIF
		END SET
	END PROPERTY

	/// The current DateCountry setting mode (used in DATE <-> STRING conversions).
   STATIC PROPERTY DateCountry AS DWORD ;
        GET GetValue<DWORD>(Set.DateCountry);
        SET _SetDateCountry(VALUE)

	/// The current Date format
	/// <remarks>This string should contain a combination of DD MM and either YY or YYYY characters.

	/// For example DD-MM-YYYY for italian date format, MM/DD/YYYY for American date format or DD/MM/YYYY for British Date format.
	/// Note that all other characters except the four groups mentioned above are copied to the output string verbatim.
	/// </remarks>
    STATIC PROPERTY DateFormat AS STRING ;
        GET GetValue<STRING>(Set.DateFormat);
        SET _SetDateFormat(VALUE)

	/// The default number of decimals for new FLOAT values that are created without explicit decimals

    STATIC PROPERTY Decimals AS DWORD ;
        GET GetValue<DWORD>(Set.DECIMALS);
        SET SetValue<DWORD>(Set.DECIMALS, VALUE)

	/// The default number of decimals for new FLOAT values that are created without explicit decimals
    STATIC PROPERTY DecimalSep AS DWORD ;
        GET GetValue<DWORD>(Set.DecimalSep);
        SET SetValue<DWORD>(Set.DecimalSep, VALUE)

	/// RDD Deleted Flag that determines whether to ignore or include records that are marked for deletion.
    STATIC PROPERTY Deleted AS LOGIC ;
        GET GetValue<LOGIC>(Set.DELETED);
        SET SetValue<LOGIC>(Set.DELETED, VALUE)

	/// The default number of digits for new FLOAT values that are created without explicit decimals
    STATIC PROPERTY Digits AS DWORD ;
        GET GetValue<DWORD>(Set.DIGITS);
        SET SetValue<DWORD>(Set.DIGITS, VALUE)

    /// Logical setting that fixes the number of digits used to display numeric output.
    STATIC PROPERTY DigitsFixed AS LOGIC ;
        GET GetValue<LOGIC>(Set.DigitFixed);
        SET SetValue<LOGIC>(Set.DigitFixed, VALUE)

	/// The DOS Codepage. This gets read at startup from the OS().
    STATIC PROPERTY DosCodePage AS LONG
        GET
			RETURN GetValue<LONG>(Set.DOSCODEPAGE)
		END GET
        SET
			SetValue<LONG>(Set.DOSCODEPAGE, VALUE)
			IF OnCodePageChanged != NULL
				OnCodePageChanged(GetInstance(), EventArgs{})
			ENDIF
		END SET
	END PROPERTY

	/// Date Epoch value that determines how dates without century digits are interpreted.
    STATIC PROPERTY Epoch AS DWORD ;
        GET GetValue<DWORD>(Set.EPOCH);
        SET SetValue<DWORD>(Set.EPOCH, VALUE)

	/// Date Epoch Year value. This gets set by the SetEpoch() function to the Epoch year % 100.
    STATIC PROPERTY EpochYear AS DWORD ;
        GET GetValue<DWORD>(Set.EPOCHYEar)

	/// Date Epoch Century value. This gets set by the SetEpoch() function to the century in which the Epoch year falls.
    STATIC PROPERTY EpochCent AS DWORD ;
        GET GetValue<DWORD>(Set.EPOCHCent)

	/// String comparison Exact flag that determines how comparisons with the single '=' characters should be done.
    STATIC PROPERTY Exact AS LOGIC ;
        GET GetValue<LOGIC>(Set.EXACT);
        SET SetValue<LOGIC>(Set.EXACT, VALUE)

    /// Logical setting that fixes the number of decimal digits used to display numbers.
    STATIC PROPERTY Fixed AS LOGIC ;
        GET GetValue<LOGIC>(Set.Fixed);
        SET SetValue<LOGIC>(Set.Fixed, VALUE)

	/// Numeric value that controls the precision of Float comparisons.
   STATIC PROPERTY FloatDelta AS REAL8 ;
        GET GetValue<REAL8>(Set.FloatDelta);
        SET SetValue<REAL8>(Set.FloatDelta, VALUE)

	/// Current SetInternational Setting.
     STATIC PROPERTY International AS CollationMode ;
        GET GetValue<CollationMode>(Set.Intl);
        SET SetValue<CollationMode>(Set.Intl, VALUE)

	/// Last error that occurred in the RDD subsystem.
    STATIC PROPERTY LastRddError AS Exception ;
        GET GetValue<Exception>(Set.LastRddError);
        SET SetValue<Exception>(Set.LastRddError, VALUE)

	/// Number of tries that were done when the last lock operation failed.
    STATIC PROPERTY LockTries AS DWORD ;
        GET GetValue<DWORD>(Set.LOCKTRIES);
        SET SetValue<DWORD>(Set.LOCKTRIES, VALUE)

	/// The current default MemoBlock size.
    STATIC PROPERTY MemoBlockSize AS DWORD;
        GET GetValue<DWORD>(Set.MEMOBLOCKSIZE);
        SET SetValue<DWORD>(Set.MEMOBLOCKSIZE, VALUE)

	/// Did the last RDD operation cause a Network Error ?
    STATIC PROPERTY NetErr AS LOGIC;
        GET GetValue<LOGIC>(Set.NETERR);
        SET SetValue<LOGIC>(Set.NETERR, VALUE)

	/// RDD Optimize Flag
    STATIC PROPERTY Optimize AS LOGIC ;
        GET GetValue<LOGIC>(Set.OPTIMIZE);
        SET SetValue<LOGIC>(Set.OPTIMIZE, VALUE)

	/// The current SetSoftSeek flag.
    STATIC PROPERTY SoftSeek AS LOGIC ;
        GET GetValue<LOGIC>(Set.SOFTSEEK);
        SET SetValue<LOGIC>(Set.SOFTSEEK, VALUE)

	/// The Thousand separator
    STATIC PROPERTY ThousandSep AS DWORD ;
        GET GetValue<DWORD>(Set.THOUSANDSEP);
        SET SetValue<DWORD>(Set.THOUSANDSEP, VALUE)

	/// Number of tries that were done when the last lock operation failed.
    STATIC PROPERTY Unique AS LOGIC ;
        GET GetValue<LOGIC>(Set.UNIQUE);
        SET SetValue<LOGIC>(Set.UNIQUE, VALUE)

	/// The Windows Codepage. This gets read at startup from the OS().
    STATIC PROPERTY WinCodePage AS LONG
	GET
        RETURN GetValue<LONG>(Set.WINCODEPAGE)
	END GET
	SET
        SetValue<LONG>(Set.WINCODEPAGE, VALUE)
			IF OnCodePageChanged != NULL
				OnCodePageChanged(GetInstance(), EventArgs{})
			ENDIF
	END SET
	END PROPERTY

	/// The name of the method that was called in the last late bound method call.
    STATIC PROPERTY NoMethod AS STRING ;
        GET GetValue<STRING>(Set.NoMethod);
        SET SetValue<STRING>(Set.NoMethod, VALUE)

	INTERNAL METHOD _SetInternationalClipper() AS VOID
		SELF:_SetThreadValue(Set.AMEXT, "")
		SELF:_SetThreadValue(Set.PMEXT, "")
		SELF:_SetThreadValue(Set.AMPM, FALSE)
		SELF:_SetThreadValue(Set.Century, FALSE)
		SELF:_SetThreadValue(Set.DateCountry, (DWORD)1)
		SELF:_SetThreadValue(Set.Decimals, (DWORD) 2)
		SELF:_SetThreadValue(Set.DECIMALSEP,  (DWORD) 46)		// DOT .
		SELF:_SetThreadValue(Set.THOUSANDSEP, (DWORD) 44)	// COMMA ,
		SELF:_SetThreadValue(Set.DateFormat, "MM/DD/YY")
		SELF:_SetThreadValue(Set.Intl, CollationMode.Clipper)

	INTERNAL METHOD _SetInternationalWindows() AS VOID
		VAR dtInfo	    := System.Globalization.DateTimeFormatInfo.CurrentInfo
		SELF:_SetThreadValue(Set.AMEXT, dtInfo:AMDesignator)
		SELF:_SetThreadValue(Set.PMEXT, dtInfo:PMDesignator)
		VAR separator := dtInfo:TimeSeparator
		IF String.IsNullOrEmpty(separator)
			SELF:_SetThreadValue(Set.TimeSep, (DWORD) 0)
		ELSE
			SELF:_SetThreadValue(Set.TimeSep, (DWORD) separator[0])
		ENDIF
		SELF:_SetThreadValue(Set.AMPM, dtInfo:ShortDatePattern:IndexOf("tt") != -1)
		VAR dateformat  := dtInfo:ShortDatePattern:ToLower()
		// reduce to single m and d
		DO WHILE (dateformat.IndexOf("mm") != -1)
			dateformat		:= dateformat:Replace("mm", "m")
		ENDDO
		// make sure we have a double mm to get double digit dates

		DO WHILE dateformat.IndexOf("dd") != -1
			dateformat		:= dateformat:Replace("dd", "d")
		ENDDO
		// change dates to dd and mm
		dateformat := dateformat:Replace("d", "dd"):Replace("m","mm"):ToUpper()
		_SetThreadValue(Set.Century, dateformat:IndexOf("yyyy") != -1)
		_SetThreadValue(Set.DateFormatNet, dateformat:ToUpper():Replace("D","d"):Replace("Y","y"):Replace("/","'/'"))
		_SetThreadValue(Set.DateFormatEmpty, dateformat:ToUpper():Replace("D"," "):Replace("Y"," "):Replace("M"," "))
		SELF:_SetThreadValue(Set.DateFormat,  dateformat)
		SELF:_SetThreadValue(Set.DateCountry, (DWORD) 1)
		SELF:_SetThreadValue(Set.DECIMALS , (DWORD) 2)
		VAR numberformat := System.Globalization.NumberFormatInfo.CurrentInfo
		SELF:_SetThreadValue(Set.DECIMALSEP, (DWORD) numberformat:NumberDecimalSeparator[0])
		SELF:_SetThreadValue(Set.THOUSANDSEP, (DWORD) numberformat:NumberGroupSeparator[0])
		SELF:_SetThreadValue(Set.EPOCH, (DWORD) 1910)
		SELF:_SetThreadValue(Set.EpochYear, (DWORD) 10)
		SELF:_SetThreadValue(Set.EpochCent, (DWORD) 2000)

		SELF:_SetThreadValue(Set.Intl, CollationMode.Windows)
		RETURN

	INTERNAL STATIC METHOD _SetDateFormat(format AS STRING) AS VOID
		format := format:ToUpper()
		// ensure we have dd, mm and yy
		IF format:IndexOf("DD") == -1 .OR. format:IndexOf("MM") == -1 .OR. format:IndexOf("YY") == -1
			RETURN
		ENDIF
		SetValue(Set.DateFormatNet, format:Replace("D","d"):Replace("Y","y"):Replace("/","'/'"))
		SetValue(Set.DateFormatEmpty, format:Replace("D"," "):Replace("Y"," "):Replace("M"," "))
		SetValue(SET.CENTURY, format:Contains("YYYY"))
		SetValue(Set.DATEFORMAT, format)
		SWITCH format
			CASE "MM/DD/YY"
			CASE "MM/DD/YYYY"
				SetValue(Set.DATECOUNTRY, (DWORD) 1)	// American
			CASE "YY.MM.DD"
			CASE "YYYY.MM.DD"
				SetValue(Set.DATECOUNTRY, (DWORD)2)	// Ansi
			CASE "DD/MM/YY"
			CASE "DD/MM/YYYY"
				SetValue(Set.DATECOUNTRY, (DWORD)3)	// British & french
			CASE "DD.MM.YY"
			CASE "DD.MM.YYYY"
				SetValue(Set.DATECOUNTRY, (DWORD)5)	// German
			CASE "DD-MM-YY"
			CASE "DD-MM-YYYY"
				SetValue(Set.DATECOUNTRY, (DWORD)6)	// Italian
			CASE "YY/MM/DD"
			CASE "YYYY/MM/DD"
				SetValue(Set.DATECOUNTRY, (DWORD)7)	// Japanese
			CASE "MM-DD-YY"
			CASE "MM-DD-YYYY"
				SetValue(Set.DATECOUNTRY, (DWORD)8)	// USA
			OTHERWISE
				SetValue(Set.DATECOUNTRY, (DWORD)0)
		END SWITCH

	INTERNAL STATIC METHOD _SetDateCountry(country AS DWORD) AS VOID
		IF country > 8
			RETURN
		END IF

		SetValue<DWORD>(Set.DateCountry, country)

		LOCAL format, year AS STRING
		year := IIF(Century , "YYYY" , "YY")
		SWITCH country
			CASE 1 // American
				format := "MM/DD/" + year
			CASE 2 // Ansi
				format := year + ".MM.DD"
			CASE 3 // British & french
			CASE 4 // British & french
				format := "DD/MM/" + year
			CASE 5 // German
				format := "DD.MM." + year
			CASE 6 // Italian
				format := "DD-MM-" + year
			CASE 7 // Japanese
				format := year + "/MM/DD"
			CASE 8 // USA
				format := "MM-DD-" + year
			OTHERWISE
				format := "MM/DD/" + year
		END SWITCH
		// this will adjust DateFormatNet, DateFormatEmpty etc, but also DateCountry again
		_SetDateFormat(format)

	PRIVATE _workareas AS WorkAreas
	/// The workarea information for the current Thread.
	PUBLIC PROPERTY Workareas AS WorkAreas
	GET
		IF _workareas == NULL_OBJECT
			_workareas := WorkAreas{}
		ENDIF
		RETURN _workareas
	END GET
	END PROPERTY
	PRIVATE _collationTable AS BYTE[]
	PUBLIC STATIC PROPERTY CollationTable AS BYTE[]
	GET
		LOCAL coll AS BYTE[]
		coll := GetInstance():_collationTable
		IF coll == NULL .OR. coll :Length < 256
			_SetCollation("Generic")
			coll := GetInstance():_collationTable := GetValue<BYTE[]>(SET.CollationTable)
		ENDIF
		RETURN coll
	END GET
	SET
		GetInstance():_collationTable  := VALUE
		SetValue(Set.CollationTable, VALUE)
		IF OnCollationChanged != NULL
			OnCollationChanged(GetInstance(), EventArgs{})
		ENDIF
	END SET
	END PROPERTY

	STATIC INTERNAL _macrocompilerType   AS System.Type
    STATIC INTERNAL _macrocompiler       AS IMacroCompiler
	PUBLIC STATIC PROPERTY MacroCompiler AS IMacroCompiler
        GET
            IF _macrocompiler == NULL
                _LoadMacroCompiler()
            ENDIF
            RETURN _macrocompiler
        END GET
        SET
            _macrocompiler := VALUE
        END SET
    END PROPERTY

	PUBLIC STATIC EVENT OnCodePageChanged AS EventHandler
	PUBLIC STATIC EVENT OnCollationChanged AS EventHandler

    PRIVATE STATIC METHOD _LoadMacroCompiler() AS VOID
        IF _macroCompilerType == NULL_OBJECT
            VAR oMacroAsm := AssemblyHelper.Load("XSharp.MacroCompiler")
		    IF oMacroAsm != NULL_OBJECT
			    LOCAL oType AS System.Type
			    oType := oMacroAsm:GetType("XSharp.MacroCompiler",FALSE,TRUE)
			    IF oType != NULL_OBJECT
				    // create instance of this type
				    IF TYPEOF(IMacroCompiler):IsAssignableFrom(oType)
					    _macroCompilerType := oType
				    ELSE
					    THROW Error{EG_CORRUPTION, "", "Could not create the macro compiler from the type "+ otype:Fullname+" in the assembly "+oMacroAsm:Location}
				    ENDIF
			    ELSE
				    THROW Error{EG_CORRUPTION, "", "Could not load the macro compiler class in the assembly "+oMacroAsm:Location}
                ENDIF
            ELSE
                // AssemblyHelper.Load will throw an exception
                NOP
		    ENDIF
        ENDIF
        IF _macroCompilerType != NULL_OBJECT
			_macroCompiler := Activator:CreateInstance(_macroCompilerType) ASTYPE IMacroCompiler
		ENDIF
		RETURN

END CLASS


[Runtime] Adjusted Error:ToString() to use tabbed output

USING System
USING System.Collections.Generic
USING System.Text
USING System.Reflection
BEGIN NAMESPACE XSharp
  /// XSharp Runtime base Error class
  CLASS Error INHERIT Exception
    /// A string representing the name of the subsystem generating the error.
    PROPERTY SubSystem AS STRING AUTO  := "BASE"
    /// An integer numeric value representing a Visual Objects generic error code.
    /// <Seealso cref="T:XSharp.Gencode"/>
    PROPERTY Gencode AS DWORD AUTO    := EG_UNKNOWN
    /// An string containing the description of the Gencode.
    PROPERTY GenCodeText AS STRING GET IIF (Gencode != 0, ErrString(Gencode), "Unknown GenCode")
    /// An integer numeric value representing a subsystem-specific error code.
    PROPERTY SubCode AS DWORD AUTO    := 0
    /// An string containing the description of the SubCode.
    PROPERTY SubCodeText AS STRING GET IIF (SubCode != 0, __CavoStr(SubCode), "Unknown SubCode")
    /// A string representing the name of the function or method in which the error occurred.
    PROPERTY FuncSym AS STRING AUTO   := ""
    /// A string representing the name used to open the file associated with the error condition.
    PROPERTY FileName AS STRING AUTO  := ""
    /// A constant indicating the severity of the error condition.
    /// <Seealso cref="T:XSharp.Severity"/>
    PROPERTY Severity AS DWORD AUTO   := ES_ERROR
    /// A string that describes the error condition.
    PROPERTY Description		AS STRING AUTO := ""
    /// A string representing the argument supplied to an operator or function when an argument error occurs.
    PROPERTY Arg				AS STRING AUTO := ""
    PRIVATE  _ArgType			AS DWORD
    /// A numeric value representing the data type of the argument that raised the error.
    PROPERTY ArgType			AS DWORD
      GET
        RETURN _ArgType
      END GET
      SET
        _ArgType := VALUE
        _ArgTypeType := UsualTypeToType(VALUE)
      END SET
    END PROPERTY
    PRIVATE  _ArgTypeType 		:= NULL AS System.Type
    /// The system type representing the data type of the argument that raised the error.
    PROPERTY ArgTypeType		AS System.Type
      GET
        RETURN _ArgTypeType
      END GET
      SET
        _ArgTypeType := VALUE
        _ArgType 	 := TypeToUsualType(VALUE)
      END SET
    END PROPERTY

    PRIVATE _ArgTypeReq		AS DWORD
    /// A numeric value representing the expected type of the argument that raised the error.
    PROPERTY ArgTypeReq			AS DWORD
      GET
        RETURN _ArgTypeReq
      END GET
      SET
        _ArgTypeReq := VALUE
        _ArgTypeReqType := UsualTypeToType(VALUE)
      END SET
    END PROPERTY
    PRIVATE  _ArgTypeReqType := NULL	AS System.Type
    /// The system type representing the expected type of the argument that raised the error.
    PROPERTY ArgTypeReqType		AS System.Type
      GET
        RETURN _ArgTypeReqType
      END GET
      SET
        _ArgTypeReqType := VALUE
        _ArgTypeReq 	 := TypeToUsualType(VALUE)
      END SET
    END PROPERTY
    /// A numeric value representing the type of the new result that the error handler substitutes for the operation that produced the error condition.
    PROPERTY SubstituteType     AS DWORD AUTO
    /// A numeric value representing the number of the argument supplied to an operator or function when an argument error occurs.
    PROPERTY ArgNum				AS DWORD AUTO
    /// An object representing the SELF of the method in which the error occurred.
    PROPERTY MethodSelf			AS OBJECT AUTO
    /// A symbol representing the calling function of the function in which the error occurred.
    PROPERTY CallFuncSym		AS STRING AUTO
    /// An array of the arguments supplied to an operator or function when an argument error occurs.
    PROPERTY Args				AS OBJECT[] AUTO
    /// An integer numeric value representing the number of times the failed operation has been attempted.
    PROPERTY Tries				AS INT AUTO := 0
    /// A logical value indicating whether the subsystem can perform default error recovery for the error condition.
    PROPERTY CanDefault         AS LOGIC AUTO
    /// A logical value indicating whether the subsystem can retry the operation that caused the error condition.
    PROPERTY CanRetry           AS LOGIC AUTO
    /// A logical value indicating whether a new result can be substituted for the operation that produced the error condition.
    PROPERTY CanSubstitute      AS LOGIC AUTO
    /// A string that describes the operation being attempted when the error occurred.
    PROPERTY Operation          AS STRING AUTO := ""
    /// A value of 0 indicates that the error condition was not caused by an error from the operating system.  When Error:OsCode is set to a value other
    PROPERTY OSCode				AS DWORD AUTO := 0
    /// Descripion of the OSCode
    PROPERTY OSCodeText			AS STRING GET IIF(OSCode == 0, "", DosErrString(OSCode))
    /// A numeric value representing the file handle supplied to a function when an file error occurs.
    PROPERTY FileHandle         AS DWORD AUTO
    /// A numeric value representing a boundary condition for an operation (such as string overflow or array bound error).
    PROPERTY MaxSize			AS DWORD AUTO
    /// A pointer to the function in which the error occurred.
    /// <remarks>Note This property is for compatibility only. It is not being used in the X# runtime.</remarks>
    PROPERTY FuncPtr            AS IntPtr AUTO := IntPtr.Zero

    /// A value of any data type unused by the Error system.  It is provided as a user-definable slot, allowing arbitrary information to be attached to an Error object and retrieved later
    PROPERTY Cargo              AS OBJECT AUTO

    PRIVATE METHOD setDefaultValues() AS VOID
        SELF:FuncSym := ProcName(2)
        SELF:Args    := <OBJECT>{}
        RETURN

    /// Create an Error Object
    CONSTRUCTOR()
    SELF:setDefaultValues()
    RETURN

    /// Create an Error Object with the specified Description
    CONSTRUCTOR (msg AS STRING)
    SUPER(msg)
    SELF:setDefaultValues()
    SELF:Description := msg
    SELF:GenCode     := EG_EXCEPTION
    RETURN

    /// Create an Error Object with the Innner Exception
    CONSTRUCTOR (ex AS Exception)
    SUPER(ex.Message,ex)
    SELF:setDefaultValues()
    IF ex IS Error
        // Clone Error properties from Inner Exception
        LOCAL e := (Error) ex AS Error
        VAR props := typeof(error):GetProperties()
        FOREACH oProp AS PropertyInfo IN props
            IF oProp:CanWrite
                oProp:SetValue(SELF, oProp:GetValue(e))
            ENDIF
        NEXT
    ELSE
        SELF:Description := ex:Message
        SELF:GenCode     := EG_EXCEPTION
    ENDIF

    /// Create an Error Object with the Innner Exception and other parameters
    CONSTRUCTOR (ex AS Exception, cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, aArgs PARAMS OBJECT[])
    SUPER(ex.Message,ex)
    SELF:setDefaultValues()
    SELF:GenCode     := EG_EXCEPTION
    SELF:FuncSym     := cFuncName
    SELF:Arg         := cArgName
    SELF:ArgNum      := iArgNum
    SELF:Args		 := aArgs

    /// Create an Error Object for a Gencode and Argument Name.
    CONSTRUCTOR (dwgencode AS DWORD, cArg AS STRING)
    SUPER(ErrString( dwGenCode ))
    SELF:setDefaultValues()
    SELF:Gencode := dwGenCode
    SELF:Arg	 := cArg

    /// Create an Error Object for a Gencode, Argument Name and Description.
    CONSTRUCTOR (dwgencode AS DWORD, cArg AS STRING, cDescription AS STRING)
    SUPER(cDescription)
    SELF:setDefaultValues()
    SELF:Gencode		:= dwGenCode
    SELF:Arg			:= cArg
    SELF:Description	:= cDescription

    /// Create an Error Object.
    CONSTRUCTOR (dwgencode AS DWORD, dwSubCode AS DWORD, cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD)
    SUPER(ErrString( dwGenCode ))
    SELF:setDefaultValues()
    SELF:Gencode := dwgencode
    SELF:SubCode := dwSubcode
    SELF:FuncSym     := cFuncName
    SELF:Arg         := cArgName
    SELF:ArgNum      := iArgNum

    /// Create an Error Object.
    CONSTRUCTOR (dwgencode AS DWORD, dwSubCode := 0 AS DWORD)
    SELF:setDefaultValues()
    SELF:Gencode := dwgencode
    SELF:SubCode := dwSubcode

    /// <inheritdoc />
    OVERRIDE METHOD ToString() AS STRING
      LOCAL sb AS StringBuilder
      LOCAL nGenCode AS GenCode
      nGenCode := (GenCode) SELF:GenCode
      sb := StringBuilder{}
      sb:AppendLine( e"Description :\t" + SELF:Description)
      sb:AppendLine( e"SubSystem :\t" 	+ SELF:SubSystem )
      sb:AppendLine( e"GenCode :\t\t" 	+ nGenCode:ToString()  )
      sb:AppendLine( e"GenCodeText :\t" + SELF:GenCodeText  )
      IF SELF:SubCode != 0
        sb:AppendLine( e"SubCode :\t\t" 	+ SELF:SubCode:ToString() )
        sb:AppendLine( e"SubCodeText :\t"	+ SELF:SubCodeText)
      ENDIF
      IF SELF:OsCode != 0
        sb:AppendLine(e"OsCode :\t\t" 	+ SELF:OsCode:ToString() )
        sb:AppendLine(e"OsCodeText :\t" + SELF:OsCodeText )
      ENDIF
      sb:AppendLine(e"FuncSym :\t\t" 	+ SELF:FuncSym   )
      LOCAL sev := (Severity) SELF:Severity AS Severity
      sb:AppendLine(e"Severity :\t\t" 	+ sev:ToString() )
      sb:AppendLine(e"CanDefault :\t"	+ SELF:CanDefault)
      sb:AppendLine(e"CanRetry :\t\t"	+ SELF:CanRetry )
      sb:AppendLine(e"CanSubstitute :\t" + SELF:CanSubstitute)
      IF ! String.IsNullOrEmpty(SELF:Operation)
        sb:AppendLine(e"Operation :\t\t" + SELF:Operation)
      ENDIF
      IF ! String.IsNullOrEmpty(SELF:FileName)
        sb:AppendLine(e"FileName :\t\t"	+ SELF:FileName )
      ENDIF
      IF SELF:Tries != 0
          sb:AppendLine(e"Tries :\t\t" 	+ SELF:Tries:ToString()    )
     ENDIF
      IF SELF:ArgType != 0
        sb:AppendLine(e"ArgType :\t\t" 	+ TypeString(SELF:ArgType    ) )
      ENDIF
      IF SELF:ArgNum != 0
        sb:AppendLine(e"ArgNum :\t\t" 	+ SELF:ArgNum:ToString()    )
      ENDIF
      IF SELF:Arg != NULL
        sb:AppendLine(e"Arg :\t\t" 		+ SELF:Arg)
      ENDIF
      LOCAL cArgs AS STRING
      IF SELF:Args != NULL .AND. SELF:Args:Length > 0
            cArgs := "{"
            LOCAL lFirst := TRUE AS LOGIC
            FOREACH VAR oArg IN SELF:Args
                IF ! lFirst
                    cArgs += ","
                ENDIF
                IF oArg == NULL
                    cArgs += "(NULL)"
                ELSE
                    cArgs += oArg:ToString()
                ENDIF
                lFirst := FALSE
            NEXT
            cArgs += "}"
            sb:AppendLine(e"Args :\t\t" + cArgs)
      ENDIF
      IF SELF:ArgTypeReqType != NULL
        sb:AppendLine(e"ArgTypeReq :\t" + SELF:ArgTypeReqType:FullName)
      ENDIF
      IF ! String.IsNullOrEmpty(SELF:CallFuncSym)
        sb:AppendLine(e"CallFuncSym :\t" + SELF:CallFuncSym  )
      ENDIF
      RETURN sb:ToString()

    /// Throw the error.
    VIRTUAL METHOD @@Throw AS VOID STRICT
        THROW SELF

    #region STATIC methods TO construct an error
    /// <exclude/>
    STATIC METHOD ArgumentError(cFuncName AS STRING, name AS STRING, description AS STRING) AS Error
    RETURN ArgumentError(cFuncName, name, description, 0)

    /// <exclude/>
    STATIC METHOD ArgumentError(cFuncName AS STRING, name AS STRING, iArgnum  AS DWORD, aArgs PARAMS OBJECT[]) AS Error
    VAR err			:= Error{Gencode.EG_ARG, name, ErrString( EG_ARG )}
    err:FuncSym     := cFuncName
    err:Description := err:Message
    err:Argnum		:= iArgNum
    err:args		:= aArgs
    RETURN err

    /// <exclude/>
    STATIC METHOD ArgumentError(cFuncName AS STRING, name AS STRING, description AS STRING, iArgnum AS DWORD) AS Error
    VAR err			:= Error{Gencode.EG_ARG, name, description}
    err:FuncSym     := cFuncName
    err:Description := err:Message
    err:Argnum		:= iArgNum
    RETURN err

    /// <exclude/>
    STATIC METHOD WrapRawException( ex AS Exception ) AS Error
    LOCAL e AS Error
    e			  := Error{ ex }
    e:Description := ErrString( EG_EXCEPTION ) + ":" + ex:Message
    RETURN e

    /// <exclude/>
    STATIC METHOD VOError( dwGenCode AS DWORD, cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, aArgs AS OBJECT[] ) AS Error
        LOCAL e AS Error
        e:= Error{dwGencode,cArgName}
        e:FuncSym := cFuncName
        e:ArgNum := iArgNum
        e:Args := aArgs
        RETURN e

    /// <exclude/>
    STATIC METHOD VOError( ex AS Exception, dwGenCode AS DWORD, cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, aArgs AS OBJECT[]  ) AS Error
    LOCAL e AS Error
    e			  := Error{ ex, cFuncName, cArgName, iArgNum, aArgs }
    e:GenCode     := dwGenCode
    e:Description := ErrString( dwGenCode )
    RETURN e

    /// <exclude/>
    STATIC METHOD VODBError( dwGenCode AS DWORD, dwSubCode AS DWORD, cFuncName AS STRING ) AS Error
    LOCAL e AS Error
    e := Error{dwGenCode, dwSubCode}
    e:SubSystem   := "DBCMD"
    e:FuncSym     := cFuncName
    e:Description := ErrString( dwGenCode )
    RETURN e

    /// <exclude/>
    STATIC METHOD VODBError( dwGenCode AS DWORD, dwSubCode AS DWORD, cFuncName AS STRING, aArgs PARAMS OBJECT[] ) AS Error
    LOCAL e AS Error
    e := Error{dwGenCode, dwSubCode}
    e:SubSystem   := "DBCMD"
    e:FuncSym     := cFuncName
    e:Description := ErrString( dwGenCode )
    e:Args        := aArgs
    IF aArgs:Length > 0
        e:Arg := aArgs[0]:ToString()
    ENDIF
    RETURN e

    /// <exclude/>
    STATIC METHOD VODBError( dwGenCode AS DWORD, dwSubCode AS DWORD, aArgs PARAMS OBJECT[] ) AS Error
    LOCAL e AS Error
    e			  := Error{dwGenCode, dwSubCode}
    e:SubSystem   := "DBCMD"
    e:Description := __CavoStr( dwSubCode)
    e:Args        := aArgs
    IF aArgs:Length > 0
        e:Arg := aArgs[0]:ToString()
    ENDIF
    RETURN e

    /// <exclude/>
    STATIC METHOD VODBError( dwGenCode AS DWORD, dwSubCode AS DWORD, cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, aArgs PARAMS OBJECT[] ) AS Error
    LOCAL e AS Error
    e := Error{dwGenCode, dwSubCode, cFuncName, cArgName, iArgNum}
    e:SubSystem   := "DBCMD"
    IF dwSubCode != 0
        e:Description := __CavoStr( dwSubCode)
    ELSE
        e:Description := ErrString(dwGenCode)
    ENDIF
    e:Args        := aArgs
    RETURN e

    /// <exclude/>
    STATIC METHOD DataTypeError( cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, aArgs PARAMS OBJECT[] ) AS Error
    LOCAL e AS Error
    e			  := Error{ ArgumentException{} , cFuncName, cArgName, iArgNum, aArgs}
    e:GenCode     := EG_DATATYPE
    e:Description := __CavoStr( VOErrors.DATATYPEERROR )
    RETURN e

    /// <exclude/>
    STATIC METHOD ArgumentError( cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, cDescription AS STRING, aArgs PARAMS OBJECT[]) AS Error
    LOCAL e AS Error
    e				:= Error{ ArgumentException{} , cFuncName, cArgName, iArgNum, aArgs}
    e:GenCode     := EG_ARG
    e:Description := cDescription
    RETURN e

    /// <exclude/>
    STATIC METHOD NullArgumentError( cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD ) AS Error
    LOCAL e AS Error
    e := Error{ ArgumentNullException{} ,cFuncName, cArgName, iArgNum}
    e:GenCode     := EG_ARG
    e:Description := __CavoStr( VOErrors.ARGISNULL )
    RETURN e

    /// <exclude/>
    STATIC METHOD BoundError( cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, aArgs PARAMS OBJECT[] ) AS Error
    LOCAL e AS Error
    e := Error{ ArgumentException{ErrString( EG_BOUND) } }
    e:Severity    := ES_ERROR
    e:GenCode     := EG_BOUND
    e:SubSystem   := "BASE"
    e:FuncSym     := cFuncName
    e:Arg         := cArgName
    e:ArgNum      := iArgNum
    e:Args        := aArgs
    RETURN e

    #endregion
    /// <exclude />
    STATIC METHOD TypeToUsualType(oType AS System.Type) AS DWORD
    SWITCH Type.GetTypeCode(oType)
    CASE TypeCode.Boolean
      RETURN __UsualType.logic
    CASE TypeCode.Byte
      RETURN __UsualType.byte
    CASE TypeCode.Char
      RETURN __UsualType.Char
    CASE TypeCode.DateTime
      RETURN __UsualType.DATETIME
    CASE TypeCode.DBNull
      RETURN __UsualType.object
    CASE TypeCode.Decimal
      RETURN __UsualType.DECIMAL
    CASE TypeCode.Double
      RETURN __UsualType.real8
    CASE TypeCode.Empty
      RETURN __UsualType.void
    CASE TypeCode.Int16
      RETURN __UsualType.shortint
    CASE TypeCode.Int32
      RETURN __UsualType.long
    CASE TypeCode.Int64
      RETURN __UsualType.int64
    CASE TypeCode.SByte
      RETURN __UsualType.byte
    CASE TypeCode.Single
      RETURN __UsualType.real4
    CASE TypeCode.UInt16
      RETURN __UsualType.word
    CASE TypeCode.UInt32
      RETURN __UsualType.dword
    CASE TypeCode.UInt64
      RETURN __UsualType.uint64
    OTHERWISE
        SWITCH oType:FullName:ToLower()
        CASE "xsharp.__array"
          RETURN __UsualType.array
        CASE "xsharp.__codeblock"
          RETURN __UsualType.codeblock
        CASE "xsharp.__date"
          RETURN __UsualType.date
        CASE "xsharp.__float"
          RETURN __UsualType.float
        CASE "xsharp.__psz"
          RETURN __UsualType.psz
        CASE "xsharp.__symbol"
          RETURN __UsualType.symbol
        CASE "xsharp.__usual"
          RETURN __UsualType.usual
        CASE "system.intptr"
          RETURN __UsualType.ptr

      END SWITCH
    END SWITCH
    RETURN __UsualType.void

    /// <exclude />
    STATIC METHOD UsualTypeTotype(dwType AS DWORD) AS System.Type
    LOCAL typename := NULL AS STRING
    SWITCH dwType
    CASE __UsualType.array
      typeName := "XSharp.__Array"
    CASE __UsualType.byte
      RETURN typeof(System.Byte)
    CASE __UsualType.char
      RETURN typeof(System.Char)
    CASE __UsualType.codeblock
      typeName := "XSharp.__CodeBlock"
    CASE __UsualType.date
      typeName := "XSharp.__Date"
    CASE __UsualType.dword
      RETURN typeof(System.UInt32)
    CASE __UsualType.int64
      RETURN typeof(System.Int64)
    CASE __UsualType.float
      typeName := "XSharp.__Float"
    CASE __UsualType.logic
      RETURN typeof(System.Boolean)
    CASE __UsualType.long
      RETURN typeof(System.Int32)
    CASE __UsualType.object
      RETURN typeof(System.Object)
    CASE __UsualType.psz
      typeName := "XSharp.__Psz"
    CASE __UsualType.ptr
      RETURN typeof(System.IntPtr)
    CASE __UsualType.real4
      RETURN typeof(System.Single)
    CASE __UsualType.real8
      RETURN typeof(System.Double)
    CASE __UsualType.shortint
      RETURN typeof(System.Int16)
    CASE __UsualType.string
      RETURN typeof(System.String)
    CASE __UsualType.symbol
      typeName := "XSharp.__Symbol"
    CASE __UsualType.uint64
      RETURN typeof(System.Int64)
    CASE __UsualType.usual
      typeName := "XSharp.__Usual"
    CASE __UsualType.void
      RETURN typeof(System.Void)
    CASE __UsualType.word
      RETURN typeof(System.Uint16)
    END SWITCH
    // lookup types in XSharp.VO
    IF typename != NULL
        FOREACH asm AS Assembly IN AppDomain.CurrentDomain:GetAssemblies()
          IF asm:Getname():Name:ToLower() == "xsharp.vo"
            VAR type := asm:GetType(typeName, FALSE, TRUE)
            IF type != NULL
              RETURN type
            ENDIF
          ENDIF
        NEXT
    ENDIF
    RETURN NULL
  END CLASS
  /// <exclude />
  ENUM __UsualType AS BYTE
        // These numbers must match with the types defined in the compiler
        // They also match with the USUAL types in VO (BaseType.h)
        /// <exclude/>
        MEMBER @@Void		:=0
        /// <exclude/>
        MEMBER @@Long		:=1
        /// <exclude/>
        MEMBER @@Date		:=2
        /// <exclude/>
        MEMBER @@Float		:=3
        /// <exclude/>
        MEMBER @@Fixed      := 4 // Note # 4 (FIXED) was defined but never used in VO
        /// <exclude/>
        MEMBER @@Array		:=5
        /// <exclude/>
        MEMBER @@Object		:=6
        /// <exclude/>
        MEMBER @@String		:=7
        /// <exclude/>
        MEMBER @@Logic		:=8
        /// <exclude/>
        MEMBER @@Codeblock	:=9
        /// <exclude/>
        MEMBER @@Symbol		:=10
        // see below for missing values
        // The follow numbers are defined but never stored inside a USUAL in VO and Vulcan
        /// <exclude/>
        MEMBER @@Byte		:=11
        /// <exclude/>
        MEMBER @@ShortInt	:=12
        /// <exclude/>
        MEMBER @@Word		:=13
        /// <exclude/>
        MEMBER @@DWord		:=14
        /// <exclude/>
        MEMBER @@Real4		:=15
        /// <exclude/>
        MEMBER @@Real8		:=16
        /// <exclude/>
        MEMBER @@Psz		:=17
        /// <exclude/>
        MEMBER @@Ptr		:=18
        /// <exclude/>
        MEMBER @@Usual		:=19	// USUAL by Ref, not implemented in Vulcan
        // 20 and 21 not used
        /// <exclude/>
        MEMBER @@Int64		:=22
        /// <exclude/>
        MEMBER @@Uint64     :=23
        /// <exclude/>
        MEMBER @@Char		:=24    // not stored in a usual
        /// <exclude/>
        MEMBER @@Dynamic    :=25
        /// <exclude/>
        MEMBER @@DateTime	:=26
        /// <exclude/>
        MEMBER @@Decimal	:=27
        /// <exclude/>
        MEMBER @@Memo		:=32	// Used in RDD system in VO
        /// <exclude/>
        MEMBER @@Invalid    :=99
    END ENUM

END NAMESPACE

/// <exclude/>
FUNCTION ErrorBuild(pErrInfo AS exception) AS XSharp.ERROR
	RETURN  XSharp.Error{pErrInfo}

USING System
USING System.Collections.Generic
USING System.Text
USING System.Reflection
BEGIN NAMESPACE XSharp
  /// XSharp Runtime base Error class
  CLASS Error INHERIT Exception
    /// A string representing the name of the subsystem generating the error.
    PROPERTY SubSystem AS STRING AUTO  := "BASE"
    /// An integer numeric value representing a Visual Objects generic error code.
    /// <Seealso cref="T:XSharp.Gencode"/>
    PROPERTY Gencode AS DWORD AUTO    := EG_UNKNOWN
    /// An string containing the description of the Gencode.
    PROPERTY GenCodeText AS STRING GET IIF (Gencode != 0, ErrString(Gencode), "Unknown GenCode")
    /// An integer numeric value representing a subsystem-specific error code.
    PROPERTY SubCode AS DWORD AUTO    := 0
    /// An string containing the description of the SubCode.
    PROPERTY SubCodeText AS STRING GET IIF (SubCode != 0, __CavoStr(SubCode), "Unknown SubCode")
    /// A string representing the name of the function or method in which the error occurred.
    PROPERTY FuncSym AS STRING AUTO   := ""
    /// A string representing the name used to open the file associated with the error condition.
    PROPERTY FileName AS STRING AUTO  := ""
    /// A constant indicating the severity of the error condition.
    /// <Seealso cref="T:XSharp.Severity"/>
    PROPERTY Severity AS DWORD AUTO   := ES_ERROR
    /// A string that describes the error condition.
    PROPERTY Description		AS STRING AUTO := ""
    /// A string representing the argument supplied to an operator or function when an argument error occurs.
    PROPERTY Arg				AS STRING AUTO := ""
    PRIVATE  _ArgType			AS DWORD
    /// A numeric value representing the data type of the argument that raised the error.
    PROPERTY ArgType			AS DWORD
      GET
        RETURN _ArgType
      END GET
      SET
        _ArgType := VALUE
        _ArgTypeType := UsualTypeToType(VALUE)
      END SET
    END PROPERTY
    PRIVATE  _ArgTypeType 		:= NULL AS System.Type
    /// The system type representing the data type of the argument that raised the error.
    PROPERTY ArgTypeType		AS System.Type
      GET
        RETURN _ArgTypeType
      END GET
      SET
        _ArgTypeType := VALUE
        _ArgType 	 := TypeToUsualType(VALUE)
      END SET
    END PROPERTY

    PRIVATE _ArgTypeReq		AS DWORD
    /// A numeric value representing the expected type of the argument that raised the error.
    PROPERTY ArgTypeReq			AS DWORD
      GET
        RETURN _ArgTypeReq
      END GET
      SET
        _ArgTypeReq := VALUE
        _ArgTypeReqType := UsualTypeToType(VALUE)
      END SET
    END PROPERTY
    PRIVATE  _ArgTypeReqType := NULL	AS System.Type
    /// The system type representing the expected type of the argument that raised the error.
    PROPERTY ArgTypeReqType		AS System.Type
      GET
        RETURN _ArgTypeReqType
      END GET
      SET
        _ArgTypeReqType := VALUE
        _ArgTypeReq 	 := TypeToUsualType(VALUE)
      END SET
    END PROPERTY
    /// A numeric value representing the type of the new result that the error handler substitutes for the operation that produced the error condition.
    PROPERTY SubstituteType     AS DWORD AUTO
    /// A numeric value representing the number of the argument supplied to an operator or function when an argument error occurs.
    PROPERTY ArgNum				AS DWORD AUTO
    /// An object representing the SELF of the method in which the error occurred.
    PROPERTY MethodSelf			AS OBJECT AUTO
    /// A symbol representing the calling function of the function in which the error occurred.
    PROPERTY CallFuncSym		AS STRING AUTO
    /// An array of the arguments supplied to an operator or function when an argument error occurs.
    PROPERTY Args				AS OBJECT[] AUTO
    /// An integer numeric value representing the number of times the failed operation has been attempted.
    PROPERTY Tries				AS INT AUTO := 0
    /// A logical value indicating whether the subsystem can perform default error recovery for the error condition.
    PROPERTY CanDefault         AS LOGIC AUTO
    /// A logical value indicating whether the subsystem can retry the operation that caused the error condition.
    PROPERTY CanRetry           AS LOGIC AUTO
    /// A logical value indicating whether a new result can be substituted for the operation that produced the error condition.
    PROPERTY CanSubstitute      AS LOGIC AUTO
    /// A string that describes the operation being attempted when the error occurred.
    PROPERTY Operation          AS STRING AUTO := ""
    /// A value of 0 indicates that the error condition was not caused by an error from the operating system.  When Error:OsCode is set to a value other
    PROPERTY OSCode				AS DWORD AUTO := 0
    /// Descripion of the OSCode
    PROPERTY OSCodeText			AS STRING GET IIF(OSCode == 0, "", DosErrString(OSCode))
    /// A numeric value representing the file handle supplied to a function when an file error occurs.
    PROPERTY FileHandle         AS DWORD AUTO
    /// A numeric value representing a boundary condition for an operation (such as string overflow or array bound error).
    PROPERTY MaxSize			AS DWORD AUTO
    /// A pointer to the function in which the error occurred.
    /// <remarks>Note This property is for compatibility only. It is not being used in the X# runtime.</remarks>
    PROPERTY FuncPtr            AS IntPtr AUTO := IntPtr.Zero

    /// A value of any data type unused by the Error system.  It is provided as a user-definable slot, allowing arbitrary information to be attached to an Error object and retrieved later
    PROPERTY Cargo              AS OBJECT AUTO

    PRIVATE METHOD setDefaultValues() AS VOID
        SELF:FuncSym := ProcName(2)
        SELF:Args    := <OBJECT>{}
        RETURN

    /// Create an Error Object
    CONSTRUCTOR()
    SELF:setDefaultValues()
    RETURN

    /// Create an Error Object with the specified Description
    CONSTRUCTOR (msg AS STRING)
    SUPER(msg)
    SELF:setDefaultValues()
    SELF:Description := msg
    SELF:GenCode     := EG_EXCEPTION
    RETURN

    /// Create an Error Object with the Innner Exception
    CONSTRUCTOR (ex AS Exception)
    SUPER(ex.Message,ex)
    SELF:setDefaultValues()
    IF ex IS Error
        // Clone Error properties from Inner Exception
        LOCAL e := (Error) ex AS Error
        VAR props := typeof(error):GetProperties()
        FOREACH oProp AS PropertyInfo IN props
            IF oProp:CanWrite
                oProp:SetValue(SELF, oProp:GetValue(e))
            ENDIF
        NEXT
    ELSE
        SELF:Description := ex:Message
        SELF:GenCode     := EG_EXCEPTION
    ENDIF

    /// Create an Error Object with the Innner Exception and other parameters
    CONSTRUCTOR (ex AS Exception, cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, aArgs PARAMS OBJECT[])
    SUPER(ex.Message,ex)
    SELF:setDefaultValues()
    SELF:GenCode     := EG_EXCEPTION
    SELF:FuncSym     := cFuncName
    SELF:Arg         := cArgName
    SELF:ArgNum      := iArgNum
    SELF:Args		 := aArgs

    /// Create an Error Object for a Gencode and Argument Name.
    CONSTRUCTOR (dwgencode AS DWORD, cArg AS STRING)
    SUPER(ErrString( dwGenCode ))
    SELF:setDefaultValues()
    SELF:Gencode := dwGenCode
    SELF:Arg	 := cArg

    /// Create an Error Object for a Gencode, Argument Name and Description.
    CONSTRUCTOR (dwgencode AS DWORD, cArg AS STRING, cDescription AS STRING)
    SUPER(cDescription)
    SELF:setDefaultValues()
    SELF:Gencode		:= dwGenCode
    SELF:Arg			:= cArg
    SELF:Description	:= cDescription

    /// Create an Error Object.
    CONSTRUCTOR (dwgencode AS DWORD, dwSubCode AS DWORD, cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD)
    SUPER(ErrString( dwGenCode ))
    SELF:setDefaultValues()
    SELF:Gencode := dwgencode
    SELF:SubCode := dwSubcode
    SELF:FuncSym     := cFuncName
    SELF:Arg         := cArgName
    SELF:ArgNum      := iArgNum

    /// Create an Error Object.
    CONSTRUCTOR (dwgencode AS DWORD, dwSubCode := 0 AS DWORD)
    SELF:setDefaultValues()
    SELF:Gencode := dwgencode
    SELF:SubCode := dwSubcode

    /// <inheritdoc />
    OVERRIDE METHOD ToString() AS STRING
      LOCAL sb AS StringBuilder
      LOCAL nGenCode AS GenCode
      nGenCode := (GenCode) SELF:GenCode
      sb := StringBuilder{}
      sb:AppendLine("Description     : " + SELF:Description)
      sb:AppendLine("SubSystem       : " + SELF:SubSystem )
      sb:AppendLine("GenCode         : " + nGenCode:ToString()  )
      sb:AppendLine("GenCodeText     : " + SELF:GenCodeText  )
      IF SELF:SubCode != 0
        sb:AppendLine("SubCode         : " + SELF:SubCode:ToString() )
        sb:AppendLine("SubCodeText     : " + SELF:SubCodeText)
      ENDIF
      IF SELF:OsCode != 0
        sb:AppendLine("OsCode          : " + SELF:OsCode:ToString() )
        sb:AppendLine("OsCodeText      : " + SELF:OsCodeText )
      ENDIF
      sb:AppendLine("FuncSym         : " + SELF:FuncSym   )
      LOCAL sev := (Severity) SELF:Severity AS Severity
      sb:AppendLine("Severity        : " + sev:ToString() )
      sb:AppendLine("CanDefault      : " + SELF:CanDefault)
      sb:AppendLine("CanRetry        : " + SELF:CanRetry )
      sb:AppendLine("CanSubstitute   : " + SELF:CanSubstitute)
      IF ! String.IsNullOrEmpty(SELF:Operation)
        sb:AppendLine("Operation       : " + SELF:Operation)
      ENDIF
      IF ! String.IsNullOrEmpty(SELF:FileName)
        sb:AppendLine("FileName        : " + SELF:FileName )
      ENDIF
      IF SELF:Tries != 0
          sb:AppendLine("Tries           : " + SELF:Tries:ToString()    )
      ENDIF
      IF SELF:ArgType != 0
        sb:AppendLine("ArgType         : " + TypeString(SELF:ArgType    ) )
      ENDIF
      IF SELF:ArgNum != 0
        sb:AppendLine("ArgNum          : " + SELF:ArgNum:ToString()    )
      ENDIF
      IF SELF:Arg != NULL
        sb:AppendLine("Arg             : " + SELF:Arg)
      ENDIF
      LOCAL cArgs AS STRING
      IF SELF:Args != NULL .AND. SELF:Args:Length > 0
            cArgs := "{"
            LOCAL lFirst := TRUE AS LOGIC
            FOREACH VAR oArg IN SELF:Args
                IF ! lFirst
                    cArgs += ","
                ENDIF
                IF oArg == NULL
                    cArgs += "(NULL)"
                ELSE
                    cArgs += oArg:ToString()
                ENDIF
                lFirst := FALSE
            NEXT
            cArgs += "}"
            sb:AppendLine("Args            : " + cArgs)
      ENDIF
      IF SELF:ArgTypeReqType != NULL
        sb:AppendLine("ArgTypeReq      : " + SELF:ArgTypeReqType:FullName)
      END IF
      IF ! String.IsNullOrEmpty(SELF:CallFuncSym)
        sb:AppendLine("CallFuncSym     : " + SELF:CallFuncSym  )
      ENDIF
      RETURN sb:ToString()

    /// Throw the error.
    VIRTUAL METHOD @@Throw AS VOID STRICT
        THROW SELF

    #region STATIC methods TO construct an error
    /// <exclude/>
    STATIC METHOD ArgumentError(cFuncName AS STRING, name AS STRING, description AS STRING) AS Error
    RETURN ArgumentError(cFuncName, name, description, 0)

    /// <exclude/>
    STATIC METHOD ArgumentError(cFuncName AS STRING, name AS STRING, iArgnum  AS DWORD, aArgs PARAMS OBJECT[]) AS Error
    VAR err			:= Error{Gencode.EG_ARG, name, ErrString( EG_ARG )}
    err:FuncSym     := cFuncName
    err:Description := err:Message
    err:Argnum		:= iArgNum
    err:args		:= aArgs
    RETURN err

    /// <exclude/>
    STATIC METHOD ArgumentError(cFuncName AS STRING, name AS STRING, description AS STRING, iArgnum AS DWORD) AS Error
    VAR err			:= Error{Gencode.EG_ARG, name, description}
    err:FuncSym     := cFuncName
    err:Description := err:Message
    err:Argnum		:= iArgNum
    RETURN err

    /// <exclude/>
    STATIC METHOD WrapRawException( ex AS Exception ) AS Error
    LOCAL e AS Error
    e			  := Error{ ex }
    e:Description := ErrString( EG_EXCEPTION ) + ":" + ex:Message
    RETURN e

    /// <exclude/>
    STATIC METHOD VOError( dwGenCode AS DWORD, cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, aArgs AS OBJECT[] ) AS Error
        LOCAL e AS Error
        e:= Error{dwGencode,cArgName}
        e:FuncSym := cFuncName
        e:ArgNum := iArgNum
        e:Args := aArgs
        RETURN e

    /// <exclude/>
    STATIC METHOD VOError( ex AS Exception, dwGenCode AS DWORD, cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, aArgs AS OBJECT[]  ) AS Error
    LOCAL e AS Error
    e			  := Error{ ex, cFuncName, cArgName, iArgNum, aArgs }
    e:GenCode     := dwGenCode
    e:Description := ErrString( dwGenCode )
    RETURN e

    /// <exclude/>
    STATIC METHOD VODBError( dwGenCode AS DWORD, dwSubCode AS DWORD, cFuncName AS STRING ) AS Error
    LOCAL e AS Error
    e := Error{dwGenCode, dwSubCode}
    e:SubSystem   := "DBCMD"
    e:FuncSym     := cFuncName
    e:Description := ErrString( dwGenCode )
    RETURN e

    /// <exclude/>
    STATIC METHOD VODBError( dwGenCode AS DWORD, dwSubCode AS DWORD, cFuncName AS STRING, aArgs PARAMS OBJECT[] ) AS Error
    LOCAL e AS Error
    e := Error{dwGenCode, dwSubCode}
    e:SubSystem   := "DBCMD"
    e:FuncSym     := cFuncName
    e:Description := ErrString( dwGenCode )
    e:Args        := aArgs
    IF aArgs:Length > 0
        e:Arg := aArgs[0]:ToString()
    ENDIF
    RETURN e

    /// <exclude/>
    STATIC METHOD VODBError( dwGenCode AS DWORD, dwSubCode AS DWORD, aArgs PARAMS OBJECT[] ) AS Error
    LOCAL e AS Error
    e			  := Error{dwGenCode, dwSubCode}
    e:SubSystem   := "DBCMD"
    e:Description := __CavoStr( dwSubCode)
    e:Args        := aArgs
    IF aArgs:Length > 0
        e:Arg := aArgs[0]:ToString()
    ENDIF
    RETURN e

    /// <exclude/>
    STATIC METHOD VODBError( dwGenCode AS DWORD, dwSubCode AS DWORD, cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, aArgs PARAMS OBJECT[] ) AS Error
    LOCAL e AS Error
    e := Error{dwGenCode, dwSubCode, cFuncName, cArgName, iArgNum}
    e:SubSystem   := "DBCMD"
    IF dwSubCode != 0
        e:Description := __CavoStr( dwSubCode)
    ELSE
        e:Description := ErrString(dwGenCode)
    ENDIF
    e:Args        := aArgs
    RETURN e

    /// <exclude/>
    STATIC METHOD DataTypeError( cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, aArgs PARAMS OBJECT[] ) AS Error
    LOCAL e AS Error
    e			  := Error{ ArgumentException{} , cFuncName, cArgName, iArgNum, aArgs}
    e:GenCode     := EG_DATATYPE
    e:Description := __CavoStr( VOErrors.DATATYPEERROR )
    RETURN e

    /// <exclude/>
    STATIC METHOD ArgumentError( cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, cDescription AS STRING, aArgs PARAMS OBJECT[]) AS Error
    LOCAL e AS Error
    e				:= Error{ ArgumentException{} , cFuncName, cArgName, iArgNum, aArgs}
    e:GenCode     := EG_ARG
    e:Description := cDescription
    RETURN e

    /// <exclude/>
    STATIC METHOD NullArgumentError( cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD ) AS Error
    LOCAL e AS Error
    e := Error{ ArgumentNullException{} ,cFuncName, cArgName, iArgNum}
    e:GenCode     := EG_ARG
    e:Description := __CavoStr( VOErrors.ARGISNULL )
    RETURN e

    /// <exclude/>
    STATIC METHOD BoundError( cFuncName AS STRING, cArgName AS STRING, iArgNum AS DWORD, aArgs PARAMS OBJECT[] ) AS Error
    LOCAL e AS Error
    e := Error{ ArgumentException{ErrString( EG_BOUND) } }
    e:Severity    := ES_ERROR
    e:GenCode     := EG_BOUND
    e:SubSystem   := "BASE"
    e:FuncSym     := cFuncName
    e:Arg         := cArgName
    e:ArgNum      := iArgNum
    e:Args        := aArgs
    RETURN e

    #endregion
    /// <exclude />
    STATIC METHOD TypeToUsualType(oType AS System.Type) AS DWORD
    SWITCH Type.GetTypeCode(oType)
    CASE TypeCode.Boolean
      RETURN __UsualType.logic
    CASE TypeCode.Byte
      RETURN __UsualType.byte
    CASE TypeCode.Char
      RETURN __UsualType.Char
    CASE TypeCode.DateTime
      RETURN __UsualType.DATETIME
    CASE TypeCode.DBNull
      RETURN __UsualType.object
    CASE TypeCode.Decimal
      RETURN __UsualType.DECIMAL
    CASE TypeCode.Double
      RETURN __UsualType.real8
    CASE TypeCode.Empty
      RETURN __UsualType.void
    CASE TypeCode.Int16
      RETURN __UsualType.shortint
    CASE TypeCode.Int32
      RETURN __UsualType.long
    CASE TypeCode.Int64
      RETURN __UsualType.int64
    CASE TypeCode.SByte
      RETURN __UsualType.byte
    CASE TypeCode.Single
      RETURN __UsualType.real4
    CASE TypeCode.UInt16
      RETURN __UsualType.word
    CASE TypeCode.UInt32
      RETURN __UsualType.dword
    CASE TypeCode.UInt64
      RETURN __UsualType.uint64
    OTHERWISE
        SWITCH oType:FullName:ToLower()
        CASE "xsharp.__array"
          RETURN __UsualType.array
        CASE "xsharp.__codeblock"
          RETURN __UsualType.codeblock
        CASE "xsharp.__date"
          RETURN __UsualType.date
        CASE "xsharp.__float"
          RETURN __UsualType.float
        CASE "xsharp.__psz"
          RETURN __UsualType.psz
        CASE "xsharp.__symbol"
          RETURN __UsualType.symbol
        CASE "xsharp.__usual"
          RETURN __UsualType.usual
        CASE "system.intptr"
          RETURN __UsualType.ptr

      END SWITCH
    END SWITCH
    RETURN __UsualType.void

    /// <exclude />
    STATIC METHOD UsualTypeTotype(dwType AS DWORD) AS System.Type
    LOCAL typename := NULL AS STRING
    SWITCH dwType
    CASE __UsualType.array
      typeName := "XSharp.__Array"
    CASE __UsualType.byte
      RETURN typeof(System.Byte)
    CASE __UsualType.char
      RETURN typeof(System.Char)
    CASE __UsualType.codeblock
      typeName := "XSharp.__CodeBlock"
    CASE __UsualType.date
      typeName := "XSharp.__Date"
    CASE __UsualType.dword
      RETURN typeof(System.UInt32)
    CASE __UsualType.int64
      RETURN typeof(System.Int64)
    CASE __UsualType.float
      typeName := "XSharp.__Float"
    CASE __UsualType.logic
      RETURN typeof(System.Boolean)
    CASE __UsualType.long
      RETURN typeof(System.Int32)
    CASE __UsualType.object
      RETURN typeof(System.Object)
    CASE __UsualType.psz
      typeName := "XSharp.__Psz"
    CASE __UsualType.ptr
      RETURN typeof(System.IntPtr)
    CASE __UsualType.real4
      RETURN typeof(System.Single)
    CASE __UsualType.real8
      RETURN typeof(System.Double)
    CASE __UsualType.shortint
      RETURN typeof(System.Int16)
    CASE __UsualType.string
      RETURN typeof(System.String)
    CASE __UsualType.symbol
      typeName := "XSharp.__Symbol"
    CASE __UsualType.uint64
      RETURN typeof(System.Int64)
    CASE __UsualType.usual
      typeName := "XSharp.__Usual"
    CASE __UsualType.void
      RETURN typeof(System.Void)
    CASE __UsualType.word
      RETURN typeof(System.Uint16)
    END SWITCH
    // lookup types in XSharp.VO
    IF typename != NULL
        FOREACH asm AS Assembly IN AppDomain.CurrentDomain:GetAssemblies()
          IF asm:Getname():Name:ToLower() == "xsharp.vo"
            VAR type := asm:GetType(typeName, FALSE, TRUE)
            IF type != NULL
              RETURN type
            ENDIF
          ENDIF
        NEXT
    ENDIF
    RETURN NULL
  END CLASS
  /// <exclude />
  ENUM __UsualType AS BYTE
        // These numbers must match with the types defined in the compiler
        // They also match with the USUAL types in VO (BaseType.h)
        /// <exclude/>
        MEMBER @@Void		:=0
        /// <exclude/>
        MEMBER @@Long		:=1
        /// <exclude/>
        MEMBER @@Date		:=2
        /// <exclude/>
        MEMBER @@Float		:=3
        /// <exclude/>
        MEMBER @@Fixed      := 4 // Note # 4 (FIXED) was defined but never used in VO
        /// <exclude/>
        MEMBER @@Array		:=5
        /// <exclude/>
        MEMBER @@Object		:=6
        /// <exclude/>
        MEMBER @@String		:=7
        /// <exclude/>
        MEMBER @@Logic		:=8
        /// <exclude/>
        MEMBER @@Codeblock	:=9
        /// <exclude/>
        MEMBER @@Symbol		:=10
        // see below for missing values
        // The follow numbers are defined but never stored inside a USUAL in VO and Vulcan
        /// <exclude/>
        MEMBER @@Byte		:=11
        /// <exclude/>
        MEMBER @@ShortInt	:=12
        /// <exclude/>
        MEMBER @@Word		:=13
        /// <exclude/>
        MEMBER @@DWord		:=14
        /// <exclude/>
        MEMBER @@Real4		:=15
        /// <exclude/>
        MEMBER @@Real8		:=16
        /// <exclude/>
        MEMBER @@Psz		:=17
        /// <exclude/>
        MEMBER @@Ptr		:=18
        /// <exclude/>
        MEMBER @@Usual		:=19	// USUAL by Ref, not implemented in Vulcan
        // 20 and 21 not used
        /// <exclude/>
        MEMBER @@Int64		:=22
        /// <exclude/>
        MEMBER @@Uint64     :=23
        /// <exclude/>
        MEMBER @@Char		:=24    // not stored in a usual
        /// <exclude/>
        MEMBER @@Dynamic    :=25
        /// <exclude/>
        MEMBER @@DateTime	:=26
        /// <exclude/>
        MEMBER @@Decimal	:=27
        /// <exclude/>
        MEMBER @@Memo		:=32	// Used in RDD system in VO
        /// <exclude/>
        MEMBER @@Invalid    :=99
    END ENUM

END NAMESPACE

/// <exclude/>
FUNCTION ErrorBuild(pErrInfo AS exception) AS XSharp.ERROR
	RETURN  XSharp.Error{pErrInfo}