package com.chenyang.druid.sql.visitor;

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.SQLUtils;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLObject;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOperator;
import com.chenyang.druid.sql.ast.expr.SQLCharExpr;
import com.chenyang.druid.sql.ast.expr.SQLHexExpr;
import com.chenyang.druid.sql.ast.expr.SQLInListExpr;
import com.chenyang.druid.sql.ast.expr.SQLIntegerExpr;
import com.chenyang.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.chenyang.druid.sql.ast.expr.SQLNCharExpr;
import com.chenyang.druid.sql.ast.expr.SQLNullExpr;
import com.chenyang.druid.sql.ast.expr.SQLNumberExpr;
import com.chenyang.druid.sql.ast.expr.SQLTimestampExpr;
import com.chenyang.druid.sql.ast.expr.SQLVariantRefExpr;
import com.chenyang.druid.sql.ast.statement.SQLInsertStatement;
import com.chenyang.druid.sql.ast.statement.SQLSelectGroupByClause;
import com.chenyang.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.chenyang.druid.util.FnvHash;
import java.util.List;

public class SQLASTParameterizedVisitor extends SQLASTVisitorAdapter {
   protected DbType dbType;
   protected List<Object> parameters;
   private int replaceCount = 0;

   public SQLASTParameterizedVisitor(DbType dbType) {
      this.dbType = dbType;
   }

   public int getReplaceCount() {
      return this.replaceCount;
   }

   public void incrementReplaceCunt() {
      ++this.replaceCount;
   }

   public DbType getDbType() {
      return this.dbType;
   }

   public SQLASTParameterizedVisitor(DbType dbType, List<Object> parameters) {
      this.dbType = dbType;
      this.parameters = parameters;
   }

   public List<Object> getParameters() {
      return this.parameters;
   }

   public void setParameters(List<Object> parameters) {
      this.parameters = parameters;
   }

   public boolean visit(SQLTimestampExpr x) {
      this.parameterizeAndExportPara(x);
      return false;
   }

   public void parameterizeAndExportPara(SQLExpr x) {
      SQLVariantRefExpr variantRefExpr = new SQLVariantRefExpr("?");
      variantRefExpr.setIndex(this.replaceCount);
      SQLUtils.replaceInParent((SQLExpr)x, (SQLExpr)variantRefExpr);
      this.incrementReplaceCunt();
      ExportParameterVisitorUtils.exportParameter(this.parameters, x);
   }

   public void parameterize(SQLExpr x) {
      SQLVariantRefExpr variantRefExpr = new SQLVariantRefExpr("?");
      variantRefExpr.setIndex(this.replaceCount);
      SQLUtils.replaceInParent((SQLExpr)x, (SQLExpr)variantRefExpr);
      this.incrementReplaceCunt();
   }

   public boolean visit(SQLCharExpr x) {
      this.parameterizeAndExportPara(x);
      return false;
   }

   public boolean visit(SQLIntegerExpr x) {
      SQLObject parent = x.getParent();
      if (!(parent instanceof SQLSelectGroupByClause) && !(parent instanceof SQLSelectOrderByItem)) {
         this.parameterizeAndExportPara(x);
         return false;
      } else {
         return false;
      }
   }

   public boolean visit(SQLMethodInvokeExpr x) {
      List<SQLExpr> arguments = x.getArguments();
      if (x.methodNameHashCode64() == FnvHash.Constants.TRIM && arguments.size() == 1 && arguments.get(0) instanceof SQLCharExpr && x.getTrimOption() == null && x.getFrom() == null) {
         this.parameterizeAndExportPara(x);
         if (this.parameters != null) {
            SQLCharExpr charExpr = (SQLCharExpr)arguments.get(0);
            this.parameters.add(charExpr.getText().trim());
         }

         ++this.replaceCount;
         return false;
      } else {
         return true;
      }
   }

   public boolean visit(SQLNCharExpr x) {
      this.parameterizeAndExportPara(x);
      return false;
   }

   public boolean visit(SQLNullExpr x) {
      SQLObject parent = x.getParent();
      if (parent instanceof SQLInsertStatement || parent instanceof SQLInsertStatement.ValuesClause || parent instanceof SQLInListExpr || parent instanceof SQLBinaryOpExpr && ((SQLBinaryOpExpr)parent).getOperator() == SQLBinaryOperator.Equality) {
         this.parameterize(x);
         if (this.parameters != null) {
            if (parent instanceof SQLBinaryOpExpr) {
               ExportParameterVisitorUtils.exportParameter(this.parameters, (SQLExpr)x);
            } else {
               this.parameters.add(null);
            }
         }

         return false;
      } else {
         return false;
      }
   }

   public boolean visit(SQLNumberExpr x) {
      this.parameterizeAndExportPara(x);
      return false;
   }

   public boolean visit(SQLHexExpr x) {
      this.parameterizeAndExportPara(x);
      return false;
   }
}
