Adjusted XPorter to add XSharp.RT assembly

//
// 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.Xml
DEFINE EXTENSION := "xsproj"  AS STRING

CLASS ProjectConverter
	PROTECT oDoc 	AS XmlDocument
	PROTECT nGroup  AS LONG
	PROTECT cSchema AS STRING
	PROTECT cGuid   AS STRING
	PROTECT cPath	AS STRING
    PROTECT lUseXsRuntime AS LOGIC
	PROTECT oProgress AS IProgress
	PROTECT lRuntimeAdded AS LOGIC
	PROTECT oProjectNode AS XmlElement
	PROTECT lHasProjectExtensions AS LOGIC
	PROPERTY Guid AS STRING GET cGuid
	CONSTRUCTOR(oProg AS IProgress, lUseXsRT AS LOGIC)
		cSchema := "http://schemas.microsoft.com/developer/msbuild/2003"
		nGroup  := 0
        cGuid   := System.Guid.NewGuid().ToString("B"):ToUpper()
        lRuntimeAdded := FALSE
        SELF:oProgress := oProg
        SELF:lUseXsRuntime := lUseXsRT

METHOD ConvertProjectFile(cSource AS STRING, cTarget AS STRING, useXsRuntime AS LOGIC) AS LOGIC
	oProgress:WriteLine("Creating ... "+System.IO.Path.GetFileName(cTarget))
	cPath := System.IO.Path.GetDirectoryName(cSource)+"\"
	IF ! SELF:LoadFile(cSource)
		RETURN FALSE
	ENDIF
	SELF:WalkNode(oDoc)
	IF (!lHasProjectExtensions ) .AND. oProjectNode != NULL_OBJECT
		VAR oExt := oDoc:CreateElement("ProjectExtensions",cSchema)
		VAR oCap := oDoc:CreateElement("ProjectCapabilities",cSchema)
		oExt:AppendChild(oCap)
		oCap:AppendChild(oDoc:CreateElement("ProjectConfigurationsDeclaredAsItems",cSchema))
		oProjectNode:AppendChild(oExt)
	ENDIF
	SELF:SaveFile(cTarget)
	RETURN TRUE

  METHOD Save2String() AS STRING STRICT
      LOCAL cString         AS STRING
      LOCAL oWriter             AS System.Xml.XmlTextWriter
      LOCAL oStringWriter       AS System.IO.StringWriter
      cString := oDoc:OuterXml
      oStringWriter := System.IO.StringWriter{}
      oWriter     := System.Xml.XmlTextWriter{oStringWriter}
      oWriter:Formatting := System.Xml.Formatting.Indented
      oDoc:WriteTo(oWriter)
      cString := oStringWriter:ToString()
      RETURN cString

   METHOD SaveFile(strFileName AS STRING) AS LOGIC STRICT
      LOCAL lRet        AS LOGIC
      LOCAL oTargetFile  AS System.IO.StreamWriter
      lRet := FALSE
      IF oDoc:HasChildNodes
         oTargetFile := System.IO.StreamWriter{strFileName, FALSE}
         oTargetFile:Write( SELF:Save2String() )
         oTargetFile:Close()
         lRet := TRUE
      ENDIF
      RETURN lRet

METHOD CloneNode(oNode AS XmlNode) AS XmlNode
	LOCAL oResult AS XmlNode
	oResult := oNode:CloneNode(FALSE)
	oResult:InnerText := oNode:InnerText
	RETURN oResult

