package qora.assets;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import database.DBSet;
import qora.account.Account;
import qora.crypto.Base58;
public class Asset {
private static final int OWNER_LENGTH = 25;
private static final int NAME_SIZE_LENGTH = 4;
private static final int DESCRIPTION_SIZE_LENGTH = 4;
private static final int QUANTITY_LENGTH = 8;
private static final int DIVISIBLE_LENGTH = 1;
private static final int REFERENCE_LENGTH = 64;
private Account owner;
private String name;
private String description;
private long quantity;
private boolean divisible;
private byte[] reference;
public Asset(Account owner, String name, String description, long quantity, boolean divisible, byte[] reference)
{
this.owner = owner;
this.name = name;
this.description = description;
this.quantity = quantity;
this.divisible = divisible;
this.reference = reference;
}
//GETTERS/SETTERS
public Account getOwner() {
return this.owner;
}
public String getName() {
return this.name;
}
public String getDescription() {
return this.description;
}
public Long getQuantity() {
return this.quantity;
}
public boolean isDivisible() {
return this.divisible;
}
public byte[] getReference() {
return this.reference;
}
public long getKey() {
return DBSet.getInstance().getIssueAssetMap().get(this.reference);
}
public boolean isConfirmed() {
return DBSet.getInstance().getIssueAssetMap().contains(this.reference);
}
//PARSE
public static Asset parse(byte[] data) throws Exception
{
int position = 0;
//READ OWNER
byte[] ownerBytes = Arrays.copyOfRange(data, position, position + OWNER_LENGTH);
Account owner = new Account(Base58.encode(ownerBytes));
position += OWNER_LENGTH;
//READ NAME
byte[] nameLengthBytes = Arrays.copyOfRange(data, position, position + NAME_SIZE_LENGTH);
int nameLength = Ints.fromByteArray(nameLengthBytes);
position += NAME_SIZE_LENGTH;
if(nameLength < 1 || nameLength > 400)
{
throw new Exception("Invalid name length");
}
byte[] nameBytes = Arrays.copyOfRange(data, position, position + nameLength);
String name = new String(nameBytes, StandardCharsets.UTF_8);
position += nameLength;
//READ DESCRIPTION
byte[] descriptionLengthBytes = Arrays.copyOfRange(data, position, position + DESCRIPTION_SIZE_LENGTH);
int descriptionLength = Ints.fromByteArray(descriptionLengthBytes);
position += DESCRIPTION_SIZE_LENGTH;
if(descriptionLength < 1 || descriptionLength > 4000)
{
throw new Exception("Invalid description length");
}
byte[] descriptionBytes = Arrays.copyOfRange(data, position, position + descriptionLength);
String description = new String(descriptionBytes, StandardCharsets.UTF_8);
position += descriptionLength;
//READ QUANTITY
byte[] quantityBytes = Arrays.copyOfRange(data, position, position + QUANTITY_LENGTH);
long quantity = Longs.fromByteArray(quantityBytes);
position += QUANTITY_LENGTH;
//READ DIVISABLE
byte[] divisibleBytes = Arrays.copyOfRange(data, position, position + DIVISIBLE_LENGTH);
boolean divisable = divisibleBytes[0] == 1;
position += DIVISIBLE_LENGTH;
//READ REFERENCE
byte[] reference = Arrays.copyOfRange(data, position, position + REFERENCE_LENGTH);
//RETURN
return new Asset(owner, name, description, quantity, divisable, reference);
}
/*@SuppressWarnings("unchecked")
public JSONObject toJson()
{
//GET BASE
JSONObject name = new JSONObject();
//ADD NAME/VALUE/OWNER
name.put("name", this.getName());
name.put("value", this.getValue());
name.put("owner", this.getOwner().getAddress());
return name;
}*/
public byte[] toBytes(boolean includeReference)
{
byte[] data = new byte[0];
//WRITE OWNER
try
{
data = Bytes.concat(data , Base58.decode(this.owner.getAddress()));
}
catch(Exception e)
{
//DECODE EXCEPTION
}
//WRITE NAME SIZE
byte[] nameBytes = this.name.getBytes(StandardCharsets.UTF_8);
int nameLength = nameBytes.length;
byte[] nameLengthBytes = Ints.toByteArray(nameLength);
data = Bytes.concat(data, nameLengthBytes);
//WRITE NAME
data = Bytes.concat(data, nameBytes);
//WRITE DESCRIPTION SIZE
byte[] descriptionBytes = this.description.getBytes(StandardCharsets.UTF_8);
int descriptionLength = descriptionBytes.length;
byte[] descriptionLengthBytes = Ints.toByteArray(descriptionLength);
data = Bytes.concat(data, descriptionLengthBytes);
//WRITE DESCRIPTION
data = Bytes.concat(data, descriptionBytes);
//WRITE QUANTITY
byte[] quantityBytes = Longs.toByteArray(this.quantity);
data = Bytes.concat(data, quantityBytes);
//WRITE DIVISIBLE
byte[] divisibleBytes = new byte[1];
divisibleBytes[0] = (byte) (this.divisible == true ? 1 : 0);
data = Bytes.concat(data, divisibleBytes);
if(includeReference)
{
//WRITE REFERENCE
data = Bytes.concat(data, this.reference);
}
else
{
//WRITE EMPTY REFERENCE
data = Bytes.concat(data, new byte[64]);
}
return data;
}
public int getDataLength()
{
return OWNER_LENGTH + NAME_SIZE_LENGTH + this.name.getBytes(StandardCharsets.UTF_8).length + DESCRIPTION_SIZE_LENGTH + this.description.getBytes(StandardCharsets.UTF_8).length + QUANTITY_LENGTH + DIVISIBLE_LENGTH + REFERENCE_LENGTH;
}
//OTHER
public String toString()
{
if(this.getKey() == 0)
{
return "Qora";
}
else
{
return "(" + this.getKey() + ") " + this.getName();
}
}
}