package util.sqlparse.visitor.common.scope;

import bean.Column;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLObject;
import com.chenyang.druid.sql.ast.SQLOrderBy;
import com.chenyang.druid.sql.ast.SQLOver;
import com.chenyang.druid.sql.ast.expr.SQLAllColumnExpr;
import com.chenyang.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.chenyang.druid.sql.ast.expr.SQLCaseExpr;
import com.chenyang.druid.sql.ast.expr.SQLExistsExpr;
import com.chenyang.druid.sql.ast.expr.SQLIdentifierExpr;
import com.chenyang.druid.sql.ast.expr.SQLInSubQueryExpr;
import com.chenyang.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.chenyang.druid.sql.ast.expr.SQLNullExpr;
import com.chenyang.druid.sql.ast.expr.SQLPropertyExpr;
import com.chenyang.druid.sql.ast.expr.SQLQueryExpr;
import com.chenyang.druid.sql.ast.statement.SQLSelectItem;
import com.chenyang.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.chenyang.druid.sql.ast.statement.SQLSelectQuery;
import com.chenyang.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.chenyang.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.chenyang.druid.sql.ast.statement.SQLUnionQuery;
import com.chenyang.druid.sql.dialect.oracle.ast.expr.OracleSysdateExpr;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import util.sqlparse.visitor.common.Context;
import util.sqlparse.visitor.common.ID;
import util.sqlparse.visitor.common.Owner;
import util.sqlparse.visitor.common.ScopeDialector;
import util.sqlparse.visitor.common.bean.SQLResult;
import util.sqlparse.visitor.common.memo.FieldMemo;
import util.sqlparse.visitor.common.memo.TableMemo;
import util.sqlparse.visitor.common.memo.ValueMemo;
import util.sqlparse.visitor.common.utils.SeqMap;

public class Scope extends ID {
   public static final int SUCCESS_CODE = 0;
   private static final String ALL_COLUMN_START = "*";
   public static final int ERROR_CODE = -1;
   public List<SQLResult> results = new ArrayList();
   public Context context;
   protected Scope current = this;
   public Scope parent;
   public SQLObject ref;
   protected List<Scope> children = new ArrayList();
   protected Set<String> schemas = new HashSet(6);
   private boolean fieldState;
   public boolean fromField;
   public boolean top = false;
   public boolean join = false;
   public ScopeDialector dialector;
   protected SeqMap<String, FieldMemo> fieldMap = new SeqMap();
   protected SeqMap<String, TableMemo> tableMap = new SeqMap();
   protected List<ValueMemo> values = new ArrayList();
   private boolean debug = false;
   public boolean union = false;
   public boolean isolated = true;
   public boolean isCheckIsolated = false;
   public ReplaceInfo replaceInfo;

   public boolean isFieldState() {
      return this.fieldState;
   }

   public void openFieldState() {
      this.fieldState = true;
   }

   public void closeFieldState() {
      this.fieldState = false;
   }

   public void addTable(TableMemo table) {
      String qualified = table.getQualifiedName();
      if (!this.tableMap.containsKey(qualified)) {
         this.tableMap.put(qualified, table);
      }

   }

   public void addTableCheckConflict(TableMemo table) {
      this.removeTableConflict(table);
      this.addTable(table);
   }

   public void removeTableConflict(TableMemo table) {
      String qualified = table.getQualifiedName();
      if (this.tableMap.containsKey(qualified)) {
         TableMemo existTable = (TableMemo)this.tableMap.get(qualified);
         if (!existTable.atom) {
            return;
         }

         if (this.isEqual(existTable.name, existTable.alias) && !this.isEqual(table.name, table.alias)) {
            this.tableMap.remove(qualified);
            this.removeTableScopeRelation(qualified);
            if (existTable.atom) {
               this.current.context.getTableMap().remove(existTable.getAtomName());
            }
         }
      }

   }

   private void removeTableScopeRelation(String qualified) {
      TableScope tableScope = this.current.getNearestParentTableScope();
      if (tableScope != null) {
         TableMemo parentTable = tableScope.table;
         if (parentTable != null) {
            for(int i = 0; i < parentTable.getChildren().size(); ++i) {
               TableMemo temp = (TableMemo)parentTable.getChildren().get(i);
               if (this.isEqual(temp.getQualifiedName(), qualified)) {
                  parentTable.getChildren().remove(i);
               }
            }
         }
      }

   }

   public FieldMemo addField(FieldMemo field) {
      field.scope = this;
      new FieldMemo();
      if (this.dialector.addField(field)) {
         return field;
      } else {
         String qualifiedName = field.getQualifiedName();
         if (!this.fieldMap.containsKey(qualifiedName)) {
            this.fieldMap.put(qualifiedName, field);
            return field;
         } else {
            FieldMemo fieldInfo = (FieldMemo)this.fieldMap.get(qualifiedName);
            if (field.isSelectItem) {
               fieldInfo.isSelectItem = true;
               fieldInfo.id = field.id;
            }

            if (field.atom) {
               fieldInfo.atom = field.atom;
            }

            fieldInfo.exprs.addAll(field.exprs);
            fieldInfo.aliasFields.addAll(field.aliasFields);
            field.children.remove(fieldInfo);
            this.mergeChildren(field, fieldInfo);
            return fieldInfo;
         }
      }
   }

   private void mergeChildren(FieldMemo field, FieldMemo fieldInfo) {
      Iterator var3 = field.children.iterator();

      while(var3.hasNext()) {
         FieldMemo temp = (FieldMemo)var3.next();
         FieldMemo find = null;
         Iterator var6 = fieldInfo.children.iterator();

         while(var6.hasNext()) {
            FieldMemo x = (FieldMemo)var6.next();
            if (this.isEqual(x.getQualifiedName(), temp.getQualifiedName())) {
               find = x;
               break;
            }
         }

         if (find == null && fieldInfo != temp && !this.isEqual(fieldInfo.getQualifiedName(), temp.getQualifiedName())) {
            fieldInfo.children.add(temp);
         }
      }

   }

