package com.chenyang.druid.sql.ast.expr;

import com.chenyang.druid.FastsqlException;
import com.chenyang.druid.sql.SQLUtils;
import com.chenyang.druid.sql.ast.SQLDataType;
import com.chenyang.druid.sql.ast.SQLDeclareItem;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLExprImpl;
import com.chenyang.druid.sql.ast.SQLName;
import com.chenyang.druid.sql.ast.SQLObject;
import com.chenyang.druid.sql.ast.SQLParameter;
import com.chenyang.druid.sql.ast.statement.SQLColumnDefinition;
import com.chenyang.druid.sql.ast.statement.SQLSelect;
import com.chenyang.druid.sql.ast.statement.SQLSelectItem;
import com.chenyang.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.chenyang.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.chenyang.druid.sql.ast.statement.SQLTableSource;
import com.chenyang.druid.sql.ast.statement.SQLUnionQuery;
import com.chenyang.druid.sql.ast.statement.SQLUnionQueryTableSource;
import com.chenyang.druid.sql.ast.statement.SQLWithSubqueryClause;
import com.chenyang.druid.sql.visitor.SQLASTVisitor;
import com.chenyang.druid.util.FnvHash;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

public final class SQLIdentifierExpr extends SQLExprImpl implements SQLName, Comparable<SQLIdentifierExpr> {
   protected String name;
   private long hashCode64;
   private SQLObject resolvedColumn;
   private SQLObject resolvedOwnerObject;

   public SQLIdentifierExpr() {
   }

   public SQLIdentifierExpr(String name) {
      this.name = name;
   }

   public SQLIdentifierExpr(String name, long hash_lower) {
      this.name = name;
      this.hashCode64 = hash_lower;
   }

   public String getSimpleName() {
      return this.name;
   }

   public String getLowerName() {
      return this.name == null ? null : this.name.toLowerCase();
   }

   public String getName() {
      return this.name;
   }

   public void setName(String name) {
      this.name = name;
      this.hashCode64 = 0L;
      if (this.parent instanceof SQLPropertyExpr) {
         SQLPropertyExpr propertyExpr = (SQLPropertyExpr)this.parent;
         propertyExpr.computeHashCode64();
      }

   }

   public long nameHashCode64() {
      return this.hashCode64();
   }

   public long hashCode64() {
      if (this.hashCode64 == 0L && this.name != null) {
         this.hashCode64 = FnvHash.hashCode64(this.name);
      }

      return this.hashCode64;
   }

   public void output(Appendable buf) {
      try {
         buf.append(this.name);
      } catch (IOException ex) {
         throw new FastsqlException("output error", ex);
      }
   }

   protected void accept0(SQLASTVisitor visitor) {
      visitor.visit(this);
      visitor.endVisit(this);
   }

   public int hashCode() {
      long value = this.hashCode64();
      return (int)(value ^ value >>> 32);
   }

   public boolean equals(Object obj) {
      if (!(obj instanceof SQLIdentifierExpr)) {
         return false;
      } else {
         SQLIdentifierExpr other = (SQLIdentifierExpr)obj;
         return this.hashCode64() == other.hashCode64();
      }
   }

   public String toString() {
      return this.name;
   }

   public SQLIdentifierExpr clone() {
      SQLIdentifierExpr x = new SQLIdentifierExpr(this.name, this.hashCode64);
      x.resolvedColumn = this.resolvedColumn;
      x.resolvedOwnerObject = this.resolvedOwnerObject;
      if (this.hint != null) {
         x.hint = this.hint.clone();
      }

      return x;
   }

   public SQLIdentifierExpr simplify() {
      String normalized = SQLUtils.normalize(this.name);
      return normalized != this.name ? new SQLIdentifierExpr(normalized, this.hashCode64) : this;
   }

   public String normalizedName() {
      return SQLUtils.normalize(this.name);
   }

