package com.chenyang.druid.sql.dialect.spark.visitor;

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLName;
import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.expr.SQLPropertyExpr;
import com.chenyang.druid.sql.ast.statement.SQLCreateTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLInsertStatement;
import com.chenyang.druid.sql.ast.statement.SQLJoinTableSource;
import com.chenyang.druid.sql.dialect.spark.ast.expr.HiveRowFormat;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkColumnDef;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkColumnSpecExpr;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkDateExpr;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkDefProperty;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkIntervalExpr;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkNullsExpr;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkNumberExpr;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkSQLSubqueryTableSource;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkSampleExpr;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkSelectJoinTableSource;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkSelectPivot;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkSelectTableReference;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkTablePartition;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkTransformExpr;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkValuesExpr;
import com.chenyang.druid.sql.dialect.spark.ast.expr.SparkWithExpr;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkAlterDatabaseStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkAlterTableStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkAlterViewStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkCacheTableStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkCreateDatabaseStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkCreateTableStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkCreateViewStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkExplainStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkInsertStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkLoadStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkRefreshStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkRepairTableStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkShowCreateTableStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkShowDatabasesStatement;
import com.chenyang.druid.sql.dialect.spark.ast.statement.SparkShowTableStatement;
import com.chenyang.druid.sql.repository.SchemaRepository;
import com.chenyang.druid.sql.visitor.SchemaStatVisitor;
import com.chenyang.druid.stat.TableStat;
import com.chenyang.druid.util.FnvHash;

public class SparkSchemaStatVisitor extends SchemaStatVisitor implements SparkVisitor {
   public SparkSchemaStatVisitor() {
      super(DbType.spark);
      this.dbType = DbType.spark;
   }

   public SparkSchemaStatVisitor(SchemaRepository repository) {
      super(repository);
      this.dbType = DbType.spark;
   }

   public boolean visit(SparkCreateTableStatement x) {
      return super.visit((SQLCreateTableStatement)x);
   }

   public void endVisit(SparkCreateTableStatement x) {
      super.endVisit((SQLCreateTableStatement)x);
   }

   public boolean visit(SparkWithExpr x) {
      x.getStatement().accept(this);
      return false;
   }

   public void endVisit(SparkWithExpr x) {
   }

   public boolean visit(SparkValuesExpr x) {
      for(SQLExpr value : x.getValues()) {
         value.accept(this);
      }

      return false;
   }

   public void endVisit(SparkValuesExpr x) {
   }

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

   public void endVisit(SparkSelectPivot x) {
   }

   public boolean visit(SparkSelectPivot.Item x) {
      return false;
   }

   public void endVisit(SparkSelectPivot.Item x) {
   }

   public boolean visit(SparkSelectJoinTableSource x) {
      super.visit((SQLJoinTableSource)x);
      return false;
   }

   public void endVisit(SparkSelectJoinTableSource x) {
   }

   public boolean visit(SparkSQLSubqueryTableSource x) {
      this.accept(x.getSelect());
      this.accept(x.getPivot());
      this.accept(x.getFlashback());
      return false;
   }

   public void endVisit(SparkSQLSubqueryTableSource x) {
   }

   public boolean visit(SparkSelectTableReference x) {
      SQLExpr expr = x.getExpr();
      TableStat stat = this.getTableStat(x);
      if (expr instanceof SQLName) {
         if (((SQLName)expr).nameHashCode64() == FnvHash.Constants.DUAL) {
            return false;
         } else {
            if (expr instanceof SQLPropertyExpr) {
               SQLPropertyExpr propertyExpr = (SQLPropertyExpr)expr;
               if (this.isSubQueryOrParamOrVariant(propertyExpr)) {
                  return false;
               }
            } else if (expr instanceof SQLIdentifierExpr) {
               SQLIdentifierExpr identifierExpr = (SQLIdentifierExpr)expr;
               if (this.isSubQueryOrParamOrVariant(identifierExpr)) {
                  return false;
               }
            }

            TableStat.Mode mode = this.getMode();
            switch (mode) {
               case Insert:
                  stat.incrementInsertCount();
                  break;
               case Select:
                  stat.incrementSelectCount();
            }

            return false;
         }
      } else {
         return false;
      }
   }

   public void endVisit(SparkSelectTableReference x) {
   }

   public boolean visit(SparkNullsExpr x) {
      x.getExpr().accept(this);
      return false;
   }

   public void endVisit(SparkNullsExpr x) {
   }

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

   public void endVisit(SparkDefProperty x) {
   }

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

   public void endVisit(SparkColumnDef x) {
   }

   public boolean visit(SparkTransformExpr x) {
      this.accept(x.getArguments());
      return false;
   }

   public void endVisit(SparkTransformExpr x) {
   }

   public boolean visit(HiveRowFormat.RowFormatSede x) {
      return false;
   }

   public void endVisit(HiveRowFormat.RowFormatSede x) {
   }

   public boolean visit(SparkTransformExpr.CommandScriptDef x) {
      return false;
   }

   public void endVisit(SparkTransformExpr.CommandScriptDef x) {
   }

   public boolean visit(HiveRowFormat.RowFormatDelimitor x) {
      return false;
   }

   public void endVisit(HiveRowFormat.RowFormatDelimitor x) {
   }

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

   public void endVisit(HiveRowFormat x) {
   }

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

   public void endVisit(SparkTablePartition x) {
   }

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

   public void endVisit(SparkDateExpr x) {
   }

   public boolean visit(SparkInsertStatement x) {
      this.visit((SQLInsertStatement)x);
      if (x.getQuery() == null) {
         return false;
      } else {
         x.getQueryTable().accept(this);
         return false;
      }
   }

   public void endVisit(SparkInsertStatement x) {
   }

   public boolean visit(SparkInsertStatement.SparkFormat x) {
      return false;
   }

   public void endVisit(SparkInsertStatement.SparkFormat x) {
   }

   public boolean visit(SparkLoadStatement x) {
      x.getTable().accept(this);
      return false;
   }

   public void endVisit(SparkLoadStatement x) {
   }

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

   public void endVisit(SparkSampleExpr x) {
   }

   public boolean visit(SparkIntervalExpr x) {
      for(SparkIntervalExpr.SparkIntervalItem interval : x.getIntervals()) {
         interval.accept(this);
      }

      return false;
   }

   public void endVisit(SparkIntervalExpr x) {
   }

   public boolean visit(SparkIntervalExpr.SparkIntervalItem x) {
      x.getValue().accept(this);
      return false;
   }

   public void endVisit(SparkIntervalExpr.SparkIntervalItem x) {
   }

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

   public void endVisit(SparkNumberExpr x) {
   }

   public void endVisit(SparkExplainStatement x) {
   }

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

   public void endVisit(SparkShowDatabasesStatement x) {
   }

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

   public void endVisit(SparkRepairTableStatement x) {
   }

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

   public void endVisit(SparkCreateViewStatement x) {
   }

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

   public void endVisit(SparkShowCreateTableStatement x) {
   }

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

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

   public void endVisit(SparkAlterDatabaseStatement x) {
   }

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

   public void endVisit(SparkAlterTableStatement x) {
   }

   public boolean visit(SparkAlterTableStatement.SparkAlterTableReNameTo x) {
      return false;
   }

   public void endVisit(SparkAlterTableStatement.SparkAlterTableReNameTo x) {
   }

   public boolean visit(SparkAlterTableStatement.SparkAlterTableAddColumns x) {
      return false;
   }

   public void endVisit(SparkAlterTableStatement.SparkAlterTableAddColumns x) {
   }

   public boolean visit(SparkAlterTableStatement.SparkAlterTableDropColumns x) {
      return false;
   }

   public void endVisit(SparkAlterTableStatement.SparkAlterTableDropColumns x) {
   }

   public boolean visit(SparkAlterTableStatement.SparkAlterTableRenameColumn x) {
      return false;
   }

   public void endVisit(SparkAlterTableStatement.SparkAlterTableRenameColumn x) {
   }

   public boolean visit(SparkAlterTableStatement.SparkAlterTableChangeColumn x) {
      return false;
   }

   public void endVisit(SparkAlterTableStatement.SparkAlterTableChangeColumn x) {
   }

   public boolean visit(SparkAlterTableStatement.SparkAlterTableReplaceColumns x) {
      return false;
   }

   public void endVisit(SparkAlterTableStatement.SparkAlterTableReplaceColumns x) {
   }

   public boolean visit(SparkAlterTableStatement.SparkAlterTableAddOrDropPartition x) {
      return false;
   }

   public void endVisit(SparkAlterTableStatement.SparkAlterTableAddOrDropPartition x) {
   }

   public boolean visit(SparkAlterTableStatement.SparkAlterTableSetUnsetProps x) {
      return false;
   }

   public void endVisit(SparkAlterTableStatement.SparkAlterTableSetUnsetProps x) {
   }

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

   public void endVisit(SparkAlterViewStatement x) {
   }

   public boolean visit(SparkAlterViewStatement.SparkAlterViewReNameTo x) {
      return false;
   }

   public void endVisit(SparkAlterViewStatement.SparkAlterViewReNameTo x) {
   }

   public boolean visit(SparkAlterViewStatement.SparkAlterViewSetUnsetProps x) {
      return false;
   }

   public void endVisit(SparkAlterViewStatement.SparkAlterViewSetUnsetProps x) {
   }

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

   public void endVisit(SparkColumnSpecExpr x) {
   }

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

   public void endVisit(SparkCreateDatabaseStatement x) {
   }

   public boolean visit(SparkCacheTableStatement x) {
      x.getTable().accept(this);
      if (x.getQuery() != null) {
         x.getQuery().accept(this);
      }

      return false;
   }

   public void endVisit(SparkCacheTableStatement x) {
   }

   public boolean visit(SparkCacheTableStatement.SparkCacheTableStatementQuery x) {
      if (x.getTableQuery() != null) {
         x.getTableQuery().accept(this);
      }

      if (x.getFromQuery() != null) {
         x.getFromQuery().accept(this);
      }

      if (x.getQuery() != null) {
         x.getQuery().accept(this);
      }

      return false;
   }

   public void endVisit(SparkCacheTableStatement.SparkCacheTableStatementQuery x) {
   }

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

   public void endVisit(SparkRefreshStatement x) {
   }

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

   public void endVisit(SparkShowTableStatement x) {
   }
}