   public void enterScope(Scope scope) {
      this.current.append(scope);
      if (this.debug) {
         System.out.println("[E]" + this.current.id + "->" + scope.id + "     " + scope.ref.getClass().toString() + "\n     " + scope.ref);
      }

      this.current = scope;
      if (this.dialector != null) {
         this.current.dialector = this.dialector.clone(this.current);
      }

   }

   public void reset() {
      this.current = this;
   }

   public void enterScope(SQLObject sqlObject) {
      Iterator var2 = this.current.children.iterator();

      Scope child;
      do {
         if (!var2.hasNext()) {
            return;
         }

         child = (Scope)var2.next();
      } while(!child.ref.equals(sqlObject));

      if (this.debug) {
         System.out.println("[E]" + this.current.id + "->" + child.id + "     " + child.ref.getClass().toString() + "\n     " + child.ref);
      }

      this.current = child;
   }

   public Scope getScope(SQLObject sqlObject) {
      Iterator var2 = this.current.children.iterator();

      Scope child;
      do {
         if (!var2.hasNext()) {
            return null;
         }

         child = (Scope)var2.next();
      } while(!child.ref.equals(sqlObject));

      return child;
   }

   public void exitScope() {
      if (this.debug) {
         if (this.current.parent != null) {
            System.out.println("[X]" + this.current.id + "->" + this.current.parent.id + "     " + this.current.ref.getClass().toString());
         } else {
            System.out.println("[X]" + this.current.id + "->root");
         }
      }

      this.current = this.current.parent;
      if (this.current == null) {
         this.current = this;
      }

   }

   public void append(Scope child) {
      this.children.add(child);
      child.context = this.context;
      child.parent = this.current;
      child.isCheckIsolated = this.isCheckIsolated;
   }

   public Scope getCurrent() {
      return this.current;
   }

   public String getDefaultSchema() {
      return this.context.getSchema();
   }

   public boolean isPrimitive(SQLExpr expr) {
      if (expr instanceof SQLSubqueryTableSource) {
         return false;
      } else {
         Iterator var3;
         SQLExpr sqlExpr;
         if (expr instanceof SQLMethodInvokeExpr) {
            List<SQLExpr> exprs = ((SQLMethodInvokeExpr)expr).getArguments();
            if (exprs.size() > 0) {
               var3 = exprs.iterator();

               while(var3.hasNext()) {
                  sqlExpr = (SQLExpr)var3.next();
                  if (!this.isPrimitive(sqlExpr)) {
                     return false;
                  }
               }
            }
         }

         if (expr instanceof SQLCaseExpr) {
            SQLCaseExpr caseExpr = (SQLCaseExpr)expr;
            var3 = caseExpr.getItems().iterator();

            while(var3.hasNext()) {
               SQLCaseExpr.Item item = (SQLCaseExpr.Item)var3.next();
               if (!this.isPrimitive(item.getConditionExpr()) && this.isPrimitive(item.getValueExpr())) {
                  return false;
               }
            }
         }

         if (!(expr instanceof SQLBinaryOpExpr)) {
            if (expr instanceof SQLInSubQueryExpr) {
               return false;
            } else if (expr instanceof SQLExistsExpr) {
               return false;
            } else {
               return !(expr instanceof SQLQueryExpr);
            }
         } else {
            SQLBinaryOpExpr opExpr = (SQLBinaryOpExpr)expr;
            SQLExpr left = opExpr.getLeft();
            sqlExpr = opExpr.getRight();
            return this.isPrimitive(left) && this.isPrimitive(sqlExpr);
         }
      }
   }

   public boolean isAllColumn(SQLExpr x) {
      if (x instanceof SQLAllColumnExpr) {
         return true;
      } else {
         if (x instanceof SQLPropertyExpr) {
            SQLPropertyExpr prop = (SQLPropertyExpr)x;
            if (prop.getName() == null) {
               return false;
            }

            if (prop.getName().equals("*")) {
               return true;
            }
         }

         if (x instanceof SQLIdentifierExpr) {
            SQLIdentifierExpr identifierExpr = (SQLIdentifierExpr)x;
            if (identifierExpr.getName().equals("*")) {
               return true;
            }
         }

         return false;
      }
   }

   public TableMemo getTable(SQLObject x) {
      List<Scope> feet = new ArrayList();
      TableMemo table = this.getTableRecursive(x, feet);
      if (table == null) {
         if (this.tableMap.size() <= 0) {
            return this.getTableDownStream(x, feet);
         }

         Iterator var4 = this.tableMap.entrySet().iterator();
         if (var4.hasNext()) {
            Map.Entry<String, TableMemo> stringTableMemoEntry = (Map.Entry)var4.next();
            return (TableMemo)stringTableMemoEntry.getValue();
         }
      }

      return table;
   }

   private TableMemo getTableDownStream(SQLObject x, List<Scope> feet) {
      Iterator var4 = this.children.iterator();

      TableMemo table;
      do {
         if (!var4.hasNext()) {
            return null;
         }

         Scope child = (Scope)var4.next();
         table = child.getTable(x);
         if (table != null) {
            return table;
         }

         table = this.getTableDownStream(x, feet);
      } while(table == null);

      return null;
   }

