package util.sqlparse.visitor.mariadb.visitor;

import bean.DataBase;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLStatement;
import com.chenyang.druid.sql.ast.expr.SQLQueryExpr;
import com.chenyang.druid.sql.ast.statement.SQLAlterFunctionStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterIndexStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterProcedureStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLAlterViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLBlockStatement;
import com.chenyang.druid.sql.ast.statement.SQLCallStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateFunctionStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateProcedureStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateTriggerStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLDeleteStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropFunctionStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropIndexStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropProcedureStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropTriggerStatement;
import com.chenyang.druid.sql.ast.statement.SQLDropViewStatement;
import com.chenyang.druid.sql.ast.statement.SQLGrantStatement;
import com.chenyang.druid.sql.ast.statement.SQLInsertStatement;
import com.chenyang.druid.sql.ast.statement.SQLReplaceStatement;
import com.chenyang.druid.sql.ast.statement.SQLReturnStatement;
import com.chenyang.druid.sql.ast.statement.SQLRevokeStatement;
import com.chenyang.druid.sql.ast.statement.SQLSelectStatement;
import com.chenyang.druid.sql.ast.statement.SQLUpdateStatement;
import com.chenyang.druid.sql.dialect.mariadb.ast.clause.MariadbSelectIntoStatement;
import com.chenyang.druid.sql.dialect.mariadb.ast.statement.MariadbAlterEventStatement;
import com.chenyang.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableAddExtPartition;
import com.chenyang.druid.sql.dialect.mariadb.ast.statement.MariadbAlterTableDropExtPartition;
import com.chenyang.druid.sql.dialect.mariadb.ast.statement.MariadbCreateEventStatement;
import com.chenyang.druid.sql.dialect.mariadb.ast.statement.MariadbDeleteStatement;
import com.chenyang.druid.sql.dialect.mariadb.ast.statement.MariadbInsertStatement;
import com.chenyang.druid.sql.dialect.mariadb.ast.statement.MariadbKillStatement;
import com.chenyang.druid.sql.dialect.mariadb.ast.statement.MariadbListResourceGroupStatement;
import com.chenyang.druid.sql.dialect.mariadb.ast.statement.MariadbLoadDataInFileStatement;
import com.chenyang.druid.sql.dialect.mariadb.ast.statement.MariadbLoadXmlStatement;
import com.chenyang.druid.sql.dialect.mariadb.ast.statement.MariadbRenameTableStatement;
import com.chenyang.druid.sql.dialect.mariadb.ast.statement.MariadbUpdateStatement;
import com.chenyang.druid.sql.dialect.mariadb.visitor.DefaultMariadbASTVisitor;
import com.chenyang.druid.sql.dialect.mysql.ast.statement.MySqlKillStatement;
import com.chenyang.druid.sql.dialect.mysql.ast.statement.SQLAlterResourceGroupStatement;
import com.chenyang.druid.sql.dialect.mysql.ast.statement.SQLCreateResourceGroupStatement;
import java.util.List;
import util.sqlparse.visitor.common.Context;
import util.sqlparse.visitor.common.bean.SQLResult;
import util.sqlparse.visitor.common.bean.StatementType;
import util.sqlparse.visitor.common.scope.Scope;
import util.sqlparse.visitor.mariadb.SQLParser;

public class CompoundVisitor extends DefaultMariadbASTVisitor {
   private boolean debug = false;
   private Scope scope;

   public CompoundVisitor(Scope scope) {
      this.scope = scope;
   }

   public void perform(List<SQLStatement> statements) {
      if (statements != null && statements.size() != 0) {
         for(SQLStatement statement : statements) {
            statement.accept(this);
         }

         this.scope.reset();
      }
   }

   public boolean visit(SQLCreateProcedureStatement statement) {
      SQLStatement block = statement.getBlock();
      if (block == null) {
         return false;
      } else {
         block.accept(this);
         return false;
      }
   }

   public boolean visit(SQLCreateFunctionStatement statement) {
      SQLStatement block = statement.getBlock();
      if (block == null) {
         return false;
      } else {
         block.accept(this);
         return false;
      }
   }

   public boolean visit(SQLCreateTriggerStatement statement) {
      SQLStatement block = statement.getBody();
      if (block == null) {
         return false;
      } else {
         block.accept(this);
         return false;
      }
   }

