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

import com.alibaba.druid.sql.ast.SQLDataType;
import com.alibaba.druid.sql.ast.SQLDataTypeImpl;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import com.alibaba.druid.util.Utils;
import java.math.BigDecimal;

public class SQLNumberExpr extends SQLNumericLiteralExpr implements SQLValuableExpr {
   public static final SQLDataType DATA_TYPE_NUMBER = new SQLDataTypeImpl("number");
   public static final SQLDataType DATA_TYPE_DOUBLE = new SQLDataTypeImpl("double");
   public static final SQLDataType DATA_TYPE_BIGINT;
   private Number number;
   private char[] chars;

   public SQLNumberExpr() {
   }

   public SQLNumberExpr(Number number) {
      this.number = number;
   }

   public SQLNumberExpr(char[] chars, SQLObject parent) {
      this.chars = chars;
      this.parent = parent;
   }

   public SQLNumberExpr(char[] chars) {
      this.chars = chars;
   }

   public Number getNumber() {
      if (this.chars != null && this.number == null) {
         boolean exp = false;

         for(int i = 0; i < this.chars.length; ++i) {
            char ch = this.chars[i];
            if (ch == 'e' || ch == 'E') {
               exp = true;
            }
         }

         if (exp) {
            this.number = Double.parseDouble(new String(this.chars));
         } else {
            this.number = new BigDecimal(this.chars);
         }
      }

      return this.number;
   }

   public String getLiteral() {
      return this.chars == null ? null : new String(this.chars);
   }

   public Number getValue() {
      return this.getNumber();
   }

   public void setNumber(Number number) {
      this.number = number;
      this.chars = null;
   }

   public void output(StringBuilder buf) {
      if (this.chars != null) {
         buf.append(this.chars);
      } else {
         buf.append(this.number.toString());
      }

   }

   public void output(StringBuffer buf) {
      if (this.chars != null) {
         buf.append(this.chars);
      } else {
         buf.append(this.number.toString());
      }

   }

   public void output(Appendable buf) {
      if (buf instanceof StringBuilder) {
         this.output((StringBuilder)buf);
      } else if (buf instanceof StringBuffer) {
         this.output((StringBuffer)buf);
      } else {
         super.output(buf);
      }

   }

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

   public int hashCode() {
      Number number = this.getNumber();
      return number == null ? 0 : number.hashCode();
   }

   public boolean equals(Object obj) {
      if (this.chars != null && this.number == null) {
         this.number = new BigDecimal(this.chars);
      }

      if (this == obj) {
         return true;
      } else if (obj == null) {
         return false;
      } else if (this.getClass() != obj.getClass()) {
         return false;
      } else {
         SQLNumberExpr other = (SQLNumberExpr)obj;
         return Utils.equals(this.getNumber(), other.getNumber());
      }
   }

   public SQLNumberExpr clone() {
      SQLNumberExpr x = new SQLNumberExpr();
      x.chars = this.chars;
      x.number = this.number;
      return x;
   }

   public SQLDataType computeDataType() {
      return DATA_TYPE_NUMBER;
   }

   public static boolean isZero(SQLExpr x) {
      if (x instanceof SQLNumberExpr) {
         Number number = ((SQLNumberExpr)x).getNumber();
         if (number instanceof Integer) {
            return number.intValue() == 0;
         }

         if (number instanceof Long) {
            return number.longValue() == 0L;
         }
      }

      return false;
   }

   public static boolean isOne(SQLExpr x) {
      if (x instanceof SQLNumberExpr) {
         Number number = ((SQLNumberExpr)x).getNumber();
         if (number instanceof Integer) {
            return number.intValue() == 1;
         }

         if (number instanceof Long) {
            return number.longValue() == 1L;
         }
      }

      return false;
   }

   static {
      DATA_TYPE_BIGINT = SQLIntegerExpr.DATA_TYPE;
   }
}
