package qora.payment;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import org.json.simple.JSONObject;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.Longs;
import database.DBSet;
import qora.account.Account;
import qora.account.PublicKeyAccount;
import qora.crypto.Base58;
public class Payment {
private static final int RECIPIENT_LENGTH = 25;
private static final int ASSET_LENGTH = 8;
private static final int AMOUNT_LENGTH = 12;
public static final int BASE_LENGTH = RECIPIENT_LENGTH + ASSET_LENGTH + AMOUNT_LENGTH;
private Account recipient;
private long asset;
private BigDecimal amount;
public Payment(Account recipient, long asset, BigDecimal amount)
{
this.recipient = recipient;
this.asset = asset;
this.amount = amount;
}
//GETTERS/SETTERS
public Account getRecipient()
{
return this.recipient;
}
public long getAsset()
{
return this.asset;
}
public BigDecimal getAmount()
{
return this.amount;
}
//PARSE
public static Payment parse(byte[] data) throws Exception
{
int position = 0;
//READ RECIPIENT
byte[] recipientBytes = Arrays.copyOfRange(data, position, position + RECIPIENT_LENGTH);
Account recipient = new Account(Base58.encode(recipientBytes));
position += RECIPIENT_LENGTH;
//READ ASSET
byte[] assetBytes = Arrays.copyOfRange(data, position, position + ASSET_LENGTH);
long asset = Longs.fromByteArray(assetBytes);
position += ASSET_LENGTH;
//READ AMOUNT
byte[] amountBytes = Arrays.copyOfRange(data, position, position + AMOUNT_LENGTH);
BigDecimal amount = new BigDecimal(new BigInteger(amountBytes), 8);
position += AMOUNT_LENGTH;
return new Payment(recipient, asset, amount);
}
@SuppressWarnings("unchecked")
public JSONObject toJson()
{
//GET BASE
JSONObject payment = new JSONObject();
//ADD RECIPIENT/ASSET/AMOUNT
payment.put("recipient", this.recipient);
payment.put("asset", this.asset);
payment.put("amount", this.amount.toPlainString());
return payment;
}
public byte[] toBytes()
{
byte[] data = new byte[0];
//WRITE RECIPIENT
data = Bytes.concat(data, Base58.decode(this.recipient.getAddress()));
//WRITE ASSET
byte[] assetBytes = Longs.toByteArray(this.asset);
assetBytes = Bytes.ensureCapacity(assetBytes, ASSET_LENGTH, 0);
data = Bytes.concat(data, assetBytes);
//WRITE AMOUNT
byte[] amountBytes = this.amount.unscaledValue().toByteArray();
byte[] fill = new byte[AMOUNT_LENGTH - amountBytes.length];
amountBytes = Bytes.concat(fill, amountBytes);
data = Bytes.concat(data, amountBytes);
return data;
}
public int getDataLength()
{
return BASE_LENGTH;
}
//PROCESS/ORPHAN
public void process(PublicKeyAccount sender, DBSet db)
{
//UPDATE SENDER
sender.setConfirmedBalance(this.asset, sender.getConfirmedBalance(this.asset, db).subtract(this.amount), db);
//UPDATE RECIPIENT
this.recipient.setConfirmedBalance(this.asset, this.recipient.getConfirmedBalance(this.asset, db).add(this.amount), db);
}
public void orphan(PublicKeyAccount sender, DBSet db)
{
//UPDATE SENDER
sender.setConfirmedBalance(this.asset, sender.getConfirmedBalance(this.asset, db).add(this.amount), db);
//UPDATE RECIPIENT
this.recipient.setConfirmedBalance(this.asset, this.recipient.getConfirmedBalance(this.asset, db).subtract(this.amount), db);
}
}