   public boolean visit(MariadbCreateEventStatement statement) {
      SQLStatement block = statement.getEventBody();
      if (block == null) {
         return true;
      } else {
         this.parseStatement(block);
         return false;
      }
   }

   public boolean visit(MariadbAlterEventStatement statement) {
      SQLStatement block = statement.getEventBody();
      if (block == null) {
         return false;
      } else {
         this.parseStatement(block);
         return false;
      }
   }

   public boolean visit(SQLBlockStatement statement) {
      for(SQLStatement sqlStatement : statement.getStatementList()) {
         sqlStatement.accept(this);
      }

      return false;
   }

   public boolean visit(SQLSelectStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(MariadbSelectIntoStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLInsertStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(MariadbInsertStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLReturnStatement statement) {
      SQLExpr expr = statement.getExpr();
      if (expr instanceof SQLQueryExpr) {
         SQLQueryExpr queryExpr = (SQLQueryExpr)expr;
         SQLSelectStatement select = new SQLSelectStatement();
         select.setSelect(queryExpr.subQuery);
         select.accept(this);
      }

      return false;
   }

   public boolean visit(SQLUpdateStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(MariadbUpdateStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLDeleteStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(MariadbDeleteStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLReplaceStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLCreateTableStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLAlterTableStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLDropTableStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLCreateIndexStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLAlterIndexStatement statement) {
      return this.parseStatement(statement);
   }

   public void endVisit(MySqlKillStatement x) {
   }

   public boolean visit(MySqlKillStatement x) {
      return false;
   }

   public boolean visit(SQLCreateResourceGroupStatement x) {
      return false;
   }

   public void endVisit(SQLCreateResourceGroupStatement x) {
   }

   public boolean visit(SQLAlterResourceGroupStatement x) {
      return false;
   }

   public void endVisit(SQLAlterResourceGroupStatement x) {
   }

   public void endVisit(MariadbKillStatement x) {
   }

   public boolean visit(MariadbKillStatement x) {
      return false;
   }

   public boolean visit(SQLDropIndexStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLCreateViewStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLAlterViewStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLDropViewStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(MariadbLoadXmlStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(MariadbLoadDataInFileStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(MariadbRenameTableStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLAlterProcedureStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLDropProcedureStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLAlterFunctionStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLDropFunctionStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLDropTriggerStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLCallStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLGrantStatement statement) {
      return this.parseStatement(statement);
   }

   public boolean visit(SQLRevokeStatement statement) {
      return this.parseStatement(statement);
   }

   private boolean parseStatement(SQLStatement statement) {
      if (this.debug) {
         System.out.println(statement);
      }

      StatementType type = SQLParser.getStatementType(statement);
      switch (type) {
         case select:
         case update:
         case delete:
         case insert:
         case replace:
         case loadData:
         case loadXml:
         case truncate:
         case renameTable:
         case createTable:
         case alterTable:
         case dropTable:
         case createIndex:
         case alterIndex:
         case dropIndex:
         case createView:
         case alterView:
         case dropView:
         case createProc:
         case alterProc:
         case dropProc:
         case createFunction:
         case alterFunction:
         case dropFunction:
         case createTrigger:
         case dropTrigger:
         case createEvent:
         case alterEvent:
         case dropEvent:
         case revoke:
         case grant:
            this.parseResult(statement);
            return false;
         case callProc:
            statement.accept(this);
            break;
         default:
            statement.accept(this);
      }

      return true;
   }

   private void parseResult(SQLStatement statement) {
      SQLParser parser = new SQLParser();
      Context context = this.scope.context;
      DataBase dataBase = context.getDataBase();
      String schema = context.getSchema();
      SQLResult result = parser.parse(statement, dataBase, schema);
      this.scope.results.add(result);
   }

   public boolean visit(MariadbAlterTableAddExtPartition x) {
      return false;
   }

   public void endVisit(MariadbAlterTableAddExtPartition x) {
   }

   public boolean visit(MariadbListResourceGroupStatement x) {
      return false;
   }

   public void endVisit(MariadbListResourceGroupStatement x) {
   }

   public boolean visit(MariadbAlterTableDropExtPartition x) {
      return false;
   }

   public void endVisit(MariadbAlterTableDropExtPartition x) {
   }
}