   private TableMemo getTableRecursive(SQLObject x, List<Scope> feet) {
      String name = null;
      SQLExpr ownerExpr = null;
      if (x instanceof SQLIdentifierExpr) {
         SQLIdentifierExpr idExpr = (SQLIdentifierExpr)x;
         name = idExpr.getName();
      } else if (x instanceof SQLPropertyExpr) {
         SQLPropertyExpr propExpr = (SQLPropertyExpr)x;
         name = propExpr.getName();
         ownerExpr = propExpr.getOwner();
      } else if (x instanceof SQLNullExpr) {
         SQLNullExpr nullExpr = (SQLNullExpr)x;
         name = nullExpr.toString();
      }

      Owner owner = this.getOwner(ownerExpr);
      TableMemo table;
      Iterator var9;
      if (owner.table != null) {
         String ns = owner.getQualifiedName();
         table = null;
         Iterator var18 = this.tableMap.values().iterator();

         while(var18.hasNext()) {
            TableMemo z = (TableMemo)var18.next();
            if (this.isEqual(z.alias, owner.table)) {
               table = z;
               break;
            }
         }

         if (table != null) {
            return table;
         } else {
            List<Scope> subScopes = new ArrayList();
            var9 = this.children.iterator();

            Scope sub;
            while(var9.hasNext()) {
               sub = (Scope)var9.next();
               if (!sub.fromField) {
                  subScopes.add(sub);
               }
            }

            var9 = subScopes.iterator();

            do {
               do {
                  if (!var9.hasNext()) {
                     if (this.parent != null) {
                        return this.parent.getTableRecursive(x, feet);
                     }

                     return null;
                  }

                  sub = (Scope)var9.next();
               } while(sub.isCheckIsolated && sub.isolated);
            } while(!sub.tableMap.containsKey(ns));

            return (TableMemo)sub.tableMap.get(ns);
         }
      } else {
         Iterator var6 = this.tableMap.values().iterator();

         while(var6.hasNext()) {
            table = (TableMemo)var6.next();
            if (table.atom) {
               List<Column> columns = this.context.getColumns(table.schema, table.name);
               var9 = columns.iterator();

               while(var9.hasNext()) {
                  Column column = (Column)var9.next();
                  if (this.isEqual(column.getColumnName(), name)) {
                     return table;
                  }
               }
            }

            if (table.refTable != null && table.refTable.scope != null) {
               FieldMemo fieldRef = table.refTable.scope.getFieldByAlias(name);
               if (fieldRef != null) {
                  return table;
               }
            }
         }

         if (this.children != null && this.children.size() > 0) {
            List<TableMemo> path = new ArrayList();
            Feet ft = this.getFieldByAliasBranch(name, path);
            if (ft != null && ft.path.size() > 0) {
               return (TableMemo)ft.path.get(0);
            }
         }

         if (this.parent != null) {
            return this.parent.getTableRecursive(x, feet);
         } else {
            return null;
         }
      }
   }

   private Feet getFieldByAliasBranch(String name, List<TableMemo> path) {
      Iterator var3 = this.children.iterator();

      while(true) {
         Scope child;
         do {
            do {
               do {
                  if (!var3.hasNext()) {
                     return null;
                  }

                  child = (Scope)var3.next();
               } while(child.top);
            } while(child.fromField);
         } while(child.isCheckIsolated && child.isolated);

         Feet feet;
         if (child.fieldMap.size() > 0) {
            FieldMemo field = child.getFieldByAliasInternal(name);
            if (field != null) {
               feet = new Feet();
               feet.field = field;
               feet.path = path;
               return feet;
            }
         } else if (child.children.size() > 0) {
            List<TableMemo> paths = new ArrayList(path);
            if (child instanceof TableScope) {
               paths.add(((TableScope)child).table);
            }

            feet = child.getFieldByAliasBranch(name, paths);
            if (feet != null) {
               return feet;
            }
         }
      }
   }

   private FieldMemo getFieldByAliasInternal(String name) {
      if (name == null) {
         return null;
      } else {
         Iterator var2 = this.fieldMap.values().iterator();

         FieldMemo value;
         do {
            if (!var2.hasNext()) {
               return null;
            }

            value = (FieldMemo)var2.next();
         } while(!this.isEqual(name, value.alias));

         return value;
      }
   }

   public ValueMemo getFieldValueInfo(SQLExpr expr) {
      if (expr == null) {
         return null;
      } else {
         FieldMemo field = this.getFieldByExpr(expr);
         if (field != null) {
            ValueMemo value = new ValueMemo();
            value.field = field;
            value.ref = expr;
            return value;
         } else {
            return null;
         }
      }
   }

   public List<SQLExpr> getSubFieldExprs(SQLExpr x) {
      List<SQLExpr> exprs = new ArrayList();
      this.getSubFieldExprs(x, exprs);
      return exprs;
   }

   private void getSubFieldExprs(SQLObject x, List<SQLExpr> exprs) {
      if (x != null) {
         if (!(x instanceof SQLSelectQueryBlock)) {
            if (!(x instanceof SQLInSubQueryExpr)) {
               if (!(x instanceof SQLExistsExpr)) {
                  if (!(x instanceof SQLSelectQuery)) {
                     if (x instanceof SQLPropertyExpr) {
                        exprs.add((SQLPropertyExpr)x);
                     } else if (x instanceof SQLIdentifierExpr) {
                        exprs.add((SQLIdentifierExpr)x);
                     } else if (x instanceof OracleSysdateExpr) {
                        exprs.add((OracleSysdateExpr)x);
                     } else if (x instanceof SQLOver) {
                        SQLOver over = (SQLOver)x;
                        this.getSubFieldExprsByExprs(over.getPartitionBy(), exprs);
                        this.getSQLOrderExprs(over.getOrderBy(), exprs);
                        this.getSQLOrderExprs(over.getDistributeBy(), exprs);
                        this.getSQLOrderExprs(over.getSortBy(), exprs);
                        this.getSubFieldExprs(over.getWindowingBetweenBegin());
                        this.getSubFieldExprs(over.getWindowingBetweenEnd());
                     } else if (x instanceof SQLCaseExpr.Item) {
                        SQLCaseExpr.Item item = (SQLCaseExpr.Item)x;
                        this.getSubFieldExprs(item.getConditionExpr(), exprs);
                        this.getSubFieldExprs(item.getValueExpr(), exprs);
                     } else if (x instanceof SQLExpr) {
                        SQLExpr expr = (SQLExpr)x;
                        if (expr.getChildren() != null && expr.getChildren().size() > 0) {
                           Iterator var4 = expr.getChildren().iterator();

                           while(var4.hasNext()) {
                              SQLObject sqlObject = (SQLObject)var4.next();
                              this.getSubFieldExprs(sqlObject, exprs);
                           }
                        }
                     }

                  }
               }
            }
         }
      }
   }

