/// <summary>
        /// Evals the specified source.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        public static bool Eval(EntityObject source, FilterElement element)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            switch (element.Type)
            {
            case FilterElementType.Abstract:
                throw new NotSupportedException();

            case FilterElementType.Exists:
                throw new NotSupportedException();

            case FilterElementType.NotExists:
                throw new NotSupportedException();

            case FilterElementType.In:
                throw new NotSupportedException();

            case FilterElementType.NotIn:
                throw new NotSupportedException();

            case FilterElementType.AndBlock:
            {
                foreach (FilterElement childElement in element.ChildElements)
                {
                    if (!Eval(source, childElement))
                    {
                        return(false);
                    }
                }
                return(true);
            }

            case FilterElementType.OrBlock:
            {
                foreach (FilterElement childElement in element.ChildElements)
                {
                    if (Eval(source, childElement))
                    {
                        return(true);
                    }
                }
                return(false);
            }

            case FilterElementType.Between:
            {
                object propertyValue = GetPropertyValue(source, element.Source);

                object start = element.ChildElements[0].Value;
                object end   = element.ChildElements[1].Value;

                int result1 = Compare(start, propertyValue);
                int result2 = Compare(propertyValue, end);

                return(result1 <= 0 && result2 <= 0);
            }

            case FilterElementType.Contains:
            {
                string propertyValue = (string)GetPropertyValue(source, element.Source);
                string mask          = (string)element.Value;

                if (propertyValue == null || mask == null)
                {
                    return(false);
                }

                return(propertyValue.IndexOf(mask, StringComparison.OrdinalIgnoreCase) != -1);
            }

            case FilterElementType.NotContains:
            {
                string propertyValue = (string)GetPropertyValue(source, element.Source);
                string mask          = (string)element.Value;

                if (propertyValue == null || mask == null)
                {
                    return(false);
                }

                return(!(propertyValue.IndexOf(mask, StringComparison.OrdinalIgnoreCase) != -1));
            }

            case FilterElementType.Custom:
                throw new NotSupportedException();

            case FilterElementType.EndsWith:
            {
                string propertyValue = (string)GetPropertyValue(source, element.Source);
                string mask          = (string)element.Value;

                if (propertyValue == null || mask == null)
                {
                    return(false);
                }

                return(propertyValue.EndsWith(mask, StringComparison.OrdinalIgnoreCase));
            }

            case FilterElementType.NotEndsWith:
            {
                string propertyValue = (string)GetPropertyValue(source, element.Source);
                string mask          = (string)element.Value;

                if (propertyValue == null || mask == null)
                {
                    return(false);
                }

                return(!propertyValue.EndsWith(mask, StringComparison.OrdinalIgnoreCase));
            }

            case FilterElementType.StartsWith:
            {
                string propertyValue = (string)GetPropertyValue(source, element.Source);
                string mask          = (string)element.Value;

                if (propertyValue == null || mask == null)
                {
                    return(false);
                }

                return(propertyValue.StartsWith(mask, StringComparison.OrdinalIgnoreCase));
            }

            case FilterElementType.NotStartsWith:
            {
                string propertyValue = (string)GetPropertyValue(source, element.Source);
                string mask          = (string)element.Value;

                if (propertyValue == null || mask == null)
                {
                    return(false);
                }

                return(!propertyValue.StartsWith(mask, StringComparison.OrdinalIgnoreCase));
            }

            case FilterElementType.Equal:
            {
                object propertyValue = GetPropertyValue(source, element.Source);
                object srcValue      = element.Value;

                return(Compare(propertyValue, srcValue) == 0);
            }

            case FilterElementType.NotEqual:
            {
                object propertyValue = GetPropertyValue(source, element.Source);
                object srcValue      = element.Value;

                return(Compare(propertyValue, srcValue) != 0);
            }

            case FilterElementType.Greater:
            {
                object propertyValue = GetPropertyValue(source, element.Source);
                object srcValue      = element.Value;

                return(Compare(propertyValue, srcValue) > 0);
            }

            case FilterElementType.GreaterOrEqual:
            {
                object propertyValue = GetPropertyValue(source, element.Source);
                object srcValue      = element.Value;

                return(Compare(propertyValue, srcValue) >= 0);
            }

            case FilterElementType.IsNotNull:
            {
                object propertyValue = GetPropertyValue(source, element.Source);
                return(propertyValue != null);
            }

            case FilterElementType.IsNull:
            {
                object propertyValue = GetPropertyValue(source, element.Source);
                return(propertyValue == null);
            }

            case FilterElementType.Less:
            {
                object propertyValue = GetPropertyValue(source, element.Source);
                object srcValue      = element.Value;

                return(Compare(propertyValue, srcValue) < 0);
            }

            case FilterElementType.LessOrEqual:
            {
                object propertyValue = GetPropertyValue(source, element.Source);
                object srcValue      = element.Value;

                return(Compare(propertyValue, srcValue) <= 0);
            }

            case FilterElementType.Like:
            {
                string propertyValue = (string)GetPropertyValue(source, element.Source);
                string mask          = (string)element.Value;

                if (propertyValue == null || mask == null)
                {
                    return(false);
                }

                // TODO: Support % Only
                mask = mask.Replace('%', '*');

                return(WildcardUtil.PatternMatch(propertyValue, mask));
            }

            case FilterElementType.NotLike:
            {
                string propertyValue = (string)GetPropertyValue(source, element.Source);
                string mask          = (string)element.Value;

                if (propertyValue == null || mask == null)
                {
                    return(false);
                }

                // TODO: Support % Only
                mask = mask.Replace('%', '*');

                return(!WildcardUtil.PatternMatch(propertyValue, mask));
            }
            }

            throw new NotSupportedException();
        }