METHOD UpdateNode(oParent AS XmlNode, oElement AS XmlElement) AS VOID
	LOCAL oChild AS XmlElement
	LOCAL oAttribute AS XmlAttribute
	IF aDelete:Contains(oElement:Name:ToLower())
		// remove the node
		oParent:RemoveChild(oElement)
	ELSEIF aRename:ContainsKey(oElement:Name)
		// Renaming Nodes is not supported. Create a new node and
		// Copy its attributes and children
		// and then replace the existing node
		oChild := oDoc:CreateElement(aRename[oElement:Name],cSchema)
		DO WHILE oElement:HasAttributes
			oChild:SetAttributeNode(oElement:RemoveAttributeNode(oElement:Attributes[0]))
		ENDDO
		DO WHILE oElement:HasChildNodes
			oChild:AppendChild(oElement:FirstChild)
		ENDDO
		oParent:ReplaceChild(oChild, oElement)
	ELSE
		// Some nodes that require special processing
		SWITCH oElement:Name:ToLower()
		CASE "compile"
		CASE "none"
		CASE "vobinary"
		CASE "nativeresource"
			VAR cItem := oElement:GetAttribute("Include")
			cItem := cPath+cItem
			VAR oChild1 := oElement:FirstChild
			IF oChild1 != NULL .AND. oChild1:Name:ToLowerInvariant() == "dependentupon"
				VAR  cInnerText := oChild1:InnerText
				IF cInnerText:Contains("\")
					// check to see if parent node is in the same folder as the child node.
					IF System.IO.File.Exists(cItem) .AND. System.IO.File.Exists(cPath+cInnerText)
						IF System.IO.Path.GetFullPath(cItem) == System.IO.Path.GetFullPath(cPath+cInnerText)
							// paths are equal, only write filename
							cInnerText := System.IO.Path.GetFileName(cInnerText)
							oChild1:InnerText := cInnerText
						ENDIF
					ENDIF
				ENDIF
			ENDIF

		CASE "import"
			// change import
			oAttribute := (XmlAttribute) oElement:Attributes:GetNamedItem("Project")
			IF oAttribute:Value:ToLower():Contains("vulcan.net")
				oAttribute:Value := "$(MSBuildExtensionsPath)\XSharp\XSharp.targets"
			ENDIF
		CASE "project"
			// Only for main project node, not for project node inside projectreference
			IF (oParent IS XMLDocument)
				// Import the schema
				SELF:oProjectNode := oElement
			ENDIF

		CASE "projectguid"
			// new guid
			oElement:InnerText := cGuid
		CASE "projecttypeguids"
			// WPF project
			// our WPF ProjectFactory
			// Generic WPF project
			// Our project factory
			oElement:InnerText := "{5ADB76EC-7017-476A-A8E0-25D4202FFCF0};{60DC8134-EBA5-43B8-BCC9-BB4BC16C2548};{AA6C8D78-22FF-423A-9C7C-5F2393824E04}"
		CASE "projectreference"
			// update extension in project references
			oAttribute := (XmlAttribute) oElement:Attributes:GetNamedItem("Include")
			IF oAttribute != NULL
				oAttribute:Value := oAttribute:Value:Replace(".vnproj", "."+EXTENSION)
			ENDIF
		CASE "propertygroup"
			// Only insert code inside the first propertygroup
			IF ++nGroup == 1
				LOCAL oImport AS XmlNode
				// Add Import
				oImport := oDoc:CreateElement("Import",cSchema)
				oAttribute := oDoc:CreateAttribute("Project")
				oAttribute:Value := "$(MSBuildExtensionsPath)\XSharp\XSharp.Default.props"
				oImport:Attributes:Append(oAttribute)
				oParent:InsertBefore(oImport, oElement)
				// Add propertygroup before Import with Label="Globals" and child <XSharpProjectExtensionsPath>
				oChild := oDoc:CreateElement( "PlatformTarget", cSchema)
				oChild:InnerText := "x86"
				oElement:InsertBefore(oChild,oElement:FirstChild)
				oChild := oDoc:CreateElement( "Dialect", cSchema)
				oChild:InnerText := "Vulcan"
				oElement:InsertBefore(oChild,oElement:FirstChild)
			ELSE
				// ALl other project groups.
				// Adjust the condition when needed
				VAR oCondition := (XMLAttribute) oElement:Attributes:GetNamedItem("Condition")
				// <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'" Label="Configuration">
				IF oCondition != NULL
					VAR  cInnerText := oCondition:InnerText
					IF ! cInnerText:ToLower():Contains("platform")
						IF cInnerText:ToLower():Contains("release")
							oCondition:InnerText := "'$(Configuration)|$(Platform)' == 'Release|AnyCPU'"
						ELSE
							oCondition:InnerText := "'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'"
						ENDIF
					ENDIF
				ENDIF
			ENDIF
		CASE "projectextensions"
			// add <ProjectCapabilities><ProjectConfigurationsDeclaredAsItems /></ProjectCapabilities>
			oChild := oDoc:CreateElement("ProjectCapabilities",cSchema)
			oChild:AppendChild(oDoc:CreateElement("ProjectConfigurationsDeclaredAsItems",cSchema))
			oElement:AppendChild(oChild)
			lHasProjectExtensions := TRUE
		CASE "reference"
			// Add RT assemblies after 1st reference
            VAR cAttribute := oElement:GetAttribute("Include")
            IF cAttribute != NULL .and. SELF:lUseXsRuntime
                SWITCH cAttribute:Tolower()
                CASE "vulcanvowin32apilibrary"
                CASE "vulcanvosystemclasses"
                CASE "vulcanvorddclasses"
                CASE "vulcanvosqlclasses"
                CASE "vulcanvoguiclasses"
                CASE "vulcanvointernetclasses"
                CASE "vulcanvoconsoleclasses"
                    cAttribute := cAttribute:Substring(6)
                    oElement:SetAttribute("Include", cAttribute)
                    // remove all version info in the children of the oElement
                    DO WHILE oElement:FirstChild != NULL
                        oElement:RemoveChild(oElement:FirstChild)
                    ENDDO
                    SELF:AddReferenceSubNodes(oElement, cAttribute)
                OTHERWISE
                    NOP
                END SWITCH
            ENDIF
			IF !SELF:lRuntimeAdded
                LOCAL cRt1, cRt2, cRT3 AS STRING
                IF SELF:lUseXsRuntime
                    cRT1 := "XSharp.Core"
                    cRT2 := "XSharp.RT"
                    cRT3 := "XSharp.VO"
                ELSE
                    cRT1 := "VulcanRT"
                    cRT2 := "VulcanRTFuncs"
                    cRT3 := ""
                ENDIF
                SELF:AddReference(oElement, cRT1)
                SELF:AddReference(oElement, cRT2)
                if !String.IsNullOrEmpty(cRT3)
                    SELF:AddReference(oElement, cRT3)
                endif
				SELF:lRuntimeAdded := TRUE
			ENDIF
		OTHERWISE
			// All other elements should not be changed
			NOP
		END SWITCH
	ENDIF
	RETURN

METHOD AddReference(oElement AS XMLNode, cReference AS STRING) AS VOID
    VAR oChild := oDoc:CreateElement("Reference",cSchema)
    oElement:ParentNode:AppendChild(oChild)
	VAR oAttribute := oDoc:CreateAttribute("Include")
	oAttribute:Value := cReference
	oChild:Attributes:Append(oAttribute)
    SELF:AddReferenceSubNodes(oChild, cReference)

METHOD AddReferenceSubNodes(oRef AS XmlNode, cReference AS STRING) AS VOID
    VAR oSub := oDoc:CreateElement("Name",cSchema)
    oSub:InnerText := cReference
    oRef:AppendChild(oSub)
    oSub := oDoc:CreateElement("AssemblyName",cSchema)
    oSub:InnerText := cReference+".DLL"
    oRef:AppendChild(oSub)
	RETURN
METHOD WalkNode(oNode AS XmlNode) AS VOID
	LOCAL aChildren AS List<XmlNode>
	aChildren := List<XmlNode>{}
	FOREACH oChild AS XmlNode IN oNode:ChildNodes
		aChildren:Add(oChild)
	NEXT
	FOREACH oChild AS XmlNode IN aChildren
		IF oChild IS XmlElement
			SELF:UpdateNode(oNode, (XmlElement) oChild)
		ENDIF
		SELF:WalkNode((XMlNode) oChild)
	NEXT
	RETURN

    PROTECT METHOD _LoadFileFromReader(oReader AS System.IO.TextReader) AS LOGIC STRICT
        LOCAL lOk AS LOGIC
        TRY
            oDoc := System.Xml.XmlDocument{}
            oDoc:Load(oReader)
            lOk := TRUE
        CATCH
            lOk := FALSE
        END TRY
        RETURN lOk

   METHOD LoadFile(strFileName AS STRING) AS LOGIC STRICT
        LOCAL lResult := FALSE AS LOGIC
        IF System.IO.File.Exists(strFileName)
            LOCAL oReader AS System.IO.TextReader
            oReader := System.IO.StreamReader{strFileName,TRUE}
            lResult := SELF:_LoadFileFromReader(oReader)
            oReader:Close()
        ENDIF
        RETURN lResult

   METHOD LoadFileFromString(strXMLString AS STRING) AS LOGIC STRICT
        LOCAL lResult AS LOGIC
        LOCAL oReader AS System.IO.StringReader
        oReader := System.IO.StringReader{strXMLString}
        lResult := SELF:_LoadFileFromReader(oReader)
        oReader:Close()
        RETURN lResult

	STATIC PROTECT aRename AS Dictionary<STRING, STRING>
	STATIC PROTECT aDelete AS List<STRING>
	STATIC CONSTRUCTOR()
		aRename := Dictionary<STRING, STRING> {StringComparer.CurrentCultureIgnoreCase}
		aRename:Add("ZeroBasedArrays","AZ")
		aRename:Add("CaseSensitiveIdentifiers","CS")
		aRename:Add("CheckFloatOverflows","FOVF")
		aRename:Add("ImplicitNamespaceLookup","INS")
		aRename:Add("AllowLateBinding","LB")
		aRename:Add("UseDefaultNamespace","NS")
		aRename:Add("CheckForOverflowUnderflow","OVF")
		aRename:Add("GeneratePreprocessorOutput","PPO")
		aRename:Add("AllowUnsafeCode","UnSafe")
		aRename:Add("VOCompatibleStringInit","VO2")
		aRename:Add("AllMethodsVirtual","VO3")
		aRename:Add("ImplicitSignConversions","VO4")
		aRename:Add("VOCompatibleCallingConventions","VO5")
		aRename:Add("VOResolveFunctionPointers","VO6")
		aRename:Add("VOCompatibleImplicitConversions","VO7")
		aRename:Add("VOCompatiblePreprocessor","VO8")
		aRename:Add("VOCompatibleImplicitRetvals","VO9")
		aRename:Add("VOCompatibleIIF","VO10")
		aRename:Add("VOCompatibleArithmeticConversions","VO11")
		aRename:Add("IntegerDivisionsReturnFloat","VO12")
		aRename:Add("VOCompatibleStringComparisons","VO13")
		aRename:Add("VOFloatLiterals","VO14")
		aRename:Add("AdditionalOptions","CommandLineOption")
		// Items to delete

		VAR aTemp := List<STRING>{}
		aTemp:Add("DisabledWarnings")
		aTemp:Add("ProjectName")
		aTemp:Add("ProjectExt")
		aTemp:Add("ProjectDir")
		aTemp:Add("ProjectFileName")
		aTemp:Add("ProjectPath")
		aTemp:Add("ProjectView")
		aTemp:Add("SchemaVersion")
		aDelete := List<STRING>{}
		FOREACH s AS STRING IN aTemp
			aDelete:Add(s:ToLower())
		NEXT

	RETURN

STATIC METHOD Convert(cFile AS STRING, oProgress AS IProgress, lUseXsRt AS LOGIC) AS VOID
	LOCAL oConverter AS ProjectConverter
	LOCAL cSource AS STRING
	LOCAL cTarget AS STRING
	oConverter := ProjectConverter{oProgress,lUseXsRT}
	cSource := cFile
	cTarget := System.IO.Path.ChangeExtension(cSource, EXTENSION)
	IF oConverter:ConvertProjectFile(cSource, cTarget,lUseXsRt)
		oProgress:WriteLine( "Converted "+System.IO.Path.GetFileName(cSource)+" to " +System.IO.Path.GetFileName(cTarget))
	ELSE
		oProgress:WriteLine( "An error occurred")
	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.Xml
DEFINE EXTENSION := "xsproj"  AS STRING

CLASS ProjectConverter
	PROTECT oDoc 	AS XmlDocument
	PROTECT nGroup  AS LONG
	PROTECT cSchema AS STRING
	PROTECT cGuid   AS STRING
	PROTECT cPath	AS STRING
    PROTECT lUseXsRuntime AS LOGIC
	PROTECT oProgress AS IProgress
	PROTECT lRuntimeAdded AS LOGIC
	PROTECT oProjectNode AS XmlElement
	PROTECT lHasProjectExtensions AS LOGIC
	PROPERTY Guid AS STRING GET cGuid
	CONSTRUCTOR(oProg AS IProgress, lUseXsRT AS LOGIC)
		cSchema := "http://schemas.microsoft.com/developer/msbuild/2003"
		nGroup  := 0
        cGuid   := System.Guid.NewGuid().ToString("B"):ToUpper()
        lRuntimeAdded := FALSE
        SELF:oProgress := oProg
        SELF:lUseXsRuntime := lUseXsRT

METHOD ConvertProjectFile(cSource AS STRING, cTarget AS STRING, useXsRuntime AS LOGIC) AS LOGIC
	oProgress:WriteLine("Creating ... "+System.IO.Path.GetFileName(cTarget))
	cPath := System.IO.Path.GetDirectoryName(cSource)+"\"
	IF ! SELF:LoadFile(cSource)
		RETURN FALSE
	ENDIF
	SELF:WalkNode(oDoc)
	IF (!lHasProjectExtensions ) .AND. oProjectNode != NULL_OBJECT
		VAR oExt := oDoc:CreateElement("ProjectExtensions",cSchema)
		VAR oCap := oDoc:CreateElement("ProjectCapabilities",cSchema)
		oExt:AppendChild(oCap)
		oCap:AppendChild(oDoc:CreateElement("ProjectConfigurationsDeclaredAsItems",cSchema))
		oProjectNode:AppendChild(oExt)
	ENDIF
	SELF:SaveFile(cTarget)
	RETURN TRUE

  METHOD Save2String() AS STRING STRICT
      LOCAL cString         AS STRING
      LOCAL oWriter             AS System.Xml.XmlTextWriter
      LOCAL oStringWriter       AS System.IO.StringWriter
      cString := oDoc:OuterXml
      oStringWriter := System.IO.StringWriter{}
      oWriter     := System.Xml.XmlTextWriter{oStringWriter}
      oWriter:Formatting := System.Xml.Formatting.Indented
      oDoc:WriteTo(oWriter)
      cString := oStringWriter:ToString()
      RETURN cString

   METHOD SaveFile(strFileName AS STRING) AS LOGIC STRICT
      LOCAL lRet        AS LOGIC
      LOCAL oTargetFile  AS System.IO.StreamWriter
      lRet := FALSE
      IF oDoc:HasChildNodes
         oTargetFile := System.IO.StreamWriter{strFileName, FALSE}
         oTargetFile:Write( SELF:Save2String() )
         oTargetFile:Close()
         lRet := TRUE
      ENDIF
      RETURN lRet

METHOD CloneNode(oNode AS XmlNode) AS XmlNode
	LOCAL oResult AS XmlNode
	oResult := oNode:CloneNode(FALSE)
	oResult:InnerText := oNode:InnerText
	RETURN oResult

METHOD UpdateNode(oParent AS XmlNode, oElement AS XmlElement) AS VOID
	LOCAL oChild AS XmlElement
	LOCAL oAttribute AS XmlAttribute
	IF aDelete:Contains(oElement:Name:ToLower())
		// remove the node
		oParent:RemoveChild(oElement)
	ELSEIF aRename:ContainsKey(oElement:Name)
		// Renaming Nodes is not supported. Create a new node and
		// Copy its attributes and children
		// and then replace the existing node
		oChild := oDoc:CreateElement(aRename[oElement:Name],cSchema)
		DO WHILE oElement:HasAttributes
			oChild:SetAttributeNode(oElement:RemoveAttributeNode(oElement:Attributes[0]))
		ENDDO
		DO WHILE oElement:HasChildNodes
			oChild:AppendChild(oElement:FirstChild)
		ENDDO
		oParent:ReplaceChild(oChild, oElement)
	ELSE
		// Some nodes that require special processing
		SWITCH oElement:Name:ToLower()
		CASE "compile"
		CASE "none"
		CASE "vobinary"
		CASE "nativeresource"
			VAR cItem := oElement:GetAttribute("Include")
			cItem := cPath+cItem
			VAR oChild1 := oElement:FirstChild
			IF oChild1 != NULL .AND. oChild1:Name:ToLowerInvariant() == "dependentupon"
				VAR  cInnerText := oChild1:InnerText
				IF cInnerText:Contains("\")
					// check to see if parent node is in the same folder as the child node.
					IF System.IO.File.Exists(cItem) .AND. System.IO.File.Exists(cPath+cInnerText)
						IF System.IO.Path.GetFullPath(cItem) == System.IO.Path.GetFullPath(cPath+cInnerText)
							// paths are equal, only write filename
							cInnerText := System.IO.Path.GetFileName(cInnerText)
							oChild1:InnerText := cInnerText
						ENDIF
					ENDIF
				ENDIF
			ENDIF

		CASE "import"
			// change import
			oAttribute := (XmlAttribute) oElement:Attributes:GetNamedItem("Project")
			IF oAttribute:Value:ToLower():Contains("vulcan.net")
				oAttribute:Value := "$(MSBuildExtensionsPath)\XSharp\XSharp.targets"
			ENDIF
		CASE "project"
			// Only for main project node, not for project node inside projectreference
			IF (oParent IS XMLDocument)
				// Import the schema
				SELF:oProjectNode := oElement
			ENDIF

		CASE "projectguid"
			// new guid
			oElement:InnerText := cGuid
		CASE "projecttypeguids"
			// WPF project
			// our WPF ProjectFactory
			// Generic WPF project
			// Our project factory
			oElement:InnerText := "{5ADB76EC-7017-476A-A8E0-25D4202FFCF0};{60DC8134-EBA5-43B8-BCC9-BB4BC16C2548};{AA6C8D78-22FF-423A-9C7C-5F2393824E04}"
		CASE "projectreference"
			// update extension in project references
			oAttribute := (XmlAttribute) oElement:Attributes:GetNamedItem("Include")
			IF oAttribute != NULL
				oAttribute:Value := oAttribute:Value:Replace(".vnproj", "."+EXTENSION)
			ENDIF
		CASE "propertygroup"
			// Only insert code inside the first propertygroup
			IF ++nGroup == 1
				LOCAL oImport AS XmlNode
				// Add Import
				oImport := oDoc:CreateElement("Import",cSchema)
				oAttribute := oDoc:CreateAttribute("Project")
				oAttribute:Value := "$(MSBuildExtensionsPath)\XSharp\XSharp.Default.props"
				oImport:Attributes:Append(oAttribute)
				oParent:InsertBefore(oImport, oElement)
				// Add propertygroup before Import with Label="Globals" and child <XSharpProjectExtensionsPath>
				oChild := oDoc:CreateElement( "PlatformTarget", cSchema)
				oChild:InnerText := "x86"
				oElement:InsertBefore(oChild,oElement:FirstChild)
				oChild := oDoc:CreateElement( "Dialect", cSchema)
				oChild:InnerText := "Vulcan"
				oElement:InsertBefore(oChild,oElement:FirstChild)
			ELSE
				// ALl other project groups.
				// Adjust the condition when needed
				VAR oCondition := (XMLAttribute) oElement:Attributes:GetNamedItem("Condition")
				// <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'" Label="Configuration">
				IF oCondition != NULL
					VAR  cInnerText := oCondition:InnerText
					IF ! cInnerText:ToLower():Contains("platform")
						IF cInnerText:ToLower():Contains("release")
							oCondition:InnerText := "'$(Configuration)|$(Platform)' == 'Release|AnyCPU'"
						ELSE
							oCondition:InnerText := "'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'"
						ENDIF
					ENDIF
				ENDIF
			ENDIF
		CASE "projectextensions"
			// add <ProjectCapabilities><ProjectConfigurationsDeclaredAsItems /></ProjectCapabilities>
			oChild := oDoc:CreateElement("ProjectCapabilities",cSchema)
			oChild:AppendChild(oDoc:CreateElement("ProjectConfigurationsDeclaredAsItems",cSchema))
			oElement:AppendChild(oChild)
			lHasProjectExtensions := TRUE
		CASE "reference"
			// Add RT assemblies after 1st reference
            VAR cAttribute := oElement:GetAttribute("Include")
            IF cAttribute != NULL .and. SELF:lUseXsRuntime
                SWITCH cAttribute:Tolower()
                CASE "vulcanvowin32apilibrary"
                CASE "vulcanvosystemclasses"
                CASE "vulcanvorddclasses"
                CASE "vulcanvosqlclasses"
                CASE "vulcanvoguiclasses"
                CASE "vulcanvointernetclasses"
                CASE "vulcanvoconsoleclasses"
                    cAttribute := cAttribute:Substring(6)
                    oElement:SetAttribute("Include", cAttribute)
                    // remove all version info in the children of the oElement
                    DO WHILE oElement:FirstChild != NULL
                        oElement:RemoveChild(oElement:FirstChild)
                    ENDDO
                    SELF:AddReferenceSubNodes(oElement, cAttribute)
                OTHERWISE
                    NOP
                END SWITCH
            ENDIF
			IF !SELF:lRuntimeAdded
                LOCAL cRt1, cRt2 AS STRING
                IF SELF:lUseXsRuntime
                    cRT1 := "XSharp.Core"
                    cRT2 := "XSharp.VO"
                ELSE
                    cRT1 := "VulcanRT"
                    cRT2 := "VulcanRTFuncs"
                ENDIF
                SELF:AddReference(oElement, cRT1)
                SELF:AddReference(oElement, cRT2)
				SELF:lRuntimeAdded := TRUE
			ENDIF
		OTHERWISE
			// All other elements should not be changed
			NOP
		END SWITCH
	ENDIF
	RETURN

METHOD AddReference(oElement AS XMLNode, cReference AS STRING) AS VOID
    VAR oChild := oDoc:CreateElement("Reference",cSchema)
    oElement:ParentNode:AppendChild(oChild)
	VAR oAttribute := oDoc:CreateAttribute("Include")
	oAttribute:Value := cReference
	oChild:Attributes:Append(oAttribute)
    SELF:AddReferenceSubNodes(oChild, cReference)

METHOD AddReferenceSubNodes(oRef AS XmlNode, cReference AS STRING) AS VOID
    VAR oSub := oDoc:CreateElement("Name",cSchema)
    oSub:InnerText := cReference
    oRef:AppendChild(oSub)
    oSub := oDoc:CreateElement("AssemblyName",cSchema)
    oSub:InnerText := cReference+".DLL"
    oRef:AppendChild(oSub)
	RETURN
METHOD WalkNode(oNode AS XmlNode) AS VOID
	LOCAL aChildren AS List<XmlNode>
	aChildren := List<XmlNode>{}
	FOREACH oChild AS XmlNode IN oNode:ChildNodes
		aChildren:Add(oChild)
	NEXT
	FOREACH oChild AS XmlNode IN aChildren
		IF oChild IS XmlElement
			SELF:UpdateNode(oNode, (XmlElement) oChild)
		ENDIF
		SELF:WalkNode((XMlNode) oChild)
	NEXT
	RETURN

    PROTECT METHOD _LoadFileFromReader(oReader AS System.IO.TextReader) AS LOGIC STRICT
        LOCAL lOk AS LOGIC
        TRY
            oDoc := System.Xml.XmlDocument{}
            oDoc:Load(oReader)
            lOk := TRUE
        CATCH
            lOk := FALSE
        END TRY
        RETURN lOk

   METHOD LoadFile(strFileName AS STRING) AS LOGIC STRICT
        LOCAL lResult := FALSE AS LOGIC
        IF System.IO.File.Exists(strFileName)
            LOCAL oReader AS System.IO.TextReader
            oReader := System.IO.StreamReader{strFileName,TRUE}
            lResult := SELF:_LoadFileFromReader(oReader)
            oReader:Close()
        ENDIF
        RETURN lResult

   METHOD LoadFileFromString(strXMLString AS STRING) AS LOGIC STRICT
        LOCAL lResult AS LOGIC
        LOCAL oReader AS System.IO.StringReader
        oReader := System.IO.StringReader{strXMLString}
        lResult := SELF:_LoadFileFromReader(oReader)
        oReader:Close()
        RETURN lResult

	STATIC PROTECT aRename AS Dictionary<STRING, STRING>
	STATIC PROTECT aDelete AS List<STRING>
	STATIC CONSTRUCTOR()
		aRename := Dictionary<STRING, STRING> {StringComparer.CurrentCultureIgnoreCase}
		aRename:Add("ZeroBasedArrays","AZ")
		aRename:Add("CaseSensitiveIdentifiers","CS")
		aRename:Add("CheckFloatOverflows","FOVF")
		aRename:Add("ImplicitNamespaceLookup","INS")
		aRename:Add("AllowLateBinding","LB")
		aRename:Add("UseDefaultNamespace","NS")
		aRename:Add("CheckForOverflowUnderflow","OVF")
		aRename:Add("GeneratePreprocessorOutput","PPO")
		aRename:Add("AllowUnsafeCode","UnSafe")
		aRename:Add("VOCompatibleStringInit","VO2")
		aRename:Add("AllMethodsVirtual","VO3")
		aRename:Add("ImplicitSignConversions","VO4")
		aRename:Add("VOCompatibleCallingConventions","VO5")
		aRename:Add("VOResolveFunctionPointers","VO6")
		aRename:Add("VOCompatibleImplicitConversions","VO7")
		aRename:Add("VOCompatiblePreprocessor","VO8")
		aRename:Add("VOCompatibleImplicitRetvals","VO9")
		aRename:Add("VOCompatibleIIF","VO10")
		aRename:Add("VOCompatibleArithmeticConversions","VO11")
		aRename:Add("IntegerDivisionsReturnFloat","VO12")
		aRename:Add("VOCompatibleStringComparisons","VO13")
		aRename:Add("VOFloatLiterals","VO14")
		aRename:Add("AdditionalOptions","CommandLineOption")
		// Items to delete

		VAR aTemp := List<STRING>{}
		aTemp:Add("DisabledWarnings")
		aTemp:Add("ProjectName")
		aTemp:Add("ProjectExt")
		aTemp:Add("ProjectDir")
		aTemp:Add("ProjectFileName")
		aTemp:Add("ProjectPath")
		aTemp:Add("ProjectView")
		aTemp:Add("SchemaVersion")
		aDelete := List<STRING>{}
		FOREACH s AS STRING IN aTemp
			aDelete:Add(s:ToLower())
		NEXT

	RETURN

STATIC METHOD Convert(cFile AS STRING, oProgress AS IProgress, lUseXsRt AS LOGIC) AS VOID
	LOCAL oConverter AS ProjectConverter
	LOCAL cSource AS STRING
	LOCAL cTarget AS STRING
	oConverter := ProjectConverter{oProgress,lUseXsRT}
	cSource := cFile
	cTarget := System.IO.Path.ChangeExtension(cSource, EXTENSION)
	IF oConverter:ConvertProjectFile(cSource, cTarget,lUseXsRt)
		oProgress:WriteLine( "Converted "+System.IO.Path.GetFileName(cSource)+" to " +System.IO.Path.GetFileName(cTarget))
	ELSE
		oProgress:WriteLine( "An error occurred")
	ENDIF
	RETURN

END CLASS


[Runtime] Prevent *EmptyCallStack* from appearing before a non empty callstack

//
// 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
USING System.Collections.Generic
USING System.Text
USING System.Reflection
USING System.Diagnostics
BEGIN NAMESPACE XSharp
  /// XSharp Runtime base Error class
  CLASS Error INHERIT Exception
    /// A string representing the name of the subsystem generating the error.
    VIRTUAL PROPERTY SubSystem AS STRING AUTO  := "BASE"
    /// An integer numeric value representing a Visual Objects generic error code.
    /// <Seealso cref="T:XSharp.Gencode"/>
    VIRTUAL PROPERTY Gencode AS DWORD AUTO    := EG_UNKNOWN
    /// An string containing the description of the Gencode.
    VIRTUAL PROPERTY GenCodeText AS STRING GET IIF (Gencode != 0, ErrString(Gencode), "Unknown GenCode")
    /// An integer numeric value representing a subsystem-specific error code.
    VIRTUAL PROPERTY SubCode AS DWORD AUTO    := 0
    /// An string containing the description of the SubCode.
    VIRTUAL PROPERTY SubCodeText AS STRING GET IIF(!String.IsNullOrEmpty(_Subcode), _Subcode, IIF (SubCode != 0, __CavoStr(SubCode), "Unknown SubCode")) SET _Subcode := value
    PRIVATE _Subcode as STRING
    /// A string representing the name of the function or method in which the error occurred.
    VIRTUAL PROPERTY FuncSym AS STRING AUTO   := ""
    /// A string representing the name used to open the file associated with the error condition.
    VIRTUAL PROPERTY FileName AS STRING AUTO  := ""
    /// A constant indicating the severity of the error condition.
    /// <Seealso cref="T:XSharp.Severity"/>
    VIRTUAL PROPERTY Severity AS DWORD AUTO   := ES_ERROR
    /// A string that describes the error condition.
    VIRTUAL PROPERTY Description		AS STRING AUTO := ""
    /// A string representing the argument supplied to an operator or function when an argument error occurs.
    VIRTUAL PROPERTY Arg				AS STRING AUTO := ""
    PRIVATE  _ArgType			AS DWORD
    /// A numeric value representing the data type of the argument that raised the error.
    VIRTUAL 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.
    VIRTUAL 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.
    VIRTUAL 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.
    VIRTUAL 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.
    VIRTUAL 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.
    VIRTUAL PROPERTY ArgNum				AS DWORD AUTO
    /// An object representing the SELF of the method in which the error occurred.
    VIRTUAL PROPERTY MethodSelf			AS OBJECT AUTO
    /// A symbol representing the calling function of the function in which the error occurred.
    VIRTUAL PROPERTY CallFuncSym		AS STRING AUTO
    /// An array of the arguments supplied to an operator or function when an argument error occurs.
    VIRTUAL PROPERTY Args				AS OBJECT[] AUTO
    /// An integer numeric value representing the number of times the failed operation has been attempted.
    VIRTUAL PROPERTY Tries				AS INT AUTO := 0
    /// A logical value indicating whether the subsystem can perform default error recovery for the error condition.
    VIRTUAL PROPERTY CanDefault         AS LOGIC AUTO
    /// A logical value indicating whether the subsystem can retry the operation that caused the error condition.
    VIRTUAL PROPERTY CanRetry           AS LOGIC AUTO
    /// A logical value indicating whether a new result can be substituted for the operation that produced the error condition.
    VIRTUAL PROPERTY CanSubstitute      AS LOGIC AUTO
    /// A string that describes the operation being attempted when the error occurred.
    VIRTUAL 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
    VIRTUAL PROPERTY OSCode				AS DWORD AUTO := 0
    /// Descripion of the OSCode
    VIRTUAL 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.
    VIRTUAL PROPERTY FileHandle         AS DWORD AUTO
    /// A numeric value representing a boundary condition for an operation (such as string overflow or array bound error).
    VIRTUAL 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>
    VIRTUAL 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
    VIRTUAL PROPERTY Cargo              AS OBJECT AUTO
    /// Call stack from the moment where the error object was created
    VIRTUAL PROPERTY Stack              AS STRING GET SELF:StackTrace SET SELF:StackTrace := Value

	PRIVATE _StackTrace AS STRING
    VIRTUAL PROPERTY StackTrace         AS STRING
    	GET
    		IF String.IsNullOrEmpty(SELF:_StackTrace)
    			RETURN SUPER:StackTrace
    		END IF
    		RETURN SELF:_StackTrace
    	END GET
    	SET
    		SELF:_StackTrace := value
    	END SET
    END PROPERTY

    PRIVATE METHOD setDefaultValues() AS VOID
        SELF:FuncSym := ProcName(2)
        SELF:Args    := <OBJECT>{}
        IF String.IsNullOrEmpty(SELF:StackTrace)
            SELF:_StackTrace  := ErrorStack(2)
        ENDIF
        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
        VAR sStack       := ErrorStack( StackTrace{ex,TRUE})
        IF !sStack:StartsWith("*EmptyCallStack*")
            SELF:_StackTrace := sStack + SELF:_StackTrace
        ENDIF
    ENDIF
    IF String.IsNullOrEmpty(SELF:StackTrace)
        SELF:StackTrace  := ErrorStack(2)
    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
    SELF:Description := ErrString( dwGenCode )

    /// 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
    SELF:Description := ErrString( dwGenCode )

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

    PRIVATE METHOD LangString(e as VOErrors) AS STRING
        local cString := __CavoStr(e):Trim() as string
        IF cString:EndsWith(":")
            cString := cString:Substring(0, cString:Length-1):Trim()
        endif
        return cString+e" :\t"

    /// <inheritdoc />
    OVERRIDE METHOD ToString() AS STRING
      LOCAL sb AS StringBuilder
      LOCAL nGenCode AS Gencode
      nGenCode := (Gencode) SELF:Gencode
      sb := StringBuilder{}

      sb:AppendLine( LangString(VOErrors.ERROR_DESCRIPTION) + SELF:Description)
      sb:AppendLine( LangString(VOErrors.ERROR_SUBSYSTEM) + SELF:SubSystem )
      sb:AppendLine( LangString(VOErrors.ERROR_GENCODE) + nGenCode:ToString()  +" " +SELF:GenCodeText  )
      IF SELF:SubCode != 0
        sb:AppendLine( LangString(VOErrors.ERROR_SUBCODE) + SELF:SubCode:ToString() +" "+SELF:SubCodeText)
      ENDIF
      IF SELF:OSCode != 0
        sb:AppendLine( LangString(VOErrors.ERROR_OSCODE)  + SELF:OSCode:ToString() +" " +SELF:OSCodeText )
      ENDIF
      IF !String.IsNullOrEmpty(SELF:FuncSym)
        sb:AppendLine(LangString(VOErrors.ERROR_FUNCSYM) + SELF:FuncSym   )
      ENDIF
      LOCAL sev := (Severity) SELF:Severity AS Severity
      sb:AppendLine(LangString(VOErrors.ERROR_SEVERITY)     + sev:ToString() )
      sb:AppendLine(LangString(VOErrors.ERROR_CANDEFAULT)   + SELF:CanDefault:ToString())
      sb:AppendLine(LangString(VOErrors.ERROR_CANRETRY)     +SELF:CanRetry:ToString() )
      sb:AppendLine(LangString(VOErrors.ERROR_CANSUBSTITUTE) +SELF:CanSubstitute:ToString())
      IF ! String.IsNullOrEmpty(SELF:Operation)
        sb:AppendLine(LangString(VOErrors.ERROR_OPERATION) + SELF:Operation)
      ENDIF
      IF ! String.IsNullOrEmpty(SELF:FileName)
        sb:AppendLine(LangString(VOErrors.ERROR_FILENAME) + SELF:FileName )
      ENDIF
      IF SELF:Tries != 0
          sb:AppendLine(LangString(VOErrors.ERROR_TRIES) + SELF:Tries:ToString()    )
     ENDIF
      IF SELF:ArgType != 0
        sb:AppendLine(LangString(VOErrors.ERROR_ARGTYPE) 	+ TypeString(SELF:ArgType    ) )
      ENDIF
      IF SELF:ArgNum != 0
        sb:AppendLine(LangString(VOErrors.ERROR_ARGNUM) 	+ SELF:ArgNum:ToString()    )
      ENDIF
      IF ! String.IsNullOrEmpty(SELF:Arg)
        sb:AppendLine(LangString(VOErrors.ERROR_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(LangString(VOErrors.ERROR_ARGS)+ cArgs)
      ENDIF
      IF SELF:ArgTypeReqType != NULL
        sb:AppendLine(LangString(VOErrors.ERROR_ARGTYPE_REQ) + SELF:ArgTypeReqType:FullName)
      ENDIF
      IF ! String.IsNullOrEmpty(SELF:CallFuncSym)
        sb:AppendLine(LangString(VOErrors.ERROR_CALLEDFROM) + SELF:CallFuncSym  )
      ENDIF
      sb:AppendLine(LangString(VOErrors.ERROR_STACK))
      sb:AppendLine(SELF:StackTrace  )
      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{XSharp.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{XSharp.Gencode.EG_ARG, name, description}
    err:FuncSym     := cFuncName
    err:Description := err:Message
    err:ArgNum		:= iArgnum
    RETURN err

    STATIC METHOD ArgumentError(cFuncName AS STRING, name AS STRING, description AS STRING, iArgnum AS DWORD, aArgs AS OBJECT[]) AS Error
        VAR err := ArgumentError(cFuncName, name, description, iArgnum)
        err:Args := aArgs
    RETURN err

    /// <exclude/>
    STATIC METHOD WrapRawException( ex AS Exception ) AS Error
    LOCAL e AS Error
    if ex != null
        e			  := Error{ ex }
        e:Description := ErrString( EG_EXCEPTION ) + ":" + ex:Message
    else
        e			  := Error{  }
        e:Description := ErrString( EG_SEQUENCE ) + ":" + ex:Message
    endif
    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
        e:Description := ErrString( dwGenCode )
        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.__currency"
          RETURN __UsualType.Currency
        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.Currency
      typeName := "XSharp.__Currency"
    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

END NAMESPACE

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/errorbuild/*" />
FUNCTION ErrorBuild(pErrInfo AS Exception) AS XSharp.Error
	RETURN  XSharp.Error{pErrInfo}

//
// 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
USING System.Collections.Generic
USING System.Text
USING System.Reflection
USING System.Diagnostics
BEGIN NAMESPACE XSharp
  /// XSharp Runtime base Error class
  CLASS Error INHERIT Exception
    /// A string representing the name of the subsystem generating the error.
    VIRTUAL PROPERTY SubSystem AS STRING AUTO  := "BASE"
    /// An integer numeric value representing a Visual Objects generic error code.
    /// <Seealso cref="T:XSharp.Gencode"/>
    VIRTUAL PROPERTY Gencode AS DWORD AUTO    := EG_UNKNOWN
    /// An string containing the description of the Gencode.
    VIRTUAL PROPERTY GenCodeText AS STRING GET IIF (Gencode != 0, ErrString(Gencode), "Unknown GenCode")
    /// An integer numeric value representing a subsystem-specific error code.
    VIRTUAL PROPERTY SubCode AS DWORD AUTO    := 0
    /// An string containing the description of the SubCode.
    VIRTUAL PROPERTY SubCodeText AS STRING GET IIF(!String.IsNullOrEmpty(_Subcode), _Subcode, IIF (SubCode != 0, __CavoStr(SubCode), "Unknown SubCode")) SET _Subcode := value
    PRIVATE _Subcode as STRING
    /// A string representing the name of the function or method in which the error occurred.
    VIRTUAL PROPERTY FuncSym AS STRING AUTO   := ""
    /// A string representing the name used to open the file associated with the error condition.
    VIRTUAL PROPERTY FileName AS STRING AUTO  := ""
    /// A constant indicating the severity of the error condition.
    /// <Seealso cref="T:XSharp.Severity"/>
    VIRTUAL PROPERTY Severity AS DWORD AUTO   := ES_ERROR
    /// A string that describes the error condition.
    VIRTUAL PROPERTY Description		AS STRING AUTO := ""
    /// A string representing the argument supplied to an operator or function when an argument error occurs.
    VIRTUAL PROPERTY Arg				AS STRING AUTO := ""
    PRIVATE  _ArgType			AS DWORD
    /// A numeric value representing the data type of the argument that raised the error.
    VIRTUAL 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.
    VIRTUAL 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.
    VIRTUAL 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.
    VIRTUAL 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.
    VIRTUAL 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.
    VIRTUAL PROPERTY ArgNum				AS DWORD AUTO
    /// An object representing the SELF of the method in which the error occurred.
    VIRTUAL PROPERTY MethodSelf			AS OBJECT AUTO
    /// A symbol representing the calling function of the function in which the error occurred.
    VIRTUAL PROPERTY CallFuncSym		AS STRING AUTO
    /// An array of the arguments supplied to an operator or function when an argument error occurs.
    VIRTUAL PROPERTY Args				AS OBJECT[] AUTO
    /// An integer numeric value representing the number of times the failed operation has been attempted.
    VIRTUAL PROPERTY Tries				AS INT AUTO := 0
    /// A logical value indicating whether the subsystem can perform default error recovery for the error condition.
    VIRTUAL PROPERTY CanDefault         AS LOGIC AUTO
    /// A logical value indicating whether the subsystem can retry the operation that caused the error condition.
    VIRTUAL PROPERTY CanRetry           AS LOGIC AUTO
    /// A logical value indicating whether a new result can be substituted for the operation that produced the error condition.
    VIRTUAL PROPERTY CanSubstitute      AS LOGIC AUTO
    /// A string that describes the operation being attempted when the error occurred.
    VIRTUAL 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
    VIRTUAL PROPERTY OSCode				AS DWORD AUTO := 0
    /// Descripion of the OSCode
    VIRTUAL 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.
    VIRTUAL PROPERTY FileHandle         AS DWORD AUTO
    /// A numeric value representing a boundary condition for an operation (such as string overflow or array bound error).
    VIRTUAL 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>
    VIRTUAL 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
    VIRTUAL PROPERTY Cargo              AS OBJECT AUTO
    /// Call stack from the moment where the error object was created
    VIRTUAL PROPERTY Stack              AS STRING GET SELF:StackTrace SET SELF:StackTrace := Value

	PRIVATE _StackTrace AS STRING
    VIRTUAL PROPERTY StackTrace         AS STRING
    	GET
    		IF String.IsNullOrEmpty(SELF:_StackTrace)
    			RETURN SUPER:StackTrace
    		END IF
    		RETURN SELF:_StackTrace
    	END GET
    	SET
    		SELF:_StackTrace := value
    	END SET
    END PROPERTY

    PRIVATE METHOD setDefaultValues() AS VOID
        SELF:FuncSym := ProcName(2)
        SELF:Args    := <OBJECT>{}
        IF String.IsNullOrEmpty(SELF:StackTrace)
            SELF:_StackTrace  := ErrorStack(2)
        ENDIF
        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
        SELF:_StackTrace := ErrorStack( StackTrace{ex,TRUE}) + SELF:_StackTrace
    ENDIF
    IF String.IsNullOrEmpty(SELF:StackTrace)
        SELF:StackTrace  := ErrorStack(2)
    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
    SELF:Description := ErrString( dwGenCode )

    /// 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
    SELF:Description := ErrString( dwGenCode )

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

    PRIVATE METHOD LangString(e as VOErrors) AS STRING
        local cString := __CavoStr(e):Trim() as string
        IF cString:EndsWith(":")
            cString := cString:Substring(0, cString:Length-1):Trim()
        endif
        return cString+e" :\t"

    /// <inheritdoc />
    OVERRIDE METHOD ToString() AS STRING
      LOCAL sb AS StringBuilder
      LOCAL nGenCode AS Gencode
      nGenCode := (Gencode) SELF:Gencode
      sb := StringBuilder{}

      sb:AppendLine( LangString(VOErrors.ERROR_DESCRIPTION) + SELF:Description)
      sb:AppendLine( LangString(VOErrors.ERROR_SUBSYSTEM) + SELF:SubSystem )
      sb:AppendLine( LangString(VOErrors.ERROR_GENCODE) + nGenCode:ToString()  +" " +SELF:GenCodeText  )
      IF SELF:SubCode != 0
        sb:AppendLine( LangString(VOErrors.ERROR_SUBCODE) + SELF:SubCode:ToString() +" "+SELF:SubCodeText)
      ENDIF
      IF SELF:OSCode != 0
        sb:AppendLine( LangString(VOErrors.ERROR_OSCODE)  + SELF:OSCode:ToString() +" " +SELF:OSCodeText )
      ENDIF
      IF !String.IsNullOrEmpty(SELF:FuncSym)
        sb:AppendLine(LangString(VOErrors.ERROR_FUNCSYM) + SELF:FuncSym   )
      ENDIF
      LOCAL sev := (Severity) SELF:Severity AS Severity
      sb:AppendLine(LangString(VOErrors.ERROR_SEVERITY)     + sev:ToString() )
      sb:AppendLine(LangString(VOErrors.ERROR_CANDEFAULT)   + SELF:CanDefault:ToString())
      sb:AppendLine(LangString(VOErrors.ERROR_CANRETRY)     +SELF:CanRetry:ToString() )
      sb:AppendLine(LangString(VOErrors.ERROR_CANSUBSTITUTE) +SELF:CanSubstitute:ToString())
      IF ! String.IsNullOrEmpty(SELF:Operation)
        sb:AppendLine(LangString(VOErrors.ERROR_OPERATION) + SELF:Operation)
      ENDIF
      IF ! String.IsNullOrEmpty(SELF:FileName)
        sb:AppendLine(LangString(VOErrors.ERROR_FILENAME) + SELF:FileName )
      ENDIF
      IF SELF:Tries != 0
          sb:AppendLine(LangString(VOErrors.ERROR_TRIES) + SELF:Tries:ToString()    )
     ENDIF
      IF SELF:ArgType != 0
        sb:AppendLine(LangString(VOErrors.ERROR_ARGTYPE) 	+ TypeString(SELF:ArgType    ) )
      ENDIF
      IF SELF:ArgNum != 0
        sb:AppendLine(LangString(VOErrors.ERROR_ARGNUM) 	+ SELF:ArgNum:ToString()    )
      ENDIF
      IF ! String.IsNullOrEmpty(SELF:Arg)
        sb:AppendLine(LangString(VOErrors.ERROR_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(LangString(VOErrors.ERROR_ARGS)+ cArgs)
      ENDIF
      IF SELF:ArgTypeReqType != NULL
        sb:AppendLine(LangString(VOErrors.ERROR_ARGTYPE_REQ) + SELF:ArgTypeReqType:FullName)
      ENDIF
      IF ! String.IsNullOrEmpty(SELF:CallFuncSym)
        sb:AppendLine(LangString(VOErrors.ERROR_CALLEDFROM) + SELF:CallFuncSym  )
      ENDIF
      sb:AppendLine(LangString(VOErrors.ERROR_STACK))
      sb:AppendLine(SELF:StackTrace  )
      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{XSharp.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{XSharp.Gencode.EG_ARG, name, description}
    err:FuncSym     := cFuncName
    err:Description := err:Message
    err:ArgNum		:= iArgnum
    RETURN err

    STATIC METHOD ArgumentError(cFuncName AS STRING, name AS STRING, description AS STRING, iArgnum AS DWORD, aArgs AS OBJECT[]) AS Error
        VAR err := ArgumentError(cFuncName, name, description, iArgnum)
        err:Args := aArgs
    RETURN err

    /// <exclude/>
    STATIC METHOD WrapRawException( ex AS Exception ) AS Error
    LOCAL e AS Error
    if ex != null
        e			  := Error{ ex }
        e:Description := ErrString( EG_EXCEPTION ) + ":" + ex:Message
    else
        e			  := Error{  }
        e:Description := ErrString( EG_SEQUENCE ) + ":" + ex:Message
    endif
    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
        e:Description := ErrString( dwGenCode )
        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.__currency"
          RETURN __UsualType.Currency
        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.Currency
      typeName := "XSharp.__Currency"
    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

END NAMESPACE

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/errorbuild/*" />
FUNCTION ErrorBuild(pErrInfo AS Exception) AS XSharp.Error
	RETURN  XSharp.Error{pErrInfo}


[Runtime] Added some goniometric functions

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

/// <summary>
/// </summary>
/// <param name="f"></param>
/// <returns>
/// </returns>
FUNCTION Float2Long(f AS USUAL) AS LONG
    LOCAL flValue AS FLOAT
    flValue := (FLOAT) f
    RETURN (LONG) flValue

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/abs/*" />
FUNCTION Abs(nValue AS USUAL) AS USUAL
    LOCAL uRet AS USUAL
    IF nValue:IsInt64
        uRet := Math.Abs( (INT64) nValue )
    ELSEIF nValue:IsDecimal
        uRet := Math.Abs( (Decimal) nValue)
    ELSEIF nValue:isInteger
        uRet := Math.Abs( (INT) nValue )
    ELSEIF nValue:IsFLoat
        uRet := AbsFloat( nValue )
    ELSE
        THROW  Error.ArgumentError( __ENTITY__, NAMEOF(nValue), "Argument not numeric",1)
    ENDIF
    RETURN uRet

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acot/*" />
FUNCTION ACot(nNum AS USUAL) AS FLOAT
    RETURN 2 * Math.ATan(1) + Math.ATan( (REAL8) nNum)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/atan/*" />
FUNCTION ATan(nNum AS USUAL) AS FLOAT
    RETURN Math.ATan((REAL8)nNum)

FUNCTION ACos(nNum AS USUAL) AS FLOAT
    RETURN Math.Acos((REAL8) nNum)

FUNCTION ASin(nNum AS USUAL) AS FLOAT
    RETURN Math.ASin((REAL8) nNum)

FUNCTION Atan2(nY as USUAL, nX AS USUAL) AS FLOAT
    RETURN Math.Atan2((REAL8) nY, (REAL8) nX)

FUNCTION DToR(nDegrees as USUAL) AS REAL8
    RETURN (Real8) nDegrees / 360 * Math.PI

FUNCTION RToD(nRadian as USUAL) AS REAL8
    RETURN ((REAL8) nRadian / Math.PI) * 360.0

FUNCTION PI() AS REAL8
    RETURN Math.PI

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ceil/*" />
FUNCTION Ceil(nNumber AS USUAL) AS USUAL
    LOCAL result AS USUAL
    IF nNumber:IsInteger
        result := nNumber
    ELSEIF nNumber:IsDecimal
        LOCAL d AS decimal
        d := (decimal) nNumber
        d := Math.Ceiling(d)
        IF d <= int32.MaxValue .AND. d >= int32.MinValue
            result := COnvert.ToInt32(d)
        ELSEIF d <= int64.MaxValue .AND. d >= int64.MinValue
            result := COnvert.ToInt64(d)
        ELSE
            result := d
        ENDIF

    ELSEIF nNumber:IsFloat
        LOCAL r8 AS REAL8
        r8 := (FLOAT) nNumber
        r8 := Math.Ceiling(r8)
        IF r8 <= int32.MaxValue .AND. r8 >= int32.MinValue
            result := COnvert.ToInt32(r8)
        ELSEIF r8 <= int64.MaxValue .AND. r8 >= int64.MinValue
            result := COnvert.ToInt64(r8)
        ELSE
            result := r8
        ENDIF
    ELSE
        THROW  Error.ArgumentError( __ENTITY__, NAMEOF(nNumber), "Argument not numeric",1)
    ENDIF
    RETURN result

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/cos/*" />
FUNCTION Cos(nNum AS USUAL) AS FLOAT
    RETURN Math.Cos((REAL8)nNum)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/cot/*" />
FUNCTION Cot(nNum AS USUAL) AS FLOAT
    RETURN 2 * Math.ATan( 1 ) + Math.ATan( (REAL8)nNum)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/exp/*" />
FUNCTION Exp(nExponent AS USUAL) AS FLOAT
    RETURN Math.Exp((REAL8)nExponent)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/floor/*" />
FUNCTION Floor(nNum AS USUAL) AS USUAL
    LOCAL result AS USUAL
    IF nNum:IsInteger
        result := nNum
    ELSEIF nNum:IsDecimal
        LOCAL d AS decimal
        d := (decimal) nNum
        d := Math.Floor(d)
        IF d <= int32.MaxValue .AND. d >= int32.MinValue
            result := COnvert.ToInt32(d)
        ELSEIF d <= int64.MaxValue .AND. d >= int64.MinValue
            result := COnvert.ToInt64(d)
        ELSE
            result := d
        ENDIF

    ELSEIF nNum:IsFloat
        LOCAL r8 AS REAL8
        r8 := (FLOAT) nNum
        r8 := Math.Floor(r8)
        IF r8 <= int32.MaxValue .AND. r8 >= int32.MinValue
            result := COnvert.ToInt32(r8)
        ELSEIF r8 <= int64.MaxValue .AND. r8 >= int64.MinValue
            result := COnvert.ToInt64(r8)
        ELSE
            result := r8
        ENDIF
    ELSE
        THROW  Error.ArgumentError( __ENTITY__, NAMEOF(nNum), "Argument not numeric",1)
    ENDIF
    RETURN result

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/integer/*" />
FUNCTION Integer(nValue AS USUAL) AS USUAL
    LOCAL result AS USUAL
    IF nValue:IsInteger
        result := nValue
    ELSEIF nValue:IsFloat .OR. nValue:IsDecimal
        IF nValue > 0.0
            result := Floor(nValue)
        ELSE
            result := Ceil(nValue)
        ENDIF
    ELSE
        THROW Error.ArgumentError( __ENTITY__, NAMEOF(nValue), "Argument not numeric",1)
    ENDIF
    RETURN result

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/log/*" />
FUNCTION LOG(nValue AS USUAL) AS FLOAT
    RETURN Math.Log((REAL8)nValue)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/log10/*" />
FUNCTION Log10(nValue AS USUAL) AS FLOAT
    RETURN Math.Log10((REAL8)nValue)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/pow/*" />
FUNCTION Pow(nBase AS USUAL,nExponent AS USUAL) AS FLOAT
    RETURN Math.Pow((REAL8)nBase, (REAL8)nExponent)

INTERNAL GLOBAL _randomGenerator AS Random
/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rand/*" />
FUNCTION Rand(nSeed AS USUAL) AS FLOAT
    IF !nSeed:IsNumeric .OR. nSeed <= 0
        nSeed := (INT) DateTime.Now:Ticks
    ENDIF
    _randomGenerator := Random{ nSeed }
    RETURN _randomGenerator:NextDouble()
/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rand/*" />
FUNCTION Rand() AS FLOAT
    IF _randomGenerator == NULL
        _randomGenerator := Random{ 100001 }
    ENDIF
    RETURN _randomGenerator:NextDouble()

    #define MAX_DECIMALS 15
/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/round/*" />
FUNCTION Round(nNumber AS USUAL,siDecimals AS INT) AS USUAL
    LOCAL ret    AS USUAL
    LOCAL IsLong   AS LOGIC
    LOCAL IsInt64  AS LOGIC
    LOCAL r8     AS REAL8

    IF ! nNumber:IsNumeric
        THROW Error.ArgumentError( __ENTITY__, NAMEOF(nNumber), "Argument is not numeric")
    ENDIF

    // For Integers we could round the numbers
    // Round(12345, -1) -> 12350
    IsInt64 := nNumber:IsInt64
    IsLong  := nNumber:IsLong
    r8  := nNumber

    IF siDecimals > 0
        // Round after decimal point
        IF siDecimals > MAX_DECIMALS
            siDecimals := MAX_DECIMALS
        ENDIF

        r8 := (REAL8) Math.Round( (System.Decimal) r8, siDecimals, MidpointRounding.AwayFromZero )
    ELSE
        // Round before decimal point
        siDecimals := -siDecimals

        IF siDecimals > MAX_DECIMALS
            siDecimals := MAX_DECIMALS
        ENDIF

        r8 := r8 / ( 10 ^ siDecimals )
        r8 := Math.Round( r8, 0, MidpointRounding.AwayFromZero )
        r8 := r8 * ( 10 ^ siDecimals )

        IF r8 < 0
            isLong	:= r8 >= Int32.MinValue
            isInt64 := r8 >= Int64.MinValue
        ELSE
            isLong  := r8 <= Int32.MaxValue
            isInt64 := r8 <= Int64.MaxValue
        ENDIF
        siDecimals := 0
    ENDIF

    IF isLong .OR. IsInt64
        siDecimals := 0
    ENDIF

    IF siDecimals == 0
        IF IsLong
            ret := (INT) r8
        ELSEIF IsInt64
            ret := (INT64) r8
        ELSE
            ret := FLOAT{r8, 0}
        ENDIF
    ELSE
        ret := FLOAT{r8, siDecimals}
    ENDIF

    RETURN ret

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/sin/*" />
FUNCTION Sin(nNum AS USUAL) AS FLOAT
    RETURN Math.Sin((REAL8)nNum)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/sqrt/*" />
FUNCTION SQrt(nNumber AS USUAL) AS FLOAT
    RETURN Math.SQrt((REAL8)nNumber)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/tan/*" />
FUNCTION Tan(nNum AS USUAL) AS FLOAT
    RETURN Math.Tan((REAL8)nNum)

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

/// <summary>
/// </summary>
/// <param name="f"></param>
/// <returns>
/// </returns>
FUNCTION Float2Long(f AS USUAL) AS LONG
    LOCAL flValue AS FLOAT
    flValue := (FLOAT) f
    RETURN (LONG) flValue

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/abs/*" />
FUNCTION Abs(nValue AS USUAL) AS USUAL
    LOCAL uRet AS USUAL
    IF nValue:IsInt64
        uRet := Math.Abs( (INT64) nValue )
    ELSEIF nValue:IsDecimal
        uRet := Math.Abs( (Decimal) nValue)
    ELSEIF nValue:isInteger
        uRet := Math.Abs( (INT) nValue )
    ELSEIF nValue:IsFLoat
        uRet := AbsFloat( nValue )
    ELSE
        THROW  Error.ArgumentError( __ENTITY__, NAMEOF(nValue), "Argument not numeric",1)
    ENDIF
    RETURN uRet

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/acot/*" />
FUNCTION ACot(nNum AS USUAL) AS FLOAT
    RETURN 2 * Math.ATan(1) + Math.ATan( (REAL8) nNum)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/atan/*" />
FUNCTION ATan(nNum AS USUAL) AS FLOAT
    RETURN Math.ATan((REAL8)nNum)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/ceil/*" />
FUNCTION Ceil(nNumber AS USUAL) AS USUAL
    LOCAL result AS USUAL
    IF nNumber:IsInteger
        result := nNumber
    ELSEIF nNumber:IsDecimal
        LOCAL d AS decimal
        d := (decimal) nNumber
        d := Math.Ceiling(d)
        IF d <= int32.MaxValue .AND. d >= int32.MinValue
            result := COnvert.ToInt32(d)
        ELSEIF d <= int64.MaxValue .AND. d >= int64.MinValue
            result := COnvert.ToInt64(d)
        ELSE
            result := d
        ENDIF

    ELSEIF nNumber:IsFloat
        LOCAL r8 AS REAL8
        r8 := (FLOAT) nNumber
        r8 := Math.Ceiling(r8)
        IF r8 <= int32.MaxValue .AND. r8 >= int32.MinValue
            result := COnvert.ToInt32(r8)
        ELSEIF r8 <= int64.MaxValue .AND. r8 >= int64.MinValue
            result := COnvert.ToInt64(r8)
        ELSE
            result := r8
        ENDIF
    ELSE
        THROW  Error.ArgumentError( __ENTITY__, NAMEOF(nNumber), "Argument not numeric",1)
    ENDIF
    RETURN result

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/cos/*" />
FUNCTION Cos(nNum AS USUAL) AS FLOAT
    RETURN Math.Cos((REAL8)nNum)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/cot/*" />
FUNCTION Cot(nNum AS USUAL) AS FLOAT
    RETURN 2 * Math.ATan( 1 ) + Math.ATan( (REAL8)nNum)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/exp/*" />
FUNCTION Exp(nExponent AS USUAL) AS FLOAT
    RETURN Math.Exp((REAL8)nExponent)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/floor/*" />
FUNCTION Floor(nNum AS USUAL) AS USUAL
    LOCAL result AS USUAL
    IF nNum:IsInteger
        result := nNum
    ELSEIF nNum:IsDecimal
        LOCAL d AS decimal
        d := (decimal) nNum
        d := Math.Floor(d)
        IF d <= int32.MaxValue .AND. d >= int32.MinValue
            result := COnvert.ToInt32(d)
        ELSEIF d <= int64.MaxValue .AND. d >= int64.MinValue
            result := COnvert.ToInt64(d)
        ELSE
            result := d
        ENDIF

    ELSEIF nNum:IsFloat
        LOCAL r8 AS REAL8
        r8 := (FLOAT) nNum
        r8 := Math.Floor(r8)
        IF r8 <= int32.MaxValue .AND. r8 >= int32.MinValue
            result := COnvert.ToInt32(r8)
        ELSEIF r8 <= int64.MaxValue .AND. r8 >= int64.MinValue
            result := COnvert.ToInt64(r8)
        ELSE
            result := r8
        ENDIF
    ELSE
        THROW  Error.ArgumentError( __ENTITY__, NAMEOF(nNum), "Argument not numeric",1)
    ENDIF
    RETURN result

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/integer/*" />
FUNCTION Integer(nValue AS USUAL) AS USUAL
    LOCAL result AS USUAL
    IF nValue:IsInteger
        result := nValue
    ELSEIF nValue:IsFloat .OR. nValue:IsDecimal
        IF nValue > 0.0
            result := Floor(nValue)
        ELSE
            result := Ceil(nValue)
        ENDIF
    ELSE
        THROW Error.ArgumentError( __ENTITY__, NAMEOF(nValue), "Argument not numeric",1)
    ENDIF
    RETURN result

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/log/*" />
FUNCTION LOG(nValue AS USUAL) AS FLOAT
    RETURN Math.Log((REAL8)nValue)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/log10/*" />
FUNCTION Log10(nValue AS USUAL) AS FLOAT
    RETURN Math.Log10((REAL8)nValue)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/pow/*" />
FUNCTION Pow(nBase AS USUAL,nExponent AS USUAL) AS FLOAT
    RETURN Math.Pow((REAL8)nBase, (REAL8)nExponent)

INTERNAL GLOBAL _randomGenerator AS Random
/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rand/*" />
FUNCTION Rand(nSeed AS USUAL) AS FLOAT
    IF !nSeed:IsNumeric .OR. nSeed <= 0
        nSeed := (INT) DateTime.Now:Ticks
    ENDIF
    _randomGenerator := Random{ nSeed }
    RETURN _randomGenerator:NextDouble()
/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/rand/*" />
FUNCTION Rand() AS FLOAT
    IF _randomGenerator == NULL
        _randomGenerator := Random{ 100001 }
    ENDIF
    RETURN _randomGenerator:NextDouble()

    #define MAX_DECIMALS 15
/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/round/*" />
FUNCTION Round(nNumber AS USUAL,siDecimals AS INT) AS USUAL
    LOCAL ret    AS USUAL
    LOCAL IsLong   AS LOGIC
    LOCAL IsInt64  AS LOGIC
    LOCAL r8     AS REAL8

    IF ! nNumber:IsNumeric
        THROW Error.ArgumentError( __ENTITY__, NAMEOF(nNumber), "Argument is not numeric")
    ENDIF

    // For Integers we could round the numbers
    // Round(12345, -1) -> 12350
    IsInt64 := nNumber:IsInt64
    IsLong  := nNumber:IsLong
    r8  := nNumber

    IF siDecimals > 0
        // Round after decimal point
        IF siDecimals > MAX_DECIMALS
            siDecimals := MAX_DECIMALS
        ENDIF

        r8 := (REAL8) Math.Round( (System.Decimal) r8, siDecimals, MidpointRounding.AwayFromZero )
    ELSE
        // Round before decimal point
        siDecimals := -siDecimals

        IF siDecimals > MAX_DECIMALS
            siDecimals := MAX_DECIMALS
        ENDIF

        r8 := r8 / ( 10 ^ siDecimals )
        r8 := Math.Round( r8, 0, MidpointRounding.AwayFromZero )
        r8 := r8 * ( 10 ^ siDecimals )

        IF r8 < 0
            isLong	:= r8 >= Int32.MinValue
            isInt64 := r8 >= Int64.MinValue
        ELSE
            isLong  := r8 <= Int32.MaxValue
            isInt64 := r8 <= Int64.MaxValue
        ENDIF
        siDecimals := 0
    ENDIF

    IF isLong .OR. IsInt64
        siDecimals := 0
    ENDIF

    IF siDecimals == 0
        IF IsLong
            ret := (INT) r8
        ELSEIF IsInt64
            ret := (INT64) r8
        ELSE
            ret := FLOAT{r8, 0}
        ENDIF
    ELSE
        ret := FLOAT{r8, siDecimals}
    ENDIF

    RETURN ret

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/sin/*" />
FUNCTION Sin(nNum AS USUAL) AS FLOAT
    RETURN Math.Sin((REAL8)nNum)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/sqrt/*" />
FUNCTION SQrt(nNumber AS USUAL) AS FLOAT
    RETURN Math.SQrt((REAL8)nNumber)

/// <include file="VoFunctionDocs.xml" path="Runtimefunctions/tan/*" />
FUNCTION Tan(nNum AS USUAL) AS FLOAT
    RETURN Math.Tan((REAL8)nNum)