// method that dynamically compiles and instantiates the _Evaluator class
        public void ConstructEvaluator( EquationDefinition[] edEquations, VariableDefinition[] vdVariables, string strDLLFileNameParam )
        {
            // instantiate a C# Code Compiler and a Compiler Parameter to use with it
            //ICodeCompiler CSharpCodeCompiler = (new CSharpCodeProvider().CreateCompiler());
            CodeDomProvider CSharpCodeCompiler = CodeDomProvider.CreateProvider("CSharp");

            CompilerParameters	cpCompilerParameters	= new CompilerParameters();

            // the Parameter object will tell the compiler what DLLs to use
            cpCompilerParameters.ReferencedAssemblies.Add( "system.dll" );

            if( bDebug )
                AddTracingAssemblies( cpCompilerParameters );

            // add Metric Manager reference
            String	strPath	= System.Configuration.ConfigurationManager.AppSettings[ "AppPath" ].ToString();
            cpCompilerParameters.ReferencedAssemblies.Add( strPath + strMetricManagerPath );

            if( strDLLFileNameParam.Equals( "" ) )
                // this tells to compile the code (in memory only) and to not generate .EXE
                cpCompilerParameters.GenerateExecutable	= false;
            else
            {
                // unload the app domain with the DLL
                FreeDLL();

                // release the NEW DLL if it is loaded (who knows? it could be)
                // because we're going to overwrite it
                FreeLibrary( GetModuleHandle( strDLLFileNameParam ) );

                // deletes the file because we're going to create
                // a new one with this name
                File.Delete( strDLLFileNameParam );

                // this tells to generate executable, that is, a DLL
                cpCompilerParameters.GenerateExecutable	= true;
                cpCompilerParameters.OutputAssembly		= strDLLFileNameParam;

                strLoadedDLLName	= strDLLFileNameParam;
            }

            cpCompilerParameters.GenerateInMemory	= true;

            // create a string builder that will
            // hold the source code in C#
            StringBuilder strbCSharpCode	= new StringBuilder();

            if( bDebug )
            {
                // these are needed to save Xml from inside the equation
                strbCSharpCode.Append( @"
            using System.Data;
            using System.Data.SqlClient;
            using System.Data.OleDb;
            using System.Xml;
            using System.IO;
            " );
            }

            // write the C# header in the string builder.
            // inside of the C# code there will be a class _Evaluator
            // the _Evaluator class will have functions that will return the result
            // of the expressions
            // the use of adEvaluatorDomain requires compiled assembly to be serializable
            // add attributes to hold MetricManager instance and some parameters
            // and add methods GreaterOf and LesserOf
            strbCSharpCode.Append( @"
            using System;
            using MetricManagerClasses;

            namespace ExpressionEvaluator {

            [Serializable]
            public class _Evaluator {
            public MetricManager mmMetricManager;
            public DateTime dtBegin;
            public DateTime dtEnd;
            public Decimal decLocationId;
            public Decimal decProvLocId;
            public Decimal decProcessId;
            public Decimal decPayHeaderId;
            public String strScheduleType;

            " );

            // add methods for > and <
            if( CheckExpression( edEquations, "GreaterOf(" ) )
                strbCSharpCode.Append( @"
            public Decimal GreaterOf( Decimal decValue1, Decimal decValue2 )
            {
            return decValue1 > decValue2 ? decValue1 : decValue2;
            }

            " );
            if( CheckExpression( edEquations, "LesserOf(" ) )
                strbCSharpCode.Append( @"
            public Decimal LesserOf( Decimal decValue1, Decimal decValue2 )
            {
            return decValue1 < decValue2 ? decValue1 : decValue2;
            }

            " );

            // append constant definitions that will store the vdVariable values
            foreach( VariableDefinition vdVariable in vdVariables )
            {
                if( Convert.IsDBNull( vdVariable ) || vdVariable == null )
                    continue;

                if( !vdVariable.Cacheable )
                {
                    // create public vdVariable in the format:  public Decimal NAME = VALUE;
                    strbCSharpCode.AppendFormat( "		public Decimal {0} = {1};\r\n",
                        vdVariable.Name, vdVariable.Value );
                }
                else
                {
                    // create a getter alias for every variable in order to call the
                    // MetricManager
                    // special trick "\"" below is to insert double quotes
                    // inside the StringBuilder
                    strbCSharpCode.AppendFormat( "\r\n		public Decimal {0}\r\n", vdVariable.Name );
                    strbCSharpCode.Append( "		{ get { return mmMetricManager.GetMetricValue( \"" );
                    strbCSharpCode.Append( vdVariable.Name );
                    strbCSharpCode.Append("\", \r\n" );
                    strbCSharpCode.Append( @"
                    dtBegin, dtEnd, decProvLocId,
                    decLocationId, decProcessId,
                    decPayHeaderId, strScheduleType ); } }
            " );
                }
            }

            // skip a line and add main method to satisfy the compiler
            // in case of DLL generation required
            strbCSharpCode.Append( "\r\n" );
            if( !strDLLFileNameParam.Equals( "" ) )
            {
                strbCSharpCode.Append( @"
            public static void Main() {}

            " );
            }

            // append C# function definitions that will return the result of the expressions
            foreach( EquationDefinition edEquation in edEquations )
            {
                String	strEquationName	= ConvertEquationName( edEquation.Name );

                // create public function in the format:  public TYPE getNAME()
                strbCSharpCode.AppendFormat( "\r\n		public {0} get{1}()\r\n	", edEquation.ReturnType.Name, strEquationName );
                strbCSharpCode.Append( "{ \r\n" );

                // define the function in the format:  { return ( EXPRESSION ); }
                // or { return ( CONDITION ? EXPRESSION : 0 ); } if there is a condition
                if( edEquation.ConditionExpression.Equals( "" ) )
                {
                    if( bDebug )
                        AddTracingCode( strbCSharpCode );

                    // if there is division, enclose expression in a try-catch
                    if( edEquation.Expression.IndexOf( "/" ) > 0 )
                    {
                        strbCSharpCode.Append( "		try { \r\n      return ( " );
                        strbCSharpCode.Append( edEquation.Expression );
                        strbCSharpCode.Append( " ); \r\n		} \r\n		catch( Exception excpt ) {\r\n" );
                        strbCSharpCode.Append( "		if( excpt.Message.IndexOf( \"Attempted to divide by zero\" ) >= 0 ) return 0; \r\n" );
                        strbCSharpCode.Append( "			throw( excpt ); \r\n" );
                        strbCSharpCode.Append( "		} \r\n" );
                    }
                    else
                        strbCSharpCode.AppendFormat( "		return ( {0} ); \r\n", edEquation.Expression );

                }
                else
                {
                    // if there is division, enclose expression in a try-catch
                    if( edEquation.Expression.IndexOf( "/" ) > 0 )
                    {
                        strbCSharpCode.Append( "		try { \r\n      " );
                        strbCSharpCode.AppendFormat( "return ( {0} ? {1} : 0m ); \r\n",
                            edEquation.ConditionExpression, edEquation.Expression );
                        strbCSharpCode.Append( "		} \r\n		catch( Exception excpt ) {\r\n" );
                        strbCSharpCode.Append( "		if( excpt.Message.IndexOf( \"Attempted to divide by zero\" ) >= 0 ) return 0; \r\n" );
                        strbCSharpCode.Append( "			throw( excpt ); \r\n" );
                        strbCSharpCode.Append( "		} \r\n" );
                    }
                    else
                        strbCSharpCode.AppendFormat( "		return ( {0} ? {1} : 0m ); \r\n",
                            edEquation.ConditionExpression, edEquation.Expression );

                }

                strbCSharpCode.Append( "}\r\n\r\n" );

                // create a getter alias for every equation name (in order to not use
                // parenthesis when referencing the equation function)
                strbCSharpCode.AppendFormat( "		public {0} {1} \r\n",
                    edEquation.ReturnType.Name, strEquationName );
                strbCSharpCode.Append( "		{ get { return " );
                strbCSharpCode.AppendFormat( "get{0}", strEquationName );
                strbCSharpCode.Append( "(); } }\r\n\r\n" );

                // if there is a Qty Source specified, create a
                // public function in the format:  public TYPE QuantityOfNAME()
                if( ! edEquation.QuantitySource.Equals( "" ) )
                {
                    strbCSharpCode.AppendFormat( "\r\n		public {0} QuantityOf{1}",
                                edEquation.ReturnType.Name, strEquationName );
                    strbCSharpCode.Append( "()\r\n		{ \r\n" );

                    // if there is a condition, arrange it so it only calculates quantity if condition is evaluated as true
                    if( edEquation.ConditionExpression.Equals( "" ) )
                        // define the function in the format:  { return ( QTY EXPRESSION ); }
                        strbCSharpCode.AppendFormat( "		return ( {0} ); \r\n",
                                    edEquation.QuantitySource );
                    else
                        // define the function in the format:  { return ( condition ? QTY EXPRESSION : 0m ); }
                        strbCSharpCode.AppendFormat( "return ( {0} ? {1} : 0m ); \r\n",
                            edEquation.ConditionExpression, edEquation.QuantitySource );

                    strbCSharpCode.Append( "		}\r\n\r\n" );
                }
            }

            // close the C# code
            strbCSharpCode.Append( "} }" );

            // save source code if debugging (uncomment code in the method below)
            if( bDebug )
                SaveSourceCode( strLoadedDLLName, strbCSharpCode );

            // send the C# code in the string builder to the compiler and get the results
            CompilerResults crCompilerResults	=
                CSharpCodeCompiler.CompileAssemblyFromSource(
                cpCompilerParameters, strbCSharpCode.ToString() );
            if( crCompilerResults.Errors.HasErrors )
            {
                if( strLoadedDLLName.Equals( "" ) )
                {
                    String	strEQUATION_DLL_PREFIX	=
                        System.Configuration.ConfigurationManager.AppSettings[
                        "DLLPathAndName" ];
                    strLoadedDLLName	= strEQUATION_DLL_PREFIX + ConvertEquationName( edEquations[ 0 ].Name );
                }

                // save source code for debugging purposes
                StreamWriter	swSourceFile	= new StreamWriter( File.OpenWrite( strLoadedDLLName + "_with_error.cs" ) );
                swSourceFile.Write( strbCSharpCode.ToString() );
                swSourceFile.Close();

                // create a string builder listing all errors and throw an exception
                StringBuilder	strbErrors	= new StringBuilder();
                strbErrors.Append( "Error Compiling Expression: " );
                foreach( CompilerError err in crCompilerResults.Errors )
                {
                    strbErrors.AppendFormat( "{0}\r\n(Error {1}, Line {2}, Column {3})",
                        err.ErrorText, err.ErrorNumber,
                        err.Line.ToString(), err.Column.ToString() );
                }
                throw new Exception( strbErrors.ToString() );
            }

            // reinstantiate app domain and load the new DLL
            adEvaluatorDomain	= AppDomain.CreateDomain( "EvaluatorDomain" );

            try
            {
                // get the dynamically compiled assembly and create an instance
                // of the _Evaluator class
                Assembly	assemblyEvaluatorClass		= crCompilerResults.CompiledAssembly;

                _objInstantiatedEvaluator	= assemblyEvaluatorClass.CreateInstance(
                    "ExpressionEvaluator._Evaluator" );

                //				// create instance of evaluator (from the DLL) within the application domain
                //				_objInstantiatedEvaluator		= adEvaluatorDomain.CreateInstanceFromAndUnwrap(
                //					strDLLFileNameParam, "ExpressionEvaluator._Evaluator" );
            }
            catch( BadImageFormatException eBadFormat )
            {
                throw eBadFormat;
            }
        }
 // constructor that receives just one EquationDefinition and the DLL name
 public Evaluator( EquationDefinition edEquation, string strDLLFileNameParam )
 {
     VariableDefinition[]	vdVariables	= {};
     EquationDefinition[] edEquations	= { edEquation };
     ConstructEvaluator( edEquations, vdVariables, strDLLFileNameParam );
 }
 // constructor that receives EquationDefinition, VariableDefinition and DLL file name
 public Evaluator( EquationDefinition[] edEquations, VariableDefinition[] vdVariables, string strDLLFileNameParam )
 {
     ConstructEvaluator( edEquations, vdVariables, strDLLFileNameParam );
 }
 // constructor that receives EquationDefinition and VariableDefinition
 public Evaluator( EquationDefinition[] edEquations, VariableDefinition[] vdVariables )
 {
     ConstructEvaluator( edEquations, vdVariables, "" );
 }
 // constructor that receives just one EquationDefinition
 public Evaluator( EquationDefinition edEquation )
 {
     VariableDefinition[]	vdVariables	= {};
     EquationDefinition[] edEquations	= { edEquation };
     ConstructEvaluator( edEquations, vdVariables, "" );
 }
        private bool CheckExpression( EquationDefinition[] edEquations, String strExpression )
        {
            foreach( EquationDefinition objEquation in edEquations )
                if( objEquation.ConditionExpression.IndexOf( strExpression ) >= 0
                    || objEquation.Expression.IndexOf( strExpression ) >= 0 )
                    return true;

            return false;
        }