/// <summary>
    /// Return the value of the specified property as an object. The PropertyName
    /// is relative to the RelativeTo argument (usually Plant).
    /// Format:
    ///    [function(]VariableName[)]
    /// Where:
    ///     function is optional and can be one of Sum, subtract, multiply, divide, max, min
    ///     VariableName is the name of a Plant variable. It can also include an array. Array can
    ///                  have a filter inside of square brackets. Filter can be an array index (0 based)
    ///                  or be the name of a class or base class.
    /// e.g. Leaf.MinT
    ///      sum(Leaf.Leaves[].Live.Wt)              - sums all live weights of all objects in leaves array.
    ///      subtract(Leaf.Leaves[].Live.Wt)         - subtracts all live weights of all objects in leaves array.
    ///      Leaf.Leaves[1].Live.Wt                  - returns the live weight of the 2nd element of the leaves array.
    ///      sum(Leaf.Leaves[AboveGround].Live.Wt)   - returns the live weight of the 2nd element of the leaves array.
    /// </summary>
    public static object Evaluate(string Expression, ModelFramework.Component RelativeTo)
    {
        ExpressionEvaluator fn = new ExpressionEvaluator();

        Parse(fn, Expression);
        FillVariableNames(fn, RelativeTo);
        Evaluate(fn);
        if (fn.Results != null)
        {
            return(fn.Results);
        }
        else
        {
            return(fn.Result);
        }
    }
    private static void FillVariableNames(ExpressionEvaluator fn, ModelFramework.Component RelativeTo)
    {
        ArrayList varUnfilled = fn.Variables;
        ArrayList varFilled   = new ArrayList();
        Symbol    symFilled;

        foreach (Symbol sym in varUnfilled)
        {
            symFilled.m_name        = sym.m_name;
            symFilled.m_type        = EBMath.Type.Variable;
            symFilled.m_valueString = "";
            symFilled.m_value       = 0;
            if (!RelativeTo.Get(sym.m_name.Trim(), out symFilled.m_value))
            {
                throw new Exception("Cannot find variable: " + sym.m_name + " in function: " + RelativeTo.Name);
            }
            varFilled.Add(symFilled);
        }
        fn.Variables = varFilled;
    }
        /// <summary>Initializes a new instance of the <see cref="PatchVariable"/> class.</summary>
        /// <param name="variableName">Name of the variable.</param>
        /// <param name="longterm">if set to <c>true</c> [longterm].</param>
        /// <param name="fromDate">From date.</param>
        /// <param name="toDate">To date.</param>
        /// <param name="data">The data.</param>
        public PatchVariable(string variableName, string dataColumnName, string value, bool longterm, DateTime fromDate, DateTime toDate, DataTable data, ModelFramework.Component paddock)
        {
            this.variableNameToSet = variableName;
            this.dataColumnName    = dataColumnName;
            this.value             = value;
            this.longterm          = longterm;
            this.fromDate          = fromDate;
            this.toDate            = toDate;
            this.data    = data;
            this.value   = value;
            this.paddock = paddock;

            // For convienence of user, sometimes the data column name may have a met. in front
            // of the name. Strip this off.
            if (this.dataColumnName != null)
            {
                int posPeriod = this.dataColumnName.LastIndexOf('.');
                if (posPeriod != -1)
                {
                    this.dataColumnName = this.dataColumnName.Substring(posPeriod + 1);
                }
            }
        }
    public void OnPrepare()
    {
        inputFile.SeekToDate(Today);
        object[] values = inputFile.GetNextLineOfData();
        foreach (Paddock p in paddock.ChildPaddocks)
        {
            fieldProps = (ModelFramework.Component)p.LinkByName("FieldProps");
            fieldProps.Get("isDry", out isDry);
            fieldProps.Get("isHot", out isHot);
            fieldProps.Get("isShaded", out isShaded);

            localMint = Convert.ToSingle(values[MinTIndex]);
            localMaxt = Convert.ToSingle(values[MaxTIndex]);
            localRadn = Convert.ToSingle(values[RadnIndex]);
            localRain = Convert.ToSingle(values[RainIndex]);

            if (isDry.Equals("yes"))
            {
                localRain *= 0.9f;
            }
            if (isHot.Equals("yes"))
            {
                localMint += 2;
                localMaxt += 2; //change tav/amp?
            }
            if (isShaded.Equals("yes"))
            {
                localMaxt -= 5;
            }

            localMet = (ModelFramework.Component)p.LinkByName("LocalClimate");
            localMet.Set("mint", localMint);
            localMet.Set("maxt", localMaxt);
            localMet.Set("radn", localRadn);
            localMet.Set("rain", localRain);
        }
    }
    /// <summary>
    /// Creates any classes that are of type [Link] in the model
    /// </summary>
    public void Resolve()
    {
        if (Field.Get == null)
        {
            Object ReferencedObject = null;

            // Load in the probe info assembly.
            //ProbeInfo = Assembly.LoadFile(Path.Combine(Configuration.ApsimDirectory(), "Model", "CSDotNetProxies.dll"));
            if (ProbeInfo == null)
            {
                ProbeInfo = Assembly.LoadFile(Path.Combine(Configuration.ApsimDirectory(), "Model", "DotNetProxies.dll"));
            }

            String TypeToFind = Field.Typ.Name;
            String NameToFind;
            if (LinkAttr.NamePath == null)
            {
                NameToFind = Field.Name;
            }
            else
            {
                NameToFind = LinkAttr.NamePath;
            }

            if (NameToFind == "My")
            {
                ReferencedObject = new ModelFramework.Component(In);
            }

            else if (IsAPSIMType(TypeToFind))
            {
                if (LinkAttr.NamePath == null)
                {
                    NameToFind = null; // default is not to use name.
                }
                string SystemName = Comp.Name.Substring(0, Math.Max(Comp.Name.LastIndexOf('.'), 0));
                ReferencedObject = FindApsimObject(TypeToFind, NameToFind, SystemName, Comp);
            }
            else if (TypeToFind.Contains("[]"))
            {
                // e.g. TypeToFind == "LeafCohort[]"
                List <object> ReferencedObjects = new List <object>();
                foreach (Instance Child in In.Children)
                {
                    string ChildNameWithoutArray = Child.Name;
                    StringManip.SplitOffBracketedValue(ref ChildNameWithoutArray, '[', ']');
                    if (ChildNameWithoutArray == NameToFind)
                    {
                        ReferencedObjects.Add(Child.Model);
                    }
                }
                Array A = Array.CreateInstance(Field.Typ.GetElementType(), ReferencedObjects.Count) as Array;
                for (int i = 0; i < ReferencedObjects.Count; i++)
                {
                    A.SetValue(ReferencedObjects[i], i);
                }
                ReferencedObject = A;
            }
            else
            {
                // Link is an Instance link - use name and type to find the object.
                ReferencedObject = FindInstanceObject(In, NameToFind, TypeToFind);
            }

            // Set the value of the [Link] field to the newly created object.
            if (ReferencedObject == null)
            {
                if (!LinkAttr.IsOptional)
                {
                    throw new Exception("Cannot find [Link] for type: " + TypeToFind + " " + NameToFind + " in object: " + In.Name);
                }
            }
            else if (ReferencedObject is Instance)
            {
                Field.SetObject(((Instance)ReferencedObject).Model);
            }
            else
            {
                Field.SetObject(ReferencedObject);
            }
        }
    }