/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

package org.apache.shardingsphere.core.rewrite.rewriter.sql;

import org.apache.shardingsphere.core.optimize.statement.OptimizedStatement;
import org.apache.shardingsphere.core.optimize.statement.sharding.dml.insert.ShardingInsertOptimizedStatement;
import org.apache.shardingsphere.core.rewrite.builder.ParameterBuilder;
import org.apache.shardingsphere.core.rewrite.builder.SQLBuilder;
import org.apache.shardingsphere.core.rewrite.placeholder.AggregationDistinctPlaceholder;
import org.apache.shardingsphere.core.rewrite.placeholder.IndexPlaceholder;
import org.apache.shardingsphere.core.rewrite.placeholder.InsertGeneratedKeyPlaceholder;
import org.apache.shardingsphere.core.rewrite.placeholder.InsertSetAddGeneratedKeyPlaceholder;
import org.apache.shardingsphere.core.rewrite.placeholder.LimitOffsetPlaceholder;
import org.apache.shardingsphere.core.rewrite.placeholder.LimitRowCountPlaceholder;
import org.apache.shardingsphere.core.rewrite.placeholder.OrderByPlaceholder;
import org.apache.shardingsphere.core.rewrite.placeholder.SelectItemPrefixPlaceholder;
import org.apache.shardingsphere.core.rewrite.placeholder.SelectItemsPlaceholder;
import org.apache.shardingsphere.core.rewrite.token.pojo.AggregationDistinctToken;
import org.apache.shardingsphere.core.rewrite.token.pojo.IndexToken;
import org.apache.shardingsphere.core.rewrite.token.pojo.InsertGeneratedKeyToken;
import org.apache.shardingsphere.core.rewrite.token.pojo.InsertSetAddGeneratedKeyToken;
import org.apache.shardingsphere.core.rewrite.token.pojo.OffsetToken;
import org.apache.shardingsphere.core.rewrite.token.pojo.OrderByToken;
import org.apache.shardingsphere.core.rewrite.token.pojo.RowCountToken;
import org.apache.shardingsphere.core.rewrite.token.pojo.SQLToken;
import org.apache.shardingsphere.core.rewrite.token.pojo.SelectItemPrefixToken;
import org.apache.shardingsphere.core.rewrite.token.pojo.SelectItemsToken;
import org.apache.shardingsphere.core.route.SQLRouteResult;

/**
 * SQL rewriter for sharding.
 * 
 * @author zhangliang
 * @author maxiaoguang
 * @author panjuan
 */
public final class ShardingSQLRewriter implements SQLRewriter {
    
    private final SQLRouteResult sqlRouteResult;
    
    private final OptimizedStatement optimizedStatement;
    
    public ShardingSQLRewriter(final SQLRouteResult sqlRouteResult, final OptimizedStatement optimizedStatement) {
        this.sqlRouteResult = sqlRouteResult;
        this.optimizedStatement = optimizedStatement;
    }
    
    @Override
    public void rewrite(final SQLBuilder sqlBuilder, final ParameterBuilder parameterBuilder, final SQLToken sqlToken) {
        if (sqlToken instanceof SelectItemPrefixToken) {
            appendSelectItemPrefixPlaceholder(sqlBuilder);
        } else if (sqlToken instanceof IndexToken) {
            appendIndexPlaceholder(sqlBuilder, (IndexToken) sqlToken);
        } else if (sqlToken instanceof SelectItemsToken) {
            appendSelectItemsPlaceholder(sqlBuilder, (SelectItemsToken) sqlToken);
        } else if (sqlToken instanceof OffsetToken) {
            appendOffsetPlaceholder(sqlBuilder, (OffsetToken) sqlToken);
        } else if (sqlToken instanceof RowCountToken) {
            appendRowCountPlaceholder(sqlBuilder, (RowCountToken) sqlToken);
        } else if (sqlToken instanceof OrderByToken) {
            appendOrderByPlaceholder(sqlBuilder, (OrderByToken) sqlToken);
        } else if (sqlToken instanceof AggregationDistinctToken) {
            appendAggregationDistinctPlaceholder(sqlBuilder, (AggregationDistinctToken) sqlToken);
        } else if (sqlToken instanceof InsertGeneratedKeyToken) {
            appendInsertGeneratedKeyPlaceholder(sqlBuilder, (InsertGeneratedKeyToken) sqlToken);
        } else if (sqlToken instanceof InsertSetAddGeneratedKeyToken) {
            appendInsertSetAddGeneratedKeyPlaceholder(sqlBuilder, (InsertSetAddGeneratedKeyToken) sqlToken, (ShardingInsertOptimizedStatement) optimizedStatement);
        }
    }
    
    private void appendSelectItemPrefixPlaceholder(final SQLBuilder sqlBuilder) {
        sqlBuilder.appendPlaceholder(new SelectItemPrefixPlaceholder());
    }
    
