Inheritance: ICloneable
        public static ExpressionTree AssociateTrees(ExpressionTree a, ExpressionTree b, FilterImplication implication)
        {
            // check the parameters
            Debug.Assert(a != null && b != null, "Null parameters");

            ExpressionTree result = new ExpressionTree();
            result.AddRoot(ExpressionType.Implication, implication);
            result.Root.Left = a.Root;
            result.Root.Right = b.Root;
            return result;
        }
        public static ExpressionTree AssociateTreeWithFilter(ExpressionTree tree, FilterBase filter, 
            FilterImplication implication, TreeDirection treeDirection)
        {
            // check the parameters
            Debug.Assert(tree != null && filter != null, "Null parameters");
            ExpressionTree result = new ExpressionTree();

            if(treeDirection == TreeDirection.Left) {
                result.AddRoot(ExpressionType.Implication, implication);
                result.Root.Left = tree.Root;
                result.AddNode(result.Root, TreeDirection.Right, ExpressionType.Filter, filter);
            }
            else {
                result.AddRoot(ExpressionType.Implication, implication);
                result.Root.Right = tree.Root;
                result.AddNode(result.Root, TreeDirection.Left, ExpressionType.Filter, filter);
            }

            return result;
        }
        public static ExpressionTree AssociateFilters(FilterBase a, FilterBase b, 
            FilterImplication implication)
        {
            // check the parameters
            Debug.Assert(a != null && b != null, "Null parameters");

            ExpressionTree result = new ExpressionTree();
            result.AddRoot(ExpressionType.Implication, implication);
            result.AddNode(result.Root, TreeDirection.Left, ExpressionType.Filter, a);
            result.AddNode(result.Root, TreeDirection.Right, ExpressionType.Filter, b);
            return result;
        }
 public object Clone()
 {
     ExpressionTree temp = new ExpressionTree();
     temp._root = (ExpressionNode)_root.Clone();
     return temp;
 }
        /// <summary>
        /// Parses the expression.
        /// </summary>
        /// <param name="expression">The expression.</param>
        /// <param name="start">The start position.</param>
        /// <param name="tree">The tree.</param>
        /// <param name="expressionLength">Length of the expression.</param>
        /// <returns></returns>
        private bool ParseExpression(string expression, int start, out ExpressionTree tree, 
            out int expressionLength)
        {
            tree = null;
            expressionLength = 0;

            if(start < 0 || start >= expression.Length) {
                return false;
            }

            // get the end position
            int position = start;
            ExpressionElement[] elements = new ExpressionElement[3];
            int elementPosition = 0;
            int length = expression.Length;

            while(position < length) {
                // jump over spaces
                if(expression[position] == ' ' || expression[position] == ExpressionEndChar) {
                    position++;
                    continue;
                }

                bool positionChanged = false;

                if(expression[position] == ExpressionStartChar) {
                    ExpressionTree child;
                    int subexpressionLength;

                    // invalid expression
                    if(ParseExpression(expression, position + 1, out child, out subexpressionLength) == false) {
                        return false;
                    }

                    // invalid expression
                    if(elementPosition == 1) {
                        return false;
                    }

                    elements[elementPosition].Type = ElementType.Tree;
                    elements[elementPosition].Element = child;
                    elementPosition++;
                    position += subexpressionLength + 1;
                    positionChanged = true;
                }
                else {
                    // get the first substring
                    string[] components = expression.Substring(position).Split(ExpressionSeparators,
                                                                               StringSplitOptions.RemoveEmptyEntries);

                    // invalid expression
                    if(components.Length == 0) {
                        return false;
                    }

                    FilterImplication implication;
                    if(GetImplicationType(components[0], out implication)) {
                        // valid Implication
                        if(elementPosition != 1) {
                            // invalid expression
                            return false;
                        }

                        elements[elementPosition].Type = ElementType.Implication;
                        elements[elementPosition].Element = implication;
                        elementPosition++;
                    }
                    else {
                        // Filter name
                        if(elementPosition == 1) {
                            // invalid expression
                            return false;
                        }

                        FilterBase filter = GetFilter(components[0]);

                        // invalid expression
                        if(filter == null) {
                            return false;
                        }

                        elements[elementPosition].Type = ElementType.Filter;
                        elements[elementPosition].Element = filter;
                        elementPosition++;
                    }

                    position += components[0].Length + 1;
                    positionChanged = true;
                }

                if(positionChanged == false) {
                    position++;
                }

                if(position >= length || elementPosition >= 3) {
                    // end of expression, build evaluation tree
                    if(elementPosition == 2) {
                        // invalid expression
                        return false;
                    }

                    // build the tree
                    tree = AssociateElements(elements, elementPosition);
                    expressionLength = position - start;
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// Associates the given tree elements.
        /// </summary>
        /// <param name="elements">The elements.</param>
        /// <param name="elementCount">The element count.</param>
        /// <returns></returns>
        private ExpressionTree AssociateElements(ExpressionElement[] elements, int elementCount)
        {
            if(elementCount == 2) {
                throw new Exception("Invalid expression element count");
            }

            // handle special case
            if(elementCount == 1) {
                if(elements[0].Type == ElementType.Implication) {
                    return null;
                }
                else if(elements[0].Type == ElementType.Tree) {
                    return (ExpressionTree)elements[0].Element;
                }
                else {
                    ExpressionTree tree = new ExpressionTree();
                    tree.Root = new FilterNode((FilterBase)elements[0].Element);
                    return tree;
                }
            }

            // normal case
            // middle element should be an Implication
            if(elements[1].Type != ElementType.Implication) {
                return null;
            }

            ExpressionTree parent = new ExpressionTree();
            ExpressionElement left = elements[0];
            ExpressionElement right = elements[2];
            FilterImplication implication = (FilterImplication)elements[1].Element;

            // build the tree
            if(left.Type == ElementType.Tree && right.Type == ElementType.Filter) {
                parent = ExpressionTreeBuilder.AssociateTreeWithFilter((ExpressionTree)left.Element,
                                                                       (FilterBase)right.Element,
                                                                        implication, TreeDirection.Left);
            }
            else if(left.Type == ElementType.Filter && right.Type == ElementType.Tree) {
                parent = ExpressionTreeBuilder.AssociateTreeWithFilter((ExpressionTree)right.Element,
                                                                       (FilterBase)left.Element,
                                                                        implication, TreeDirection.Right);
            }
            else if(left.Type == ElementType.Tree && right.Type == ElementType.Tree) {
                parent = ExpressionTreeBuilder.AssociateTrees((ExpressionTree)left.Element,
                                                              (ExpressionTree)right.Element,
                                                               implication);
            }
            else if(left.Type == ElementType.Filter && right.Type == ElementType.Filter) {
                parent = ExpressionTreeBuilder.AssociateFilters((FilterBase)left.Element,
                                                                (FilterBase)right.Element,
                                                                implication);
            }

            return parent;
        }
        /// <summary>
        /// Gets the expression tree string.
        /// </summary>
        /// <param name="tree">The tree.</param>
        /// <returns></returns>
        public string GetExpressionTreeString(ExpressionTree tree)
        {
            if(tree == null) {
                throw new ArgumentNullException("tree");
            }

            return TreeToString(tree.Root).Trim();
        }