   public SQLColumnDefinition getResolvedColumn() {
      if (this.resolvedColumn instanceof SQLColumnDefinition) {
         return (SQLColumnDefinition)this.resolvedColumn;
      } else {
         if (this.resolvedColumn instanceof SQLSelectItem) {
            SQLSelectItem selectItem = (SQLSelectItem)this.resolvedColumn;
            SQLExpr expr = selectItem.getExpr();
            if (expr instanceof SQLIdentifierExpr) {
               return ((SQLIdentifierExpr)expr).getResolvedColumn();
            }

            if (expr instanceof SQLPropertyExpr) {
               return ((SQLPropertyExpr)expr).getResolvedColumn();
            }
         }

         return null;
      }
   }

   public SQLSelectItem getResolvedSelectItem() {
      return this.resolvedColumn instanceof SQLSelectItem ? (SQLSelectItem)this.resolvedColumn : null;
   }

   public SQLObject getResolvedColumnObject() {
      return this.resolvedColumn;
   }

   public void setResolvedColumn(SQLColumnDefinition resolvedColumn) {
      this.resolvedColumn = resolvedColumn;
   }

   public void setResolvedColumn(SQLSelectItem selectItem) {
      this.resolvedColumn = selectItem;
   }

   public SQLTableSource getResolvedTableSource() {
      return this.resolvedOwnerObject instanceof SQLTableSource ? (SQLTableSource)this.resolvedOwnerObject : null;
   }

   public void setResolvedTableSource(SQLTableSource resolvedTableSource) {
      this.resolvedOwnerObject = resolvedTableSource;
   }

   public SQLObject getResolvedOwnerObject() {
      return this.resolvedOwnerObject;
   }

   public void setResolvedOwnerObject(SQLObject resolvedOwnerObject) {
      this.resolvedOwnerObject = resolvedOwnerObject;
   }

   public SQLParameter getResolvedParameter() {
      return this.resolvedColumn instanceof SQLParameter ? (SQLParameter)this.resolvedColumn : null;
   }

   public void setResolvedParameter(SQLParameter resolvedParameter) {
      this.resolvedColumn = resolvedParameter;
   }

   public SQLDeclareItem getResolvedDeclareItem() {
      return this.resolvedColumn instanceof SQLDeclareItem ? (SQLDeclareItem)this.resolvedColumn : null;
   }

   public void setResolvedDeclareItem(SQLDeclareItem resolvedDeclareItem) {
      this.resolvedColumn = resolvedDeclareItem;
   }

   public SQLDataType computeDataType() {
      SQLColumnDefinition resolvedColumn = this.getResolvedColumn();
      if (resolvedColumn != null) {
         return resolvedColumn.getDataType();
      } else if (this.resolvedColumn instanceof SQLSelectItem) {
         return ((SQLSelectItem)this.resolvedColumn).computeDataType();
      } else {
         SQLSelectQueryBlock queryBlock = null;
         if (this.resolvedOwnerObject instanceof SQLSubqueryTableSource) {
            SQLSelect select = ((SQLSubqueryTableSource)this.resolvedOwnerObject).getSelect();
            queryBlock = select.getFirstQueryBlock();
         } else if (this.resolvedOwnerObject instanceof SQLUnionQueryTableSource) {
            SQLUnionQuery union = ((SQLUnionQueryTableSource)this.resolvedOwnerObject).getUnion();
            queryBlock = union.getFirstQueryBlock();
         } else if (this.resolvedOwnerObject instanceof SQLWithSubqueryClause.Entry) {
            queryBlock = ((SQLWithSubqueryClause.Entry)this.resolvedOwnerObject).getSubQuery().getFirstQueryBlock();
         }

         if (queryBlock != null) {
            SQLSelectItem selectItem = queryBlock.findSelectItem(this.nameHashCode64());
            if (selectItem != null) {
               return selectItem.computeDataType();
            }
         }

         return null;
      }
   }

   public boolean nameEquals(String name) {
      return SQLUtils.nameEquals(this.name, name);
   }

   public List<SQLObject> getChildren() {
      return Collections.emptyList();
   }

   public static boolean matchIgnoreCase(SQLExpr expr, String name) {
      if (!(expr instanceof SQLIdentifierExpr)) {
         return false;
      } else {
         SQLIdentifierExpr ident = (SQLIdentifierExpr)expr;
         return ident.getName().equalsIgnoreCase(name);
      }
   }

   public int compareTo(SQLIdentifierExpr o) {
      return this.normalizedName().compareTo(o.normalizedName());
   }
}