   private void getSQLOrderExprs(SQLOrderBy order, List<SQLExpr> exprs) {
      if (order != null) {
         Iterator var3 = order.getItems().iterator();

         while(var3.hasNext()) {
            SQLSelectOrderByItem item = (SQLSelectOrderByItem)var3.next();
            exprs.addAll(this.getSubFieldExprs(item.getExpr()));
         }
      }

   }

   private void getSubFieldExprsByExprs(List<SQLExpr> sqlExprs, List<SQLExpr> exprs) {
      if (sqlExprs != null) {
         Iterator var3 = sqlExprs.iterator();

         while(var3.hasNext()) {
            SQLExpr sqlExpr = (SQLExpr)var3.next();
            this.getSubFieldExprs(sqlExpr, exprs);
         }
      }

   }

   public Owner getOwner(SQLObject x) {
      Owner owner = new Owner();
      if (x == null) {
         owner.schema = this.getDefaultSchema();
      }

      if (x instanceof SQLIdentifierExpr) {
         SQLIdentifierExpr idExpr = (SQLIdentifierExpr)x;
         owner.table = this.dialector.wrap(idExpr.getName());
         owner.schema = this.dialector.wrap(this.getDefaultSchema());
      } else if (x instanceof SQLPropertyExpr) {
         SQLPropertyExpr propExpr = (SQLPropertyExpr)x;
         owner.table = this.dialector.wrap(propExpr.getName());
         owner.schema = this.dialector.wrap(propExpr.getOwnerName());
      } else if (x instanceof SQLAllColumnExpr) {
         owner.table = null;
         owner.schema = this.dialector.wrap(this.getDefaultSchema());
      }

      return owner;
   }

   public Owner getAllOwner(SQLExpr e) {
      Owner owner = new Owner();
      owner.schema = this.getDefaultSchema();
      if (e instanceof SQLAllColumnExpr) {
         owner.schema = this.context.getSchema();
      } else if (e instanceof SQLPropertyExpr) {
         SQLPropertyExpr propExpr = (SQLPropertyExpr)e;
         SQLExpr expr = propExpr.getOwner();
         if (expr instanceof SQLIdentifierExpr) {
            owner.alias = ((SQLIdentifierExpr)expr).getName();
         } else {
            owner.alias = ((SQLPropertyExpr)expr).getName();
            owner.schema = ((SQLPropertyExpr)expr).getOwnerName();
         }
      }

      return owner;
   }

   public List<FieldMemo> expandAllColumns(TableMemo table, boolean isSub) {
      List<FieldMemo> fields = new FieldNameList();
      if (this.dialector != null) {
         boolean continueExpand = this.dialector.expandAllColumns(table, isSub, fields);
         if (!continueExpand) {
            return fields;
         }
      }

      Iterator var5;
      ArrayList fieldMemos;
      Iterator var17;
      if (table == null) {
         fieldMemos = new ArrayList();
         var5 = this.tableMap.orderValues().iterator();

         TableMemo topTable;
         while(var5.hasNext()) {
            topTable = (TableMemo)var5.next();
            if (topTable.refTable != null) {
               fieldMemos.add(topTable);
            }
         }

         if (fieldMemos.size() > 0) {
            var5 = fieldMemos.iterator();

            while(var5.hasNext()) {
               topTable = (TableMemo)var5.next();
               List<FieldMemo> subFields = this.cloneFields(this.expandAllColumns(topTable.refTable, topTable.refTable.isSub), topTable, true);
               fields.addAll(subFields);
            }
         }

         List<TableMemo> memTables = new ArrayList();
         var17 = this.tableMap.orderValues().iterator();

         TableMemo memTable;
         while(var17.hasNext()) {
            memTable = (TableMemo)var17.next();
            if (!memTable.isSub && memTable.refTable == null) {
               memTables.add(memTable);
            }
         }

         if (memTables.size() > 0) {
            var17 = memTables.iterator();

            while(var17.hasNext()) {
               memTable = (TableMemo)var17.next();
               List<FieldMemo> subFields = this.cloneFields(this.expandAllColumns(memTable, memTable.isSub), memTable, false);
               fields.addAll(subFields);
            }
         }

         var17 = this.children.iterator();

         while(var17.hasNext()) {
            Scope child = (Scope)var17.next();
            if (!child.fromField) {
               child.expandScopeColumns(fields);
            }
         }
      } else {
         Iterator var12;
         List tbFields;
         if (!table.isSub) {
            if (table.refTable != null) {
               var12 = table.refTable.getChildren().iterator();

               while(var12.hasNext()) {
                  TableMemo childTable = (TableMemo)var12.next();
                  if (childTable.topTable) {
                     List<FieldMemo> subFields = new ArrayList();
                     List<FieldMemo> cloneFields = new ArrayList();
                     Iterator var23 = childTable.scope.fieldMap.orderValues().iterator();

                     FieldMemo field;
                     while(var23.hasNext()) {
                        field = (FieldMemo)var23.next();
                        if (field.isSelectItem) {
                           cloneFields.add(field);
                        }
                     }

                     var23 = cloneFields.iterator();

                     while(var23.hasNext()) {
                        field = (FieldMemo)var23.next();
                        FieldMemo cloneField = field.copy();
                        cloneField.alias = field.alias;
                        cloneField.table = table;
                        cloneField.refField = field;
                        subFields.add(cloneField);
                     }

                     fields.addAll(subFields);
                     return fields;
                  }
               }
            } else {
               FieldMemo tbField;
               if (!table.atom && table.scope.fieldMap.size() > 0) {
                  fieldMemos = new ArrayList();
                  var5 = table.scope.fieldMap.orderValues().iterator();

                  while(var5.hasNext()) {
                     tbField = (FieldMemo)var5.next();
                     if (tbField.isSelectItem) {
                        fieldMemos.add(tbField);
                     }
                  }

                  fields.addAll(fieldMemos);
                  return fields;
               }

               tbFields = this.dialector.getColumns(table);
               if (tbFields != null && tbFields.size() > 0) {
                  var5 = tbFields.iterator();

                  while(var5.hasNext()) {
                     tbField = (FieldMemo)var5.next();
                     fields.add(tbField);
                  }
               } else {
                  List<Column> columns = this.context.getColumns(table.schema, table.name);
                  if (columns != null && columns.size() > 0) {
                     var17 = columns.iterator();

                     while(var17.hasNext()) {
                        Column column = (Column)var17.next();
                        FieldMemo field = new FieldMemo();
                        field.table = table;
                        field.alias = this.current.dialector.wrapColumn(table.schema, table.name, column.getColumnName());
                        field.name = this.current.dialector.wrapColumn(table.schema, table.name, column.getColumnName());
                        field.isSelectItem = true;
                        fields.add(field);
                     }
                  }
               }
            }
         } else if (table.topTable) {
            tbFields = this.getParentTableFields(table, table.scope);
            fields.addAll(tbFields);
         } else {
            var12 = table.scope.children.iterator();

            while(var12.hasNext()) {
               Scope child = (Scope)var12.next();
               child.expandScopeColumns(fields);
               if (table.scope.union) {
                  break;
               }
            }
         }
      }

      return fields;
   }

   private List<FieldMemo> cloneFields(List<FieldMemo> fields, TableMemo table, boolean isRefField) {
      if (fields != null && fields.size() != 0) {
         List<FieldMemo> cloneFields = new ArrayList();

         FieldMemo cloneField;
         for(Iterator var5 = fields.iterator(); var5.hasNext(); cloneFields.add(cloneField)) {
            FieldMemo fieldMemo = (FieldMemo)var5.next();
            cloneField = fieldMemo.copy();
            cloneField.alias = fieldMemo.alias;
            cloneField.table = table;
            if (isRefField) {
               cloneField.refField = fieldMemo;
            }
         }

         return cloneFields;
      } else {
         return new ArrayList();
      }
   }

   private void expandScopeColumns(List<FieldMemo> fields) {
      if (this.fieldMap.size() > 0) {
         TableScope scope = this.getNearestParentTableScope();
         List<FieldMemo> selfFields = new ArrayList();
         Iterator var4 = this.fieldMap.orderValues().iterator();

         while(var4.hasNext()) {
            FieldMemo x = (FieldMemo)var4.next();
            if (x.isSelectItem) {
               selfFields.add(x);
            }
         }

         if (scope != null) {
            List<FieldMemo> subFields = this.cloneFields(selfFields, scope.table, false);
            fields.addAll(subFields);
            return;
         }
      }

      Iterator var6 = this.children.iterator();

      while(var6.hasNext()) {
         Scope child = (Scope)var6.next();
         child.expandScopeColumns(fields);
         if (this.union) {
            break;
         }
      }

   }

   public TableMemo getParentTable(String schemaName, String table) {
      boolean childrenTop = false;
      boolean parentChildrenTop = false;
      if (this.parent != null) {
         Iterator var5 = this.parent.children.iterator();

         Scope x;
         while(var5.hasNext()) {
            x = (Scope)var5.next();
            if (x.top) {
               parentChildrenTop = true;
               break;
            }
         }

         var5 = this.children.iterator();

         while(var5.hasNext()) {
            x = (Scope)var5.next();
            if (x.top) {
               childrenTop = true;
               break;
            }
         }

         String name = this.dialector.wrap(schemaName + "." + table);
         if (this.parent.tableMap.containsKey(name)) {
            return (TableMemo)this.parent.tableMap.get(name);
         }

         TableMemo memo;
         if (parentChildrenTop) {
            memo = this.parent.getParentTopTable(name);
            if (memo != null && memo.topTable) {
               return memo;
            }
         } else if (childrenTop) {
            memo = this.current.getParentTopTable(name);
            if (memo != null && memo.topTable) {
               return memo;
            }
         }

         if (this.parent.parent != null) {
            return this.parent.getParentTable(schemaName, table);
         }
      }

      return null;
   }

   private TableMemo getParentTopTable(String name) {
      boolean childrenTop = false;
      Iterator var3 = this.children.iterator();

      while(true) {
         Scope child;
         do {
            if (!var3.hasNext()) {
               return null;
            }

            child = (Scope)var3.next();
         } while(!child.top);

         Iterator var5 = child.children.iterator();

         while(var5.hasNext()) {
            Scope x = (Scope)var5.next();
            if (x.top) {
               childrenTop = true;
            }
         }

         TableMemo memo;
         if (child.tableMap.size() == 0) {
            if (childrenTop) {
               memo = child.getParentTopTable(name);
               if (memo != null && memo.topTable) {
                  return memo;
               }
            }
         } else {
            memo = (TableMemo)child.tableMap.get(name);
            if (memo != null && memo.topTable) {
               return memo;
            }
         }

         childrenTop = false;
      }
   }