    private void appendIndexPlaceholder(final SQLBuilder sqlBuilder, final IndexToken indexToken) {
        sqlBuilder.appendPlaceholder(new IndexPlaceholder(indexToken.getIndexName(), indexToken.getQuoteCharacter()));
    }
    
    private void appendSelectItemsPlaceholder(final SQLBuilder sqlBuilder, final SelectItemsToken selectItemsToken) {
        SelectItemsPlaceholder selectItemsPlaceholder = new SelectItemsPlaceholder();
        selectItemsPlaceholder.getItems().addAll(selectItemsToken.getItems());
        sqlBuilder.appendPlaceholder(selectItemsPlaceholder);
    }
    
    private void appendOffsetPlaceholder(final SQLBuilder sqlBuilder, final OffsetToken offsetToken) {
        sqlBuilder.appendPlaceholder(new LimitOffsetPlaceholder(offsetToken.getRevisedOffset()));
    }
    
    private void appendRowCountPlaceholder(final SQLBuilder sqlBuilder, final RowCountToken rowCountToken) {
        sqlBuilder.appendPlaceholder(new LimitRowCountPlaceholder(rowCountToken.getRevisedRowCount()));
    }
    
    private void appendOrderByPlaceholder(final SQLBuilder sqlBuilder, final OrderByToken orderByToken) {
        OrderByPlaceholder orderByPlaceholder = new OrderByPlaceholder();
        orderByPlaceholder.getColumnLabels().addAll(orderByToken.getColumnLabels());
        orderByPlaceholder.getOrderDirections().addAll(orderByToken.getOrderDirections());
        sqlBuilder.appendPlaceholder(orderByPlaceholder);
    }
    
    private void appendAggregationDistinctPlaceholder(final SQLBuilder sqlBuilder, final AggregationDistinctToken distinctToken) {
        sqlBuilder.appendPlaceholder(new AggregationDistinctPlaceholder(distinctToken.getColumnName().toLowerCase(), distinctToken.getDerivedAlias()));
    }
    
    private void appendInsertGeneratedKeyPlaceholder(final SQLBuilder sqlBuilder, final InsertGeneratedKeyToken insertGeneratedKeyToken) {
        sqlBuilder.appendPlaceholder(new InsertGeneratedKeyPlaceholder(insertGeneratedKeyToken.getColumn(), insertGeneratedKeyToken.isToAppendCloseParenthesis()));
    }
    
    private void appendInsertSetAddGeneratedKeyPlaceholder(
            final SQLBuilder sqlBuilder, final InsertSetAddGeneratedKeyToken insertSetAddGeneratedKeyToken, final ShardingInsertOptimizedStatement optimizedStatement) {
        String columnName = insertSetAddGeneratedKeyToken.getColumnName();
        sqlBuilder.appendPlaceholder(new InsertSetAddGeneratedKeyPlaceholder(columnName, optimizedStatement.getUnits().get(0).getColumnSQLExpression(columnName)));
    }
}

@@ -862,196 +862,8 @@
 l;%0A%0A
-import org.apache.shardingsphere.core.optimize.statement.OptimizedStatement;%0Aimport org.apache.shardingsphere.core.optimize.statement.sharding.dml.insert.ShardingInsertOptimizedStatement;%0A
 impo
@@ -922,32 +922,32 @@
 rameterBuilder;%0A
+
 import org.apach
@@ -2519,68 +2519,8 @@
 ken;
-%0Aimport org.apache.shardingsphere.core.route.SQLRouteResult;
 %0A%0A/*
@@ -2696,350 +2696,8 @@
    %0A
-    private final SQLRouteResult sqlRouteResult;%0A    %0A    private final OptimizedStatement optimizedStatement;%0A    %0A    public ShardingSQLRewriter(final SQLRouteResult sqlRouteResult, final OptimizedStatement optimizedStatement) %7B%0A        this.sqlRouteResult = sqlRouteResult;%0A        this.optimizedStatement = optimizedStatement;%0A    %7D%0A    %0A
     
@@ -4110,63 +4110,8 @@
 oken
-, (ShardingInsertOptimizedStatement) optimizedStatement
 );%0A 
@@ -6410,29 +6410,16 @@
 eholder(
-%0A            
 final SQ
@@ -6508,305 +6508,181 @@
 oken
-, final ShardingInsertOptimizedStatement optimizedStatement) %7B%0A        String columnName = insertSetAddGeneratedKeyToken.getColumnName();%0A        sqlBuilder.appendPlaceholder(new InsertSetAddGeneratedKeyPlaceholder(columnName, optimizedStatement.getUnits().get(0).getColumnSQLExpression(columnName
+) %7B%0A        sqlBuilder.appendPlaceholder(new InsertSetAddGeneratedKeyPlaceholder(insertSetAddGeneratedKeyToken.getColumnName(), insertSetAddGeneratedKeyToken.getColumnValue(
 )));

delete members