package com.chenyang.druid.sql.repository;

import com.chenyang.druid.sql.ast.SQLDeclareItem;
import com.chenyang.druid.sql.ast.SQLObject;
import com.chenyang.druid.sql.ast.SQLOver;
import com.chenyang.druid.sql.ast.SQLParameter;
import com.chenyang.druid.sql.ast.expr.SQLAllColumnExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.chenyang.druid.sql.ast.expr.SQLCastExpr;
import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.chenyang.druid.sql.ast.expr.SQLPropertyExpr;
import com.chenyang.druid.sql.ast.statement.SQLAlterTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLBlockStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateFunctionStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateProcedureStatement;
import com.chenyang.druid.sql.ast.statement.SQLCreateTableStatement;
import com.chenyang.druid.sql.ast.statement.SQLDeleteStatement;
import com.chenyang.druid.sql.ast.statement.SQLExprTableSource;
import com.chenyang.druid.sql.ast.statement.SQLFetchStatement;
import com.chenyang.druid.sql.ast.statement.SQLForeignKeyImpl;
import com.chenyang.druid.sql.ast.statement.SQLIfStatement;
import com.chenyang.druid.sql.ast.statement.SQLInsertStatement;
import com.chenyang.druid.sql.ast.statement.SQLMergeStatement;
import com.chenyang.druid.sql.ast.statement.SQLReplaceStatement;
import com.chenyang.druid.sql.ast.statement.SQLSelect;
import com.chenyang.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.chenyang.druid.sql.ast.statement.SQLSelectStatement;
import com.chenyang.druid.sql.ast.statement.SQLTableSource;
import com.chenyang.druid.sql.ast.statement.SQLUnionQuery;
import com.chenyang.druid.sql.ast.statement.SQLUpdateStatement;
import com.chenyang.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.chenyang.druid.sql.visitor.SQLASTVisitor;
import java.util.HashMap;
import java.util.Map;

public interface SchemaResolveVisitor extends SQLASTVisitor {
   boolean isEnabled(Option var1);

   int getOptions();

   SchemaRepository getRepository();

   Context getContext();

   Context createContext(SQLObject var1);

   void popContext();

   boolean visit(SQLSelectStatement var1);

   boolean visit(SQLSelect var1);

   boolean visit(SQLWithSubqueryClause var1);

   boolean visit(SQLIfStatement var1);

   boolean visit(SQLCreateFunctionStatement var1);

   boolean visit(SQLExprTableSource var1);

   boolean visit(SQLSelectQueryBlock var1);

   boolean visit(SQLForeignKeyImpl var1);

   boolean visit(SQLIdentifierExpr var1);

   boolean visit(SQLPropertyExpr var1);

   boolean visit(SQLBinaryOpExpr var1);

   boolean visit(SQLAllColumnExpr var1);

   boolean visit(SQLCreateTableStatement var1);

   boolean visit(SQLUpdateStatement var1);

   boolean visit(SQLDeleteStatement var1);

   boolean visit(SQLAlterTableStatement var1);

   boolean visit(SQLInsertStatement var1);

   boolean visit(SQLParameter var1);

   boolean visit(SQLDeclareItem var1);

   boolean visit(SQLOver var1);

   boolean visit(SQLMethodInvokeExpr var1);

   boolean visit(SQLUnionQuery var1);

   boolean visit(SQLMergeStatement var1);

   boolean visit(SQLCreateProcedureStatement var1);

   boolean visit(SQLBlockStatement var1);

   boolean visit(SQLReplaceStatement var1);

   boolean visit(SQLCastExpr var1);

   boolean visit(SQLFetchStatement var1);

   public static enum Option {
      ResolveAllColumn,
      ResolveIdentifierAlias,
      CheckColumnAmbiguous;

      public final int mask = 1 << this.ordinal();

      public static int of(Option... options) {
         if (options == null) {
            return 0;
         } else {
            int value = 0;

            for(Option option : options) {
               value |= option.mask;
            }

            return value;
         }
      }
   }

   public static class Context {
      public final Context parent;
      public final SQLObject object;
      private SQLTableSource tableSource;
      private SQLTableSource from;
      private Map<Long, SQLTableSource> tableSourceMap;
      protected Map<Long, SQLDeclareItem> declares;

      public Context(SQLObject object, Context parent) {
         this.object = object;
         this.parent = parent;
      }

      public SQLTableSource getFrom() {
         return this.from;
      }

      public void setFrom(SQLTableSource from) {
         this.from = from;
      }

      public SQLTableSource getTableSource() {
         return this.tableSource;
      }

      public void setTableSource(SQLTableSource tableSource) {
         this.tableSource = tableSource;
      }

      public void addTableSource(long alias_hash, SQLTableSource tableSource) {
         if (this.tableSourceMap == null) {
            this.tableSourceMap = new HashMap();
         }

         this.tableSourceMap.put(alias_hash, tableSource);
      }

      protected void declare(SQLDeclareItem x) {
         if (this.declares == null) {
            this.declares = new HashMap();
         }

         this.declares.put(x.getName().nameHashCode64(), x);
      }

      protected SQLDeclareItem findDeclare(long nameHash) {
         return this.declares == null ? null : (SQLDeclareItem)this.declares.get(nameHash);
      }

      protected SQLTableSource findTableSource(long nameHash) {
         SQLTableSource table = null;
         if (this.tableSourceMap != null) {
            table = (SQLTableSource)this.tableSourceMap.get(nameHash);
         }

         return table;
      }

      protected SQLTableSource findTableSourceRecursive(long nameHash) {
         for(Context ctx = this; ctx != null; ctx = ctx.parent) {
            if (ctx.tableSourceMap != null) {
               SQLTableSource table = (SQLTableSource)ctx.tableSourceMap.get(nameHash);
               if (table != null) {
                  return table;
               }
            }
         }

         return null;
      }
   }
}
