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

import com.alibaba.druid.FastsqlException;
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 java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;

public class SQLIntegerExpr extends SQLNumericLiteralExpr implements SQLValuableExpr, Comparable<SQLIntegerExpr> {
   public static final SQLDataType DATA_TYPE = new SQLDataTypeImpl("bigint");
   private Number number;
   private String type;

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

   public SQLIntegerExpr(Number number, SQLObject parent) {
      this.number = number;
      this.parent = parent;
   }

   public SQLIntegerExpr() {
   }

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

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

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

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

   public String getType() {
      return this.type;
   }

   public void setType(String type) {
      this.type = type;
   }

   public int hashCode() {
      int prime = 31;
      int result = 1;
      result = 31 * result + (this.number == null ? 0 : this.number.hashCode());
      return result;
   }

   public boolean equals(Object obj) {
      if (this == obj) {
         return true;
      } else if (obj == null) {
         return false;
      } else if (this.getClass() != obj.getClass()) {
         return false;
      } else {
         SQLIntegerExpr other = (SQLIntegerExpr)obj;
         if (this.number == null) {
            if (other.number != null) {
               return false;
            }
         } else if (!this.number.equals(other.number)) {
            return false;
         }

         return true;
      }
   }

   public Object getValue() {
      return this.number;
   }

   public SQLIntegerExpr clone() {
      return new SQLIntegerExpr(this.number);
   }

   public SQLDataType computeDataType() {
      return DATA_TYPE;
   }

   public void decrement() {
      if (this.number instanceof Integer) {
         this.number = Integer.valueOf(this.number.intValue()) - 1;
      } else {
         if (!(this.number instanceof Long)) {
            throw new FastsqlException("decrement not support.");
         }

         this.number = Long.valueOf(this.number.longValue()) - 1L;
      }

   }

   public static boolean isZero(SQLExpr expr) {
      if (!(expr instanceof SQLIntegerExpr)) {
         return false;
      } else {
         Number number = ((SQLIntegerExpr)expr).getNumber();
         return number != null && number.intValue() == 0;
      }
   }

   public static SQLIntegerExpr substract(SQLIntegerExpr a, SQLIntegerExpr b) {
      int val = a.number.intValue() - b.number.intValue();
      return new SQLIntegerExpr(val);
   }

   public static SQLIntegerExpr least(SQLIntegerExpr a, SQLIntegerExpr b) {
      if (a == null) {
         return b;
      } else {
         return a.number.intValue() <= b.number.intValue() ? a : b;
      }
   }

   public static SQLIntegerExpr greatst(SQLIntegerExpr a, SQLIntegerExpr b) {
      return a.number.intValue() >= b.number.intValue() ? a : b;
   }

   public static SQLIntegerExpr ofIntOrLong(long value) {
      return value >= -2147483648L && value <= 2147483647L ? new SQLIntegerExpr((int)value) : new SQLIntegerExpr(value);
   }

   public static SQLIntegerExpr add(long a, long b) {
      long r = a + b;
      return a > 0L && b > 0L && r <= 0L ? new SQLIntegerExpr(BigInteger.valueOf(a).add(BigInteger.valueOf(b))) : new SQLIntegerExpr(r);
   }

   public int compareTo(SQLIntegerExpr o) {
      if (this.number instanceof Integer && o.number instanceof Integer) {
         return ((Integer)this.number).compareTo((Integer)o.number);
      } else if (this.number instanceof Long && o.number instanceof Long) {
         return ((Long)this.number).compareTo((Long)o.number);
      } else if (this.number instanceof BigDecimal && o.number instanceof BigDecimal) {
         return ((BigDecimal)this.number).compareTo((BigDecimal)o.number);
      } else if (this.number instanceof Float && o.number instanceof Float) {
         return ((Float)this.number).compareTo((Float)o.number);
      } else {
         return this.number instanceof Double && o.number instanceof Double ? ((Float)this.number).compareTo((Float)o.number) : -1;
      }
   }
}