   private List<FieldMemo> getBranchTableFields(TableMemo table, Scope parent) {
      List<FieldMemo> fields = new ArrayList();
      Iterator var4 = parent.children.iterator();

      label40:
      while(var4.hasNext()) {
         Scope child = (Scope)var4.next();
         if (child.fieldMap.size() <= 0) {
            return this.getBranchTableFields(table, child);
         }

         Iterator var6 = child.fieldMap.orderValues().iterator();

         while(true) {
            FieldMemo branchField;
            do {
               do {
                  if (!var6.hasNext()) {
                     continue label40;
                  }

                  branchField = (FieldMemo)var6.next();
               } while(!branchField.isSelectItem);
            } while((branchField.table == null || !branchField.table.equals(table)) && !branchField.tables.contains(table));

            FieldMemo field = branchField.copy();
            field.alias = branchField.alias;
            field.table = table;
            fields.add(field);
         }
      }

      return fields;
   }

   private List<FieldMemo> getParentTableFields(TableMemo table, Scope scope) {
      List<FieldMemo> fields = new ArrayList();
      if (scope == null) {
         return fields;
      } else {
         if (scope.fieldMap.size() > 0) {
            Iterator var4 = scope.fieldMap.orderValues().iterator();

            while(true) {
               FieldMemo branchField;
               do {
                  if (!var4.hasNext()) {
                     return fields;
                  }

                  branchField = (FieldMemo)var4.next();
               } while((branchField.table == null || !branchField.table.equals(table)) && !branchField.tables.contains(table));

               FieldMemo field = branchField.copy();
               field.children.addAll(branchField.children);
               field.isSelectItem = true;
               field.refField = branchField;
               field.table = table;
               fields.add(field);
            }
         } else if (scope.parent != null) {
            fields.addAll(this.getParentTableFields(table, scope.parent));
         }

         return fields;
      }
   }

   public List<TableMemo> getBranchTables() {
      List<TableMemo> tables = new ArrayList();
      if (this.tableMap.size() > 0) {
         tables.addAll(this.tableMap.values());
      } else {
         Iterator var2 = this.children.iterator();

         while(var2.hasNext()) {
            Scope child = (Scope)var2.next();
            tables.addAll(child.getBranchTables());
         }
      }

      return tables;
   }

   public List<FieldMemo> getBranchAllFields(TableMemo table) {
      List<FieldMemo> fields = new ArrayList();
      Iterator var3 = this.children.iterator();

      while(true) {
         label22:
         while(var3.hasNext()) {
            Scope child = (Scope)var3.next();
            if (child.fieldMap.size() > 0) {
               Iterator var5 = child.fieldMap.values().iterator();

               while(true) {
                  FieldMemo value;
                  do {
                     if (!var5.hasNext()) {
                        continue label22;
                     }

                     value = (FieldMemo)var5.next();
                  } while(table != null && !value.tables.contains(table));

                  FieldMemo field = value.copy();
                  field.table = table;
                  fields.add(field);
               }
            } else {
               fields.addAll(child.getBranchAllFields(table));
            }
         }

         return fields;
      }
   }

   public TableScope getNearestParentTableScope() {
      for(Scope cursor = this; cursor != null; cursor = cursor.parent) {
         if (cursor instanceof TableScope) {
            return (TableScope)cursor;
         }
      }

      return null;
   }

   public void getSubBranchFields(List<FieldMemo> fields) {
      if (this.children.size() != 0) {
         Iterator var2 = this.children.iterator();

         while(var2.hasNext()) {
            Scope child = (Scope)var2.next();
            if (child instanceof ClauseScope) {
               fields.addAll(child.getFieldMap().values());
            } else {
               child.getSubBranchFields(fields);
            }
         }

      }
   }

   public FieldMemo getFieldByExpr(SQLExpr expr) {
      FieldMemo field = null;
      Iterator var3 = this.fieldMap.values().iterator();

      while(var3.hasNext()) {
         FieldMemo value = (FieldMemo)var3.next();
         boolean found = false;
         Iterator var6 = value.exprs.iterator();

         while(var6.hasNext()) {
            SQLObject sqlObject = (SQLObject)var6.next();
            if (sqlObject == expr) {
               found = true;
               break;
            }
         }

         if (found) {
            field = value;
            break;
         }
      }

      if (field != null) {
         return field;
      } else {
         return this.parent != null ? this.parent.getFieldByExpr(expr) : null;
      }
   }

   public FieldMemo getFieldByName(String name) {
      FieldMemo field = this.getFieldByNameInternal(name);
      if (field != null) {
         return field;
      } else {
         field = this.getFieldByNameBranch(name);
         if (field != null) {
            return field;
         } else {
            if (this.parent != null) {
               field = this.getFieldByNameTop(name);
            }

            return field;
         }
      }
   }

   public FieldMemo getFieldByAlias(String name) {
      if (name != null && name.length() != 0) {
         Iterator var2 = this.fieldMap.values().iterator();

         FieldMemo x;
         do {
            if (!var2.hasNext()) {
               return null;
            }

            x = (FieldMemo)var2.next();
         } while(x.alias == null || !this.isEqual(x.alias, name));

         return x;
      } else {
         return null;
      }
   }

   private FieldMemo getFieldByNameTop(String name) {
      Scope child = null;
      Iterator var3 = this.parent.children.iterator();

      while(var3.hasNext()) {
         Scope x = (Scope)var3.next();
         if (x.top) {
            child = x;
            break;
         }
      }

      if (child != null) {
         FieldMemo field = child.getFieldByNameTopBranch(name);
         if (field != null) {
            return field;
         }
      }

      return this.parent.parent != null ? this.parent.getFieldByNameTop(name) : null;
   }

   private FieldMemo getFieldByNameTopBranch(String name) {
      if (!this.top) {
         return null;
      } else {
         FieldMemo field = this.getFieldByNameInternal(name);
         if (field != null) {
            return field;
         } else {
            if (this.fieldMap.size() == 0 && this.children.size() > 0) {
               Iterator var3 = this.children.iterator();

               while(var3.hasNext()) {
                  Scope child = (Scope)var3.next();
                  if (child.top) {
                     field = child.getFieldByNameTopBranch(name);
                     if (field != null) {
                        return field;
                     }
                  }
               }
            }

            return null;
         }
      }
   }

   private FieldMemo getFieldByNameInternal(String name) {
      Iterator var2 = this.fieldMap.values().iterator();

      FieldMemo x;
      do {
         if (!var2.hasNext()) {
            return null;
         }

         x = (FieldMemo)var2.next();
      } while(!x.isSelectItem || !this.isEqual(x.name, name));

      return x;
   }

   private FieldMemo getFieldByNameBranch(String name) {
      FieldMemo field = null;
      Iterator var3 = this.children.iterator();

      while(var3.hasNext()) {
         Scope child = (Scope)var3.next();
         if (!child.top) {
            if (child.fieldMap.size() > 0) {
               field = child.getFieldByNameInternal(name);
               if (field != null) {
                  return field;
               }
            } else if (child.children.size() > 0) {
               field = child.getFieldByNameBranch(name);
               if (field != null) {
                  return field;
               }
            }
         }
      }

      return null;
   }

   public void getFieldsByExprs(List<SQLExpr> exprs, List<FieldMemo> fields) {
      Iterator var3 = exprs.iterator();

      while(var3.hasNext()) {
         SQLExpr expr = (SQLExpr)var3.next();
         FieldMemo field = this.getFieldByExpr(expr);
         if (field == null) {
            if (this.debug) {
               System.out.println("null" + expr.getParent().toString());
            }
         } else {
            fields.add(field);
         }
      }

   }

   public List<FieldMemo> getSubRelationFields(FieldMemo field) {
      List<FieldMemo> relations = this.getSubRelationFieldsInternal(field);
      if (field.table != null && field.table.refTable != null) {
         FieldMemo refField = field.table.refTable.scope.getFieldByNameTopBranch(field.alias);
         if (refField != null) {
            relations.add(refField);
         }
      }

      FieldMemo relation;
      if (relations != null) {
         for(Iterator var5 = relations.iterator(); var5.hasNext(); relation.outside = true) {
            relation = (FieldMemo)var5.next();
         }
      }

      return relations;
   }

   private List<FieldMemo> getSubRelationFieldsInternal(FieldMemo field) {
      if (field.table == null) {
         return new ArrayList();
      } else if (!field.table.isSub && !field.complex) {
         return new ArrayList();
      } else {
         List<FieldMemo> list = new ArrayList();
         if (!field.complex) {
            if (field.table == null) {
               return new ArrayList();
            } else {
               Scope tableScope;
               if (field.table.scope.isCheckIsolated && field.table.scope.join) {
                  tableScope = this.getTableScope(field);
                  if (tableScope != null) {
                     return this.getJoinSubRelationFieldsInteral(tableScope, field);
                  }
               }

               if (field.table.scope.isCheckIsolated) {
                  tableScope = this.getTableScope(field);
                  if (tableScope != null && tableScope.union) {
                     this.getUnionSubRelationFieldsInteral(tableScope, field, (List)list);
                     return (List)list;
                  }
               }

               list = this.getSubRelationFieldsInteral(field.table.scope, field);
               return (List)list;
            }
         } else {
            Iterator var7 = this.children.iterator();

            while(true) {
               while(true) {
                  Scope child;
                  do {
                     if (!var7.hasNext()) {
                        return (List)list;
                     }

                     child = (Scope)var7.next();
                  } while(child.isCheckIsolated && child.isolated);

                  if (child.fieldMap.size() == 0) {
                     ((List)list).addAll(child.getSubRelationFieldsInternal(field));
                  } else {
                     Iterator var5 = child.fieldMap.values().iterator();

                     while(var5.hasNext()) {
                        FieldMemo value = (FieldMemo)var5.next();
                        if (value.alias.equals(field.name)) {
                           ((List)list).add(value);
                        }
                     }
                  }
               }
            }
         }
      }
   }

   private Scope getTableScope(FieldMemo field) {
      Scope tableScope = null;
      Iterator var3 = field.table.scope.children.iterator();

      while(var3.hasNext()) {
         Scope child = (Scope)var3.next();
         if (field.table.ref != null && child.ref != null && this.isEqual(field.table.ref.toString(), child.ref.toString())) {
            tableScope = child;
         }
      }

      return tableScope;
   }

   private List<FieldMemo> getSubRelationFieldsInteral(Scope scope, FieldMemo field) {
      List<FieldMemo> list = new ArrayList();
      Iterator var4 = scope.children.iterator();

      while(true) {
         while(true) {
            Scope child;
            do {
               if (!var4.hasNext()) {
                  return list;
               }

               child = (Scope)var4.next();
            } while(child.isCheckIsolated && child.isolated);

            if (child.isCheckIsolated && child.union) {
               this.getUnionSubRelationFieldsInteral(child, field, list);
            } else if (child.fieldMap.size() == 0) {
               list.addAll(child.getSubRelationFieldsInteral(child, field));
            } else {
               Iterator var6 = child.fieldMap.values().iterator();

               while(var6.hasNext()) {
                  FieldMemo value = (FieldMemo)var6.next();
                  if (field.name != null && scope.dialector.isColumnEqual(field.name, value.alias) && value.isSelectItem) {
                     list.add(value);
                  }
               }
            }
         }
      }
   }

   private List<FieldMemo> getJoinSubRelationFieldsInteral(Scope scope, FieldMemo field) {
      List<FieldMemo> list = new ArrayList();
      Iterator var4 = scope.children.iterator();

      do {
         Scope child;
         do {
            if (!var4.hasNext()) {
               return list;
            }

            child = (Scope)var4.next();
         } while(child.isCheckIsolated && child.isolated);

         if (child.union) {
            this.getUnionSubRelationFieldsInteral(child, field, list);
         } else if (child.fieldMap.size() == 0) {
            list.addAll(child.getJoinSubRelationFieldsInteral(child, field));
         } else {
            Iterator var6 = child.fieldMap.values().iterator();

            while(var6.hasNext()) {
               FieldMemo value = (FieldMemo)var6.next();
               if (field.name != null && field.name.equals(value.alias) && value.isSelectItem) {
                  list.add(value);
               }
            }
         }
      } while(list.size() <= 0);

      return list;
   }

   private int getUnionSubRelationFieldsInteral(Scope scope, FieldMemo field, List<FieldMemo> list) {
      int loop = 0;
      int index = 0;

      while(true) {
         while(scope.children.size() != loop) {
            Scope child = (Scope)scope.children.get(loop);
            if (child.isCheckIsolated && child.isolated) {
               ++loop;
            } else {
               if (child.fieldMap.size() == 0) {
                  index = child.getUnionSubRelationFieldsInteral(child, field, list);
                  if (index < 0) {
                     return index;
                  }
               } else {
                  List<FieldMemo> fields = new ArrayList(child.fieldMap.values());
                  if (loop == 0) {
                     index = this.getIndex(field, list, fields);
                     if (index < 0) {
                        return index;
                     }
                  } else if (fields.size() > index) {
                     list.add(fields.get(index));
                  }
               }

               ++loop;
            }
         }

         return index;
      }
   }

   private int getIndex(FieldMemo field, List<FieldMemo> list, List<FieldMemo> fields) {
      for(int j = 0; j < fields.size(); ++j) {
         FieldMemo value = (FieldMemo)fields.get(j);
         if (field.name != null && field.name.equals(value.alias) && value.isSelectItem) {
            list.add(value);
            return j;
         }
      }

      return -1;
   }

   public boolean getSubFieldsForWith(List<FieldMemo> fields) {
      Iterator var2 = this.children.iterator();

      Scope child;
      do {
         if (!var2.hasNext()) {
            var2 = this.children.iterator();

            do {
               if (!var2.hasNext()) {
                  return false;
               }

               child = (Scope)var2.next();
            } while(!child.getSubFieldsForWith(fields));

            return true;
         }

         child = (Scope)var2.next();
      } while(child.getFieldMap().size() <= 0);

      List<FieldMemo> childFields = new ArrayList();
      Iterator var5 = child.getFieldMap().orderValues().iterator();

      while(var5.hasNext()) {
         FieldMemo x = (FieldMemo)var5.next();
         if (x.isSelectItem) {
            childFields.add(x);
         }
      }

      fields.addAll(childFields);
      return true;
   }

   public void getUnionFieldsForWithRecursive(List<List<FieldMemo>> list) {
      Iterator var2 = this.children.iterator();

      while(true) {
         while(var2.hasNext()) {
            Scope child = (Scope)var2.next();
            if (child.ref instanceof SQLUnionQuery) {
               child.getUnionFieldsForWithRecursive(list);
            } else if (child.getFieldMap().size() > 0) {
               List<FieldMemo> childFields = new ArrayList();
               Iterator var5 = child.getFieldMap().orderValues().iterator();

               while(var5.hasNext()) {
                  FieldMemo x = (FieldMemo)var5.next();
                  if (x.isSelectItem) {
                     childFields.add(x);
                  }
               }

               list.add(childFields);
            }
         }

         return;
      }
   }

   public void getUnionFieldsForWith(List<List<FieldMemo>> unionFieldlist) {
      if (this.children.size() > 0) {
         Scope tableScopChild = (Scope)this.children.get(0);
         if (tableScopChild != null && tableScopChild.union) {
            tableScopChild.getUnionFieldsForWithRecursive(unionFieldlist);
         }
      }

   }

   public boolean isFromField(SQLObject x) {
      for(Scope pCursor = this.parent; pCursor != null; pCursor = pCursor.parent) {
         if (pCursor.fromField) {
            return true;
         }
      }

      for(SQLObject cursor = x.getParent(); cursor != null; cursor = cursor.getParent()) {
         if (cursor instanceof SQLSelectItem) {
            return true;
         }
      }

      return false;
   }

   public final List<ValueMemo> getValues() {
      return this.values;
   }

   public SeqMap<String, FieldMemo> getFieldMap() {
      return this.fieldMap;
   }

   public SeqMap<String, TableMemo> getTableMap() {
      return this.tableMap;
   }

   public final List<Scope> getChildren() {
      return this.children;
   }

   public boolean isCaseSensitive() {
      return this.context.getDataBase() != null ? this.context.getDataBase().isCaseSensitive() : false;
   }

   private boolean isEqual(String name1, String name2) {
      return this.dialector.isEqual(name1, name2);
   }

   public ReplaceInfo getReplaceInfo() {
      return this.replaceInfo;
   }

   public void setReplaceInfo(ReplaceInfo replaceInfo) {
      this.replaceInfo = replaceInfo;
   }

   class FieldNameList extends ArrayList<FieldMemo> {
      Set<String> names = new HashSet();

      public boolean add(FieldMemo field) {
         if (!this.names.contains(field.alias)) {
            super.add(field);
            this.names.add(field.alias);
         }

         return true;
      }

      public boolean addAll(Collection<? extends FieldMemo> fields) {
         if (fields != null && fields.size() != 0) {
            Iterator var2 = fields.iterator();

            while(var2.hasNext()) {
               FieldMemo field = (FieldMemo)var2.next();
               this.add(field);
            }

            return true;
         } else {
            return true;
         }
      }
   }

   class Feet {
      FieldMemo field;
      List<TableMemo> path;
   }
}
