class PushdownNegationVisitor extends BaseVisitor {

    @Override
    public Object visit(ASTNotNode node, Object data) {
        // if there is already a negation passed down it should negate this node and continue down the tree to check for other negations
        if (data != null && ((NegationState) data).isNegated()) {
            JexlNode nextNode = dropNot(node, (NegationState) data);
            
            // pass down with a new negation state since nothing that comes up from this point should impact what is already being returned (a processed
            // negation)
            nextNode.jjtAccept(this, new NegationState(false));
            
            return data;
        } else {
            // arrived to this node without a negation, apply a negation and push down
            NegationState state = (NegationState) super.visit(node, new NegationState(true));
            
            // if the returned state is false the negation was successfully pushed down, it should be removed
            if (!state.isNegated()) {
                // drop the not because it was pushed down and get the new node
                JexlNode nextNode = dropNot(node, new NegationState(true));
                
                // the negation at this level was removed so the state is false going forward
                nextNode.jjtAccept(this, new NegationState(false));
            }
            
            // any down-tree state manipulation is a result of this NOT so do not back propagate that
            return data;
        }
    }

}