package com.ripple.core.coretypes.uint;
import com.ripple.core.serialized.BinaryParser;
import com.ripple.core.serialized.BytesSink;
import com.ripple.core.serialized.SerializedType;
import com.ripple.core.serialized.TypeTranslator;
import com.ripple.encodings.common.B16;
import java.math.BigInteger;
abstract public class UInt<Subclass extends UInt> extends Number implements SerializedType, Comparable<UInt> {
private BigInteger value;
public static BigInteger Max8 = new BigInteger("256"),
Max16 = new BigInteger("65536"),
Max32 = new BigInteger("4294967296"),
Max64 = new BigInteger("18446744073709551616");
public BigInteger getMinimumValue() {
return BigInteger.ZERO;
}
public UInt(byte[] bytes) {
setValue(new BigInteger(1, bytes));
}
public UInt(BigInteger bi) {
setValue(bi);
}
public UInt(Number s) {
setValue(BigInteger.valueOf(s.longValue()));
}
public UInt(String s) {
setValue(new BigInteger(s));
}
public UInt(String s, int radix) {
setValue(new BigInteger(s, radix));
}
@Override
public String toString() {
return value.toString();
}
public UInt() {}
public abstract int getByteWidth();
public abstract Subclass instanceFrom(BigInteger n);
public boolean isValid(BigInteger n) {
return !((bitLength() / 8) > getByteWidth());
}
public Subclass add(UInt val) {
return instanceFrom(value.add(val.value));
}
public Subclass subtract(UInt val) {
return instanceFrom(value.subtract(val.value));
}
public Subclass multiply(UInt val) {
return instanceFrom(value.multiply(val.value));
}
public Subclass divide(UInt val) {
return instanceFrom(value.divide(val.value));
}
public Subclass or(UInt val) {
return instanceFrom(value.or(val.value));
}
public Subclass shiftLeft(int n) {
return instanceFrom(value.shiftLeft(n));
}
public Subclass shiftRight(int n) {
return instanceFrom(value.shiftRight(n));
}
public int bitLength() {
return value.bitLength();
}
public int compareTo(UInt val) {
return value.compareTo(val.value);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof UInt) {
return equals((UInt) obj);
}
else return super.equals(obj);
}
public boolean equals(UInt x) {
return value.equals(x.value);
}
public BigInteger min(BigInteger val) {
return value.min(val);
}
public BigInteger max(BigInteger val) {
return value.max(val);
}
public String toString(int radix) {
return value.toString(radix);
}
public byte[] toByteArray() {
int length = getByteWidth();
{
byte[] bytes = value.toByteArray();
if (bytes[0] == 0) {
if (bytes.length - 1 > length) {
throw new IllegalArgumentException("standard length exceeded for value");
}
byte[] tmp = new byte[length];
System.arraycopy(bytes, 1, tmp, tmp.length - (bytes.length - 1), bytes.length - 1);
return tmp;
} else {
if (bytes.length == length) {
return bytes;
}
if (bytes.length > length) {
throw new IllegalArgumentException("standard length exceeded for value");
}
byte[] tmp = new byte[length];
System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length);
return tmp;
}
}
}
abstract public Object value();
public BigInteger bigInteger(){
return value;
}
@Override
public int intValue() {
return value.intValue();
}
@Override
public long longValue() {
return value.longValue();
}
@Override
public double doubleValue() {
return value.doubleValue();
}
@Override
public float floatValue() {
return value.floatValue();
}
@Override
public byte byteValue() {
return value.byteValue();
}
@Override
public short shortValue() {
return value.shortValue();
}
public void setValue(BigInteger value) {
this.value = value;
}
public <T extends UInt> boolean lte(T sequence) {
return compareTo(sequence) < 1;
}
public boolean testBit(int f) {
// TODO, optimized ;) // move to Uint32
return value.testBit(f);
}
public boolean isZero() {
return value.signum() == 0;
}
static public abstract class UINTTranslator<T extends UInt> extends TypeTranslator<T> {
public abstract T newInstance(BigInteger i);
public abstract int byteWidth();
@Override
public T fromParser(BinaryParser parser, Integer hint) {
return newInstance(new BigInteger(1, parser.read(byteWidth())));
}
@Override
public Object toJSON(T obj) {
if (obj.getByteWidth() <= 4) {
return obj.longValue();
} else {
return toString(obj);
}
}
@Override
public T fromLong(long aLong) {
return newInstance(BigInteger.valueOf(aLong));
}
@Override
public T fromString(String value) {
int radix = byteWidth() <= 4 ? 10 : 16;
return newInstance(new BigInteger(value, radix));
}
@Override
public T fromInteger(int integer) {
return fromLong(integer);
}
@Override
public String toString(T obj) {
return B16.toString(obj.toByteArray());
}
@Override
public void toBytesSink(T obj, BytesSink to) {
to.add(obj.toByteArray());
}
}
}