package com.alibaba.druid.sql.visitor;

import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLLateralViewTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUnionQueryTableSource;
import com.alibaba.druid.sql.ast.statement.SQLValuesTableSource;
import com.alibaba.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.alibaba.druid.util.FnvHash;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

public class SQLTableAliasCollectVisitor extends SQLASTVisitorAdapter {
   protected Map<Long, SQLTableSource> tableSourceMap = new LinkedHashMap();
   protected volatile int seed;

   public boolean visit(SQLLateralViewTableSource x) {
      String alias = x.getAlias();
      if (alias == null) {
         return false;
      } else {
         long hashCode64 = FnvHash.hashCode64(alias);
         this.tableSourceMap.put(hashCode64, x);
         return true;
      }
   }

   public boolean visit(SQLValuesTableSource x) {
      String alias = x.getAlias();
      if (alias == null) {
         return false;
      } else {
         long hashCode64 = FnvHash.hashCode64(alias);
         this.tableSourceMap.put(hashCode64, x);
         return true;
      }
   }

   public boolean visit(SQLUnionQueryTableSource x) {
      String alias = x.getAlias();
      if (alias == null) {
         x.getUnion().accept(this);
         return false;
      } else {
         long hashCode64 = FnvHash.hashCode64(alias);
         this.tableSourceMap.put(hashCode64, x);
         return true;
      }
   }

   public boolean visit(SQLSubqueryTableSource x) {
      String alias = x.getAlias();
      if (alias == null) {
         x.getSelect().accept(this);
         return false;
      } else {
         long hashCode64 = FnvHash.hashCode64(alias);
         this.tableSourceMap.put(hashCode64, x);
         return true;
      }
   }

   public boolean visit(SQLJoinTableSource x) {
      String alias = x.getAlias();
      if (alias == null) {
         return true;
      } else {
         long hashCode64 = FnvHash.hashCode64(alias);
         this.tableSourceMap.put(hashCode64, x);
         return true;
      }
   }

   public boolean visit(SQLWithSubqueryClause.Entry x) {
      String alias = x.getAlias();
      if (alias == null) {
         return true;
      } else {
         long hashCode64 = FnvHash.hashCode64(alias);
         this.tableSourceMap.put(hashCode64, x);
         return true;
      }
   }

   public boolean visit(SQLExprTableSource x) {
      String alias = x.getAlias();
      if (alias == null) {
         SQLExpr expr = x.getExpr();
         if (expr instanceof SQLName) {
            long hashCode64 = ((SQLName)expr).nameHashCode64();
            this.tableSourceMap.put(hashCode64, x);
            return false;
         } else {
            return true;
         }
      } else {
         return true;
      }
   }

   public Collection<SQLTableSource> getTableSources() {
      return this.tableSourceMap.values();
   }

   public SQLTableSource getTableSource(long hashCode64) {
      return (SQLTableSource)this.tableSourceMap.get(hashCode64);
   }

   public boolean containsTableSource(String alias) {
      if (alias == null) {
         return false;
      } else {
         long hashCode64 = FnvHash.hashCode64(alias);
         return this.tableSourceMap.containsKey(hashCode64);
      }
   }

   public String genAlias(int seed) {
      String alias = null;

      while(seed < 100) {
         String str = "G" + seed++;
         if (!this.containsTableSource(str)) {
            alias = str;
            this.seed = seed;
            break;
         }
      }

      return alias;
   }

   public int getSeed() {
      return this.seed;
   }
}
