/**
 * Copyright 1999-2015 dangdang.com.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * </p>
 */

package com.dangdang.ddframe.rdb.sharding.parser.visitor.or;

import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
import com.alibaba.druid.wall.spi.WallVisitorUtils;
import com.dangdang.ddframe.rdb.sharding.parser.visitor.SQLVisitor;
import com.dangdang.ddframe.rdb.sharding.parser.visitor.basic.mysql.AbstractMySQLVisitor;
import com.dangdang.ddframe.rdb.sharding.parser.visitor.or.node.AbstractOrASTNode;
import com.dangdang.ddframe.rdb.sharding.parser.visitor.or.node.CompositeOrASTNode;
import com.dangdang.ddframe.rdb.sharding.parser.visitor.or.node.SimpleOrASTNode;
import com.google.common.base.Optional;

/**
 * 逻辑OR条件访问器.
 * 
 * @author gaohongtao
 */
public class OrVisitor extends AbstractMySQLVisitor {
    
    private AbstractOrASTNode orASTNode;
    
    public OrVisitor(final SQLASTOutputVisitor dependencyVisitor) {
        setParameters(dependencyVisitor.getParameters());
        SQLVisitor visitor = (SQLVisitor) dependencyVisitor;
        String currentTableName = null == visitor.getParseContext().getCurrentTable() ? "" : visitor.getParseContext().getCurrentTable().getName();
        getParseContext().setCurrentTable(currentTableName, Optional.<String>absent());
        getParseContext().setShardingColumns(visitor.getParseContext().getShardingColumns());
    }
    
    /**
     * 进行OR表达式的访问.
     *
     * @param sqlObject SQL对象
     * @return OR访问节点
     */
    public Optional<AbstractOrASTNode> visitHandle(final SQLObject sqlObject) {
        reset();
        sqlObject.accept(this);
        postVisitHandle();
        return Optional.fromNullable(orASTNode);
    }
    
    private void reset() {
        orASTNode = null;
        getParseContext().getCurrentConditionContext().clear();
        getParseContext().setHasOrCondition(false);
    }
    
    private void postVisitHandle() {
        if (null == orASTNode) {
            return;
        }
        if (!getParseContext().getCurrentConditionContext().isEmpty()) {
            CompositeOrASTNode existingOutConditionOrASTNode = new CompositeOrASTNode();
            existingOutConditionOrASTNode.addSubNode(orASTNode);
            existingOutConditionOrASTNode.addOutConditions(getParseContext().getCurrentConditionContext());
            orASTNode = existingOutConditionOrASTNode;
        }
        orASTNode.createOrASTAsRootNode();
    }
    
    /**
     * 逻辑OR访问器, 每次只解析一层OR条件.
     * 
     * @param x 二元表达式
     * @return false 停止访问AST
     */
    @Override
    public boolean visit(final SQLBinaryOpExpr x) {
        if (!SQLBinaryOperator.BooleanOr.equals(x.getOperator())) {
            return super.visit(x);
        }
        if (Boolean.TRUE.equals(WallVisitorUtils.getValue(x))) {
            return false;
        }
        orASTNode = new SimpleOrASTNode(x, new OrVisitor(this));
        return false;
    }
}

@@ -3496,32 +3496,64 @@
       %7D%0A        
+if(orASTNode == null)%7B%0A        %09
 orASTNode = new 
@@ -3589,24 +3589,367 @@
 tor(this));%0A
+        %7Delse%7B%0A        %09%0A            CompositeOrASTNode existingOutConditionOrASTNode = new CompositeOrASTNode();%0A            existingOutConditionOrASTNode.addSubNode(orASTNode);%0A            existingOutConditionOrASTNode.addSubNode(new SimpleOrASTNode(x, new OrVisitor(this)));%0A            orASTNode = existingOutConditionOrASTNode;%0A        %7D%0A
         retu

update OrVisitor