package com.ripple.core.types.known.sle.entries;
import com.ripple.core.coretypes.*;
import com.ripple.core.coretypes.hash.Hash256;
import com.ripple.core.coretypes.hash.Index;
import com.ripple.core.coretypes.uint.UInt32;
import com.ripple.core.coretypes.uint.UInt64;
import com.ripple.core.fields.Field;
import com.ripple.core.serialized.enums.LedgerEntryType;
import com.ripple.core.types.known.sle.ThreadedLedgerEntry;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
public class Offer extends ThreadedLedgerEntry {
public Offer() {
super(LedgerEntryType.Offer);
}
/**
* Use the BookDirectory field
*
* @return how much must `pay` to `get` one.
*
*/
public BigDecimal directoryAskQuality() {
return Quality.fromBookDirectory(bookDirectory(),
takerPays().isNative(),
takerGets().isNative());
}
/**
* @return how much must `pay` to `get` one.
*/
public BigDecimal askQuality() {
return takerPays().computeQuality(takerGets());
}
/**
* @return how much `get` if `pay` one.
*/
public BigDecimal bidQuality() {
return takerGets().computeQuality(takerPays());
}
/**
*
* @return One of TakerGets issue, eg 1/USD/BITSTAMP or 1/EUR/SNAPSWAP
*/
public Amount getsOne() {
return takerGets().one();
}
/**
*
* @return One of TakerPays issue, eg 1/USD/BITSTAMP or 1/EUR/SNAPSWAP
*/
public Amount paysOne() {
return takerPays().one();
}
public String getPayCurrencyPair() {
return takerGets().currencyString() + "/" +
takerPays().currencyString();
}
public STObject executed(STObject finalFields) {
// where `this` is an AffectedNode nodeAsPrevious
STObject executed = new STObject();
executed.put(Amount.TakerPays, finalFields.get(Amount.TakerPays).subtract(takerPays()));
executed.put(Amount.TakerGets, finalFields.get(Amount.TakerGets).subtract(takerGets()));
return executed;
}
public Hash256 lineIndex(Amount amt) {
return account().lineIndex(amt.issue());
}
public Hash256 fundingSource() {
Amount takerGets = takerGets();
if (account().equals(takerGets.issuer())) {
return null;
}
else if (takerGets.isNative()) {
return Index.accountRoot(account());
} else {
return lineIndex(takerGets);
}
}
public Vector256 lineIndexes() {
Vector256 ret = new Vector256();
Amount takerGets = takerGets();
for (Amount amt : new Amount[]{takerGets, takerPays()}) {
// Actually want to compare by reference here :)
if (amt == takerGets()) {
// selling own funds
continue;
}
if (!amt.isNative()) {
ret.add(lineIndex(amt));
}
}
return ret;
}
public Hash256 bookBase() {
return Index.bookStart(takerPays().issue(), takerGets().issue());
}
public boolean belongsToBook(Hash256 bookBase) {
byte[] baseBytes = bookBase.bytes();
byte[] directoryBytes = bookDirectory().bytes();
for (int i = 0; i < 24; i++) {
if (baseBytes[i] != directoryBytes[i]) {
return false;
}
}
return true;
}
public boolean sellingOwnFunds() {
return account().equals(takerGets().issuer());
}
public Amount takerGetsFunded() {
return has(Field.taker_gets_funded) ? get(Amount.taker_gets_funded) : takerGets();
}
public Amount takerPaysFunded() {
return has(Field.taker_pays_funded) ? get(Amount.taker_pays_funded) : takerPays();
}
public static Comparator<Offer> qualityAscending = new Comparator<Offer>() {
@Override
public int compare(Offer lhs, Offer rhs) {
return lhs.directoryAskQuality().compareTo(rhs.directoryAskQuality());
}
};
public static Iterator<Offer> iterateCollection(Collection<STObject> offers) {
final Iterator<STObject> iterator = offers.iterator();
return new Iterator<Offer>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Offer next() {
return (Offer) iterator.next();
}
@Override
public void remove() {
iterator.remove();
}
};
}
public Hash256 bookNodeDirectoryIndex() {
return Index.directoryNode(bookDirectory(), bookNode());
}
public Hash256 ownerNodeDirectoryIndex() {
Hash256 ownerDir = Index.ownerDirectory(account());
return Index.directoryNode(ownerDir, ownerNode());
}
public UInt32 sequence() {return get(UInt32.Sequence);}
public UInt32 expiration() {return get(UInt32.Expiration);}
public UInt64 bookNode() {return get(UInt64.BookNode);}
public UInt64 ownerNode() {return get(UInt64.OwnerNode);}
public Hash256 bookDirectory() {return get(Hash256.BookDirectory);}
public Amount takerPays() {return get(Amount.TakerPays);}
public Amount takerGets() {return get(Amount.TakerGets);}
public AccountID account() {return get(AccountID.Account);}
public void sequence(UInt32 val) {put(Field.Sequence, val);}
public void expiration(UInt32 val) {put(Field.Expiration, val);}
public void bookNode(UInt64 val) {put(Field.BookNode, val);}
public void ownerNode(UInt64 val) {put(Field.OwnerNode, val);}
public void bookDirectory(Hash256 val) {put(Field.BookDirectory, val);}
public void takerPays(Amount val) {put(Field.TakerPays, val);}
public void takerGets(Amount val) {put(Field.TakerGets, val);}
public void account(AccountID val) {put(Field.Account, val);}
public Hash256[] directoryIndexes() {
return new Hash256[]{bookNodeDirectoryIndex(), ownerNodeDirectoryIndex()};
}
public void setOfferDefaults() {
if (bookNode() == null) {
bookNode(UInt64.ZERO);
}
if (ownerNode() == null) {
ownerNode(UInt64.ZERO);
}
}
public IssuePair issuePair() {
return new IssuePair(takerPays().issue(), takerGets().issue());
}
public Amount payToGet(Amount funded) {
BigDecimal quality = directoryAskQuality();
// Multiply by one as that will do the rounding operation we want
return paysOne().multiply(funded.multiply(quality));
}
}