private boolean applyDistributiveLaw(IExpressionContext context,
            ASTNode result) 
    {
        // Distributionsgesetz
        // 	case 1: a and (b or  c) = (a and b) or  (a and c) 	
        //  case 2: a or  (b and c) = (a or  b) and (a or  c)

        
        final TreeMatcher matcher = new TreeMatcher().ignoreChildOrder( true ).requireNodeToHaveParent( true ).unwrapAll()
                .matchParent().matchAND().matchOR().buildOR()
                .matchRightChild().addMatcher( new INodeMatcher() {

                    @Override
                    public boolean matches(TreeMatcher matcher, ASTNode n)
                    {
                        final ASTNode unwrapped = unwrap(matcher.parentMatch());
                        if ( unwrapped.isOR() ) {
                            return n.isAND();
                        }  
                        if ( unwrapped.isAND() ) {
                            return n.isOR();
                        }
                        throw new RuntimeException("Unreachable code reached");
                    }
                } ).buildOR()
                .matchExtra().addMatcher( new INodeMatcher() {

                    @Override
                    public boolean matches(TreeMatcher matcher, ASTNode n)
                    {
                        return matcher.leftMatch().getNodeCount() != matcher.rightMatch().getNodeCount();
                    }
                } ).buildOR();
                
        final MutatingNodeVisitor visitor = new MutatingNodeVisitor( context ) {

            @Override
            public void visit(ASTNode node,IExpressionContext context,IIterationContext it) 
            {
                
                if ( ! matcher.matches( matcher , node ) ) {
                    return;
                }
                
                final ASTNode matchedParent = matcher.parentMatch();
                final ASTNode leftChild = matcher.leftMatch();
                final ASTNode rightChild = matcher.rightMatch();
                
                final ASTNode leftTerm;
                final ASTNode rightTerm;
                final ASTNode replacementTerm;
                
                ASTNode unwrappedRight = unwrap( rightChild );
                if ( unwrap( matchedParent) .isAND() && unwrappedRight.isOR() ) 
                {
                    leftTerm = maybeWrapInTerm( OperatorNode.and( leftChild , unwrappedRight.child(0) ) );
                    rightTerm = maybeWrapInTerm( OperatorNode.and( leftChild , unwrappedRight.child(1) ) );
                    replacementTerm = OperatorNode.or( leftTerm  , rightTerm );
                } 
                else if ( unwrap( matchedParent).isOR() && unwrappedRight.isAND() ) 
                {
                    leftTerm = maybeWrapInTerm( OperatorNode.or( leftChild , unwrappedRight.child(0) ) );
                    rightTerm = maybeWrapInTerm( OperatorNode.or( leftChild , unwrappedRight.child(1) ) );
                    replacementTerm = OperatorNode.and( leftTerm  , rightTerm );
                } else {
                    throw new RuntimeException("Unreachable code reached => "+matcher);
                }
                
                ASTNode toReplace = matchedParent;
                if ( ! toReplace.hasParent() ) 
                {
                  if ( unwrap( toReplace ) != toReplace ) {
                      toReplace = unwrap( toReplace );
                  } else {
                      throw new RuntimeException("Unreachable code reached");                          
                  }
                }
                
                debugPrintln("DISTRIBUTIVE LAW: Replacing "+matchedParent.toString(false)+" -> "+replacementTerm);
                toReplace.replaceWith( replacementTerm );
                it.astMutated();                
            }
        };
        return applyInOrder( result , visitor );
    }