/// <summary>
        /// Evaluate
        /// </summary>
        public override object Evaluate(Act act, CdssContext <Patient> context, IDictionary <String, Object> scopes)
        {
            var value = act.GetType().GetRuntimeProperty(this.PropertyName) as IList;

            value?.Add(this.Element);
            return(value);
        }
        /// <summary>
        /// Evaluate the "when" clause
        /// </summary>
        public bool Evaluate <TData>(CdssContext <TData> context)
        {
            if (this.m_compiledExpression == null)
            {
                this.Compile <TData>(context);
            }

            lock (m_lockObject)
            {
                st_contextReference = context;
                return(this.m_compiledExpression.Invoke(context));
            }
        }
        /// <summary>
        /// Evaluate the actions
        /// </summary>
        /// <returns></returns>
        public IEnumerable <Act> Evaluate(CdssContext <Patient> context)
        {
            List <Act> retVal = new List <Act>();
            Dictionary <String, Object> calculatedScopes = new Dictionary <string, object>()
            {
                { ".", context.Target }
            };

            foreach (var itm in this.Action)
            {
                Act act = null;
                if (itm.Element is String) // JSON
                {
                    itm.Element = s_serializer.DeSerialize <Act>(itm.Element as String);
                    // Load all concepts for the specified objects
                }
                act = (itm.Element as Act).Clone() as Act;
                act.Participations = new List <ActParticipation>((itm.Element as Act).Participations.Select(o => o.Clone() as ActParticipation));
                act.Relationships  = new List <ActRelationship>((itm.Element as Act).Relationships.Select(o => o.Clone() as ActRelationship));
                act.Protocols      = new List <ActProtocol>();// (itm.Element as Act).Protocols);
                // Now do the actions to the properties as stated
                foreach (var instr in itm.Do)
                {
                    instr.Evaluate(act, context, calculatedScopes);
                }

                // Assign this patient as the record target
                act.Key = act.Key ?? Guid.NewGuid();
                Guid pkey = Guid.NewGuid();
                act.Participations.Add(new ActParticipation(ActParticipationKey.RecordTarget, context.Target.Key)
                {
                    ParticipationRole = new Core.Model.DataTypes.Concept()
                    {
                        Key = ActParticipationKey.RecordTarget, Mnemonic = "RecordTarget"
                    }, Key = pkey
                });
                // Add record target to the source for forward rules
                context.Target.Participations.Add(new ActParticipation(ActParticipationKey.RecordTarget, context.Target)
                {
                    SourceEntity = act, ParticipationRole = new Core.Model.DataTypes.Concept()
                    {
                        Key = ActParticipationKey.RecordTarget, Mnemonic = "RecordTarget"
                    }, Key = pkey
                });
                act.CreationTime = DateTimeOffset.Now;
                // The act to the return value
                retVal.Add(act);
            }

            return(retVal);
        }
        /// <summary>
        /// Evaluate the specified action on the object
        /// </summary>
        public override object Evaluate(Act act, CdssContext <Patient> context, IDictionary <String, Object> scopes)
        {
            var propertyInfo = act.GetType().GetRuntimeProperty(this.PropertyName);

            if (this.Element != null)
            {
                propertyInfo.SetValue(act, this.Element);
            }
            else
            {
                var setValue = this.GetValue(act, context, scopes);

                //exp.TypeRegistry.RegisterSymbol("data", expressionParm);
                if (Core.Model.Map.MapUtil.TryConvert(setValue, propertyInfo.PropertyType, out setValue))
                {
                    propertyInfo.SetValue(act, setValue);
                }
            }

            return(propertyInfo.GetValue(act));
        }
        /// <summary>
        /// Get the specified value
        /// </summary>
        public object GetValue(Act act, CdssContext <Patient> context, IDictionary <String, Object> scopes)
        {
            if (this.m_setter == null)
            {
                Func <String, Object> varFetch = (a) => context.Get(a);

                var interpretor = new Interpreter(InterpreterOptions.Default)
                                  .Reference(typeof(TimeSpan))
                                  .Reference(typeof(Guid))
                                  .Reference(typeof(DateTimeOffset))
                                  .Reference(typeof(Types));

                // Scope
                if (!String.IsNullOrEmpty(this.ScopeSelector) && this.m_setter == null)
                {
                    var scopeProperty = context.Target.GetType().GetRuntimeProperty(this.ScopeSelector);

                    if (scopeProperty == null)
                    {
                        return(null);                       // no scope
                    }
                    // Where clause?
                    if (!String.IsNullOrEmpty(this.WhereFilter) && this.m_scopeSelectMethod == null)
                    {
                        var itemType      = scopeProperty.PropertyType.GenericTypeArguments[0];
                        var predicateType = typeof(Func <,>).MakeGenericType(new Type[] { itemType, typeof(bool) });
                        var builderMethod = typeof(QueryExpressionParser).GetGenericMethod(nameof(QueryExpressionParser.BuildLinqExpression), new Type[] { itemType }, new Type[] { typeof(NameValueCollection) });
                        this.m_linqExpression     = builderMethod.Invoke(null, new Object[] { NameValueCollection.ParseQueryString(this.WhereFilter) }) as Expression;
                        this.m_compiledExpression = (this.m_linqExpression as LambdaExpression).Compile();
                        // Call where clause
                        builderMethod = typeof(Expression).GetGenericMethod(nameof(Expression.Lambda), new Type[] { predicateType }, new Type[] { typeof(Expression), typeof(ParameterExpression[]) });
                        var firstMethod = typeof(Enumerable).GetGenericMethod("FirstOrDefault",
                                                                              new Type[] { itemType },
                                                                              new Type[] { scopeProperty.PropertyType, predicateType });

                        this.m_scopeSelectMethod = (MethodInfo)firstMethod;
                    }
                    interpretor   = interpretor.Reference(this.m_scopeSelectMethod.ReturnType);
                    this.m_setter = interpretor.Parse(this.ValueExpression, new Parameter("_", this.m_scopeSelectMethod.ReturnType));
                }
                else
                {
                    this.m_setter = interpretor.Parse(this.ValueExpression, new Parameter("_", typeof(CdssContext <Patient>)));
                }
            }

            Object setValue = null;

            // Where clause?
            if (!String.IsNullOrEmpty(this.ScopeSelector))
            {
                // Is the scope selector key present?
                String scopeKey = $"{this.ScopeSelector}.{this.WhereFilter}";
                object scope    = null;
                if (!scopes.TryGetValue(scopeKey, out scope))
                {
                    var scopeProperty = context.Target.GetType().GetRuntimeProperty(this.ScopeSelector);
                    var scopeValue    = scopeProperty.GetValue(context.Target);
                    scope = scopeValue;
                    if (!String.IsNullOrEmpty(this.WhereFilter))
                    {
                        scope = this.m_scopeSelectMethod.Invoke(null, new Object[] { scopeValue, this.m_compiledExpression });
                    }
                    lock (scopes)
                        if (!scopes.ContainsKey(scopeKey))
                        {
                            scopes.Add(scopeKey, scope);
                        }
                }
                setValue = this.m_setter.Invoke(scope);
            }
            else
            {
                setValue = this.m_setter.Invoke(context);
            }

            return(setValue);
        }
 /// <summary>
 /// Evaluate the expression
 /// </summary>
 /// <returns></returns>
 public abstract object Evaluate(Act act, CdssContext <Patient> context, IDictionary <String, Object> scopes);
        /// <summary>
        /// Compile the expression
        /// </summary>
        public Expression Compile <TData>(CdssContext <TData> context)
        {
            ParameterExpression expressionParm = Expression.Parameter(typeof(CdssContext <TData>), "_scope");
            Expression          body           = null;

            // Iterate and perform binary operations
            foreach (var itm in this.Clause)
            {
                Expression clauseExpr = null;
                if (itm is ProtocolWhenClauseCollection)
                {
                    clauseExpr = Expression.Invoke((itm as ProtocolWhenClauseCollection).Compile <TData>(context), expressionParm);
                }
                else if (itm is WhenClauseHdsiExpression)
                {
                    var varDict = new Dictionary <String, Func <Object> >();
                    foreach (var varRef in context.Variables)
                    {
                        varDict.Add(varRef, () => st_contextReference?.Get(varRef));
                    }

                    var hdsiExpr = itm as WhenClauseHdsiExpression;
                    clauseExpr = QueryExpressionParser.BuildLinqExpression <TData>(NameValueCollection.ParseQueryString(hdsiExpr.Expression), "s", varDict, safeNullable: true, forceLoad: true, lazyExpandVariables: true);
                    clauseExpr = Expression.Invoke(clauseExpr, Expression.MakeMemberAccess(expressionParm, typeof(CdssContext <TData>).GetProperty("Target")));
                    if (hdsiExpr.NegationIndicator)
                    {
                        clauseExpr = Expression.Not(clauseExpr);
                    }
                    this.m_tracer.TraceVerbose("Converted WHEN {0} > {1}", hdsiExpr.Expression, clauseExpr);
                }
                else if (itm is XmlLambdaExpression)
                {
                    var xmlLambda = itm as XmlLambdaExpression;
                    (itm as XmlLambdaExpression).InitializeContext(null);
                    // replace parameter
                    clauseExpr = Expression.Invoke(((itm as XmlLambdaExpression).ToExpression() as LambdaExpression), expressionParm);
                }
                else
                {
                    var interpreter = new Interpreter(InterpreterOptions.Default)
                                      .Reference(typeof(TData))
                                      .Reference(typeof(Guid))
                                      .Reference(typeof(TimeSpan))
                                      .Reference(typeof(Types))
                                      .EnableReflection();
                    var linqAction = interpreter.ParseAsExpression <Func <CdssContext <TData>, bool> >(itm.ToString(), "_");
                    clauseExpr = Expression.Invoke(linqAction, expressionParm);
                    //clauseExpr = Expression.Invoke(d, expressionParm);
                }

                // Append to master expression
                if (body == null)
                {
                    body = clauseExpr;
                }
                else
                {
                    body = Expression.MakeBinary((ExpressionType)Enum.Parse(typeof(ExpressionType), this.Operator.ToString()), body, clauseExpr);
                }
            }

            // Wrap and compile
            var objParm       = Expression.Parameter(typeof(Object));
            var bodyCondition = Expression.Lambda <Func <CdssContext <TData>, bool> >(body, expressionParm);
            var invoke        = Expression.Invoke(
                bodyCondition,
                Expression.Convert(objParm, typeof(CdssContext <TData>))
                );
            var uncompiledExpression = Expression.Lambda <Func <Object, bool> >(invoke, objParm);

            this.DebugView            = uncompiledExpression.ToString();
            this.m_compiledExpression = uncompiledExpression.Compile();
            return(uncompiledExpression);
        }