package org.cryptocoinpartners.schema;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.Index;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.NoResultException;
import javax.persistence.PostPersist;
import javax.persistence.QueryHint;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.cryptocoinpartners.enumeration.FeeMethod;
import org.cryptocoinpartners.schema.dao.Dao;
import org.cryptocoinpartners.schema.dao.ListingDao;
import org.cryptocoinpartners.util.EM;
import com.google.inject.Inject;
/**
* Represents the possibility to trade one Asset for another
*/
@SuppressWarnings("UnusedDeclaration")
@Entity
@Cacheable
@NamedQueries({
@NamedQuery(name = "Listing.findByQuoteBase", query = "select a from Listing a where base=?1 and quote=?2 and prompt IS NULL", hints = { @QueryHint(name = "org.hibernate.cacheable", value = "true") }),
@NamedQuery(name = "Listing.findByQuoteBasePrompt", query = "select a from Listing a where base=?1 and quote=?2 and prompt=?3", hints = { @QueryHint(name = "org.hibernate.cacheable", value = "true") }) })
@Table(indexes = { @Index(columnList = "base"), @Index(columnList = "quote"), @Index(columnList = "prompt") })
//@Table(name = "listing", uniqueConstraints = { @UniqueConstraint(columnNames = { "base", "quote", "prompt" }),
//@UniqueConstraint(columnNames = { "base", "quote" }) })
public class Listing extends EntityBase {
@Inject
protected static ListingDao listingDao;
@ManyToOne(optional = false)
//@Column(unique = true)
public Asset getBase() {
return base;
}
@PostPersist
private void postPersist() {
// PersistUtil.clear();
// PersistUtil.refresh(this);
//PersistUtil.merge(this);
// PersistUtil.close();
//PersistUtil.evict(this);
}
@ManyToOne(optional = false)
//@Column(unique = true)
public Asset getQuote() {
return quote;
}
@ManyToOne(optional = true)
public Prompt getPrompt() {
return prompt;
}
/** will create the listing if it doesn't exist */
public static Listing forPair(Asset base, Asset quote) {
try {
Listing listing = EM.namedQueryZeroOne(Listing.class, "Listing.findByQuoteBase", base, quote);
if (listing == null) {
listing = new Listing(base, quote);
EM.find(base);
EM.find(quote);
EM.persist(listing);
}
return listing;
} catch (NoResultException e) {
final Listing listing = new Listing(base, quote);
EM.persist(listing);
return listing;
}
}
public static Listing forPair(Asset base, Asset quote, Prompt prompt) {
try {
Listing listing = EM.namedQueryZeroOne(Listing.class, "Listing.findByQuoteBasePrompt", base, quote, prompt);
if (listing == null) {
listing = new Listing(base, quote, prompt);
EM.persist(listing);
}
return listing;
} catch (NoResultException e) {
final Listing listing = new Listing(base, quote, prompt);
EM.persist(listing);
return listing;
}
}
@Override
public String toString() {
return getSymbol();
}
@Transient
public String getSymbol() {
if (prompt != null)
return base.getSymbol() + '.' + quote.getSymbol() + '.' + prompt.getSymbol();
return base.getSymbol() + '.' + quote.getSymbol();
}
@Transient
protected double getMultiplier() {
if (prompt != null)
return prompt.getMultiplier();
return getContractSize() * getTickSize();
}
@Transient
protected double getTickValue() {
if (prompt != null)
return prompt.getTickValue();
return 1;
}
@Transient
protected double getContractSize() {
if (prompt != null)
return prompt.getContractSize();
return 1;
}
@Transient
protected double getTickSize() {
if (prompt != null)
return prompt.getTickSize();
return getPriceBasis();
}
@Transient
protected Amount getMultiplierAsAmount() {
return new DiscreteAmount((long) getMultiplier(), getVolumeBasis());
}
@Transient
protected double getVolumeBasis() {
double volumeBasis = 0;
if (prompt != null)
volumeBasis = prompt.getVolumeBasis();
return volumeBasis == 0 ? getBase().getBasis() : volumeBasis;
}
@Transient
public FeeMethod getMarginMethod() {
FeeMethod marginMethod = null;
if (prompt != null)
marginMethod = prompt.getMarginMethod();
return marginMethod == null ? null : marginMethod;
}
@Transient
public FeeMethod getMarginFeeMethod() {
FeeMethod marginFeeMethod = null;
if (prompt != null)
marginFeeMethod = prompt.getMarginFeeMethod();
return marginFeeMethod == null ? null : marginFeeMethod;
}
@Transient
protected double getPriceBasis() {
double priceBasis = 0;
if (prompt != null)
priceBasis = prompt.getPriceBasis();
return priceBasis == 0 ? getQuote().getBasis() : priceBasis;
}
@Transient
protected Asset getTradedCurrency() {
if (prompt != null && prompt.getTradedCurrency() != null)
return prompt.getTradedCurrency();
return getQuote();
}
@Transient
public FeeMethod getFeeMethod() {
if (prompt != null && prompt.getFeeMethod() != null)
return prompt.getFeeMethod();
return null;
}
@Transient
public double getFeeRate() {
if (prompt != null && prompt.getFeeRate() != 0)
return prompt.getFeeRate();
return 0;
}
@Transient
protected int getMargin() {
if (prompt != null && prompt.getMargin() != 0)
return prompt.getMargin();
return 0;
}
public static List<String> allSymbols() {
List<String> result = new ArrayList<>();
List<Listing> listings = EM.queryList(Listing.class, "select x from Listing x");
for (Listing listing : listings)
result.add((listing.getSymbol()));
return result;
}
// JPA
protected Listing() {
}
protected void setBase(Asset base) {
this.base = base;
}
protected void setQuote(Asset quote) {
this.quote = quote;
}
protected void setPrompt(Prompt prompt) {
this.prompt = prompt;
}
protected Asset base;
protected Asset quote;
private Prompt prompt;
public Listing(Asset base, Asset quote) {
this.base = base;
this.quote = quote;
}
public Listing(Asset base, Asset quote, Prompt prompt) {
this.base = base;
this.quote = quote;
this.prompt = prompt;
}
public static Listing forSymbol(String symbol) {
symbol = symbol.toUpperCase();
final int dot = symbol.indexOf('.');
if (dot == -1)
throw new IllegalArgumentException("Invalid Listing symbol: \"" + symbol + "\"");
final String baseSymbol = symbol.substring(0, dot);
Asset base = Asset.forSymbol(baseSymbol);
if (base == null)
throw new IllegalArgumentException("Invalid base symbol: \"" + baseSymbol + "\"");
int len = symbol.substring(dot + 1, symbol.length()).indexOf('.');
len = (len != -1) ? Math.min(symbol.length(), dot + 1 + symbol.substring(dot + 1, symbol.length()).indexOf('.')) : symbol.length();
final String quoteSymbol = symbol.substring(dot + 1, len);
final String promptSymbol = (symbol.length() > len) ? symbol.substring(len + 1, symbol.length()) : null;
Asset quote = Asset.forSymbol(quoteSymbol);
if (quote == null)
throw new IllegalArgumentException("Invalid quote symbol: \"" + quoteSymbol + "\"");
if (promptSymbol == null)
return Listing.forPair(base, quote);
Prompt prompt = Prompt.forSymbol(promptSymbol);
return Listing.forPair(base, quote, prompt);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Listing) {
Listing listing = (Listing) obj;
if (!listing.getBase().equals(getBase())) {
return false;
}
if (!listing.getQuote().equals(getQuote())) {
return false;
}
if (listing.getPrompt() != null)
if (this.getPrompt() != null) {
if (!listing.getPrompt().equals(getPrompt()))
return false;
} else {
return false;
}
return true;
}
return false;
}
@Override
public int hashCode() {
return getPrompt() != null ? getQuote().hashCode() + getBase().hashCode() + getPrompt().hashCode() : getQuote().hashCode() + getBase().hashCode();
}
@Override
public void persit() {
listingDao.persist(this);
}
@Override
public EntityBase refresh() {
return listingDao.refresh(this);
}
public <T> T find() {
// synchronized (persistanceLock) {
try {
return (T) listingDao.find(Listing.class, this.getId());
//if (duplicate == null || duplicate.isEmpty())
} catch (Exception | Error ex) {
return null;
// System.out.println("Unable to perform request in " + this.getClass().getSimpleName() + ":find, full stack trace follows:" + ex);
// ex.printStackTrace();
}
}
@Override
public void detach() {
listingDao.detach(this);
// TODO Auto-generated method stub
}
@Override
public void merge() {
listingDao.merge(this);
// TODO Auto-generated method stub
}
@Override
@Transient
public Dao getDao() {
return listingDao;
}
@Override
public void delete() {
// TODO Auto-generated method stub
}
}