package io.bitsquare.trade.statistics;
import io.bitsquare.app.Capabilities;
import io.bitsquare.app.Version;
import io.bitsquare.common.crypto.PubKeyRing;
import io.bitsquare.common.util.JsonExclude;
import io.bitsquare.p2p.storage.payload.CapabilityRequiringPayload;
import io.bitsquare.p2p.storage.payload.LazyProcessedStoragePayload;
import io.bitsquare.p2p.storage.payload.PersistedStoragePayload;
import io.bitsquare.trade.offer.Offer;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.ExchangeRate;
import org.bitcoinj.utils.Fiat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.concurrent.Immutable;
import java.security.PublicKey;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Immutable
public final class TradeStatistics implements LazyProcessedStoragePayload, CapabilityRequiringPayload, PersistedStoragePayload {
private static final Logger log = LoggerFactory.getLogger(TradeStatistics.class);
@JsonExclude
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
@JsonExclude
public static final long TTL = TimeUnit.DAYS.toMillis(30);
public final String currency;
public final Offer.Direction direction;
public final long tradePrice;
public final long tradeAmount;
public final long tradeDate;
public final String paymentMethod;
public final long offerDate;
public final boolean useMarketBasedPrice;
public final double marketPriceMargin;
public final long offerAmount;
public final long offerMinAmount;
public final String offerId;
public final String depositTxId;
@JsonExclude
public final PubKeyRing pubKeyRing;
public TradeStatistics(Offer offer, Fiat tradePrice, Coin tradeAmount, Date tradeDate, String depositTxId, PubKeyRing pubKeyRing) {
this.direction = offer.getDirection();
this.currency = offer.getCurrencyCode();
this.paymentMethod = offer.getPaymentMethod().getId();
this.offerDate = offer.getDate().getTime();
this.useMarketBasedPrice = offer.getUseMarketBasedPrice();
this.marketPriceMargin = offer.getMarketPriceMargin();
this.offerAmount = offer.getAmount().value;
this.offerMinAmount = offer.getMinAmount().value;
this.offerId = offer.getId();
this.tradePrice = tradePrice.longValue();
this.tradeAmount = tradeAmount.value;
this.tradeDate = tradeDate.getTime();
this.depositTxId = depositTxId;
this.pubKeyRing = pubKeyRing;
}
@Override
public long getTTL() {
return TTL;
}
@Override
public PublicKey getOwnerPubKey() {
return pubKeyRing.getSignaturePubKey();
}
@Override
public List<Integer> getRequiredCapabilities() {
return Arrays.asList(
Capabilities.Capability.TRADE_STATISTICS.ordinal()
);
}
public Date getTradeDate() {
return new Date(tradeDate);
}
public Fiat getTradePrice() {
return Fiat.valueOf(currency, tradePrice);
}
public Coin getTradeAmount() {
return Coin.valueOf(tradeAmount);
}
public Fiat getTradeVolume() {
return new ExchangeRate(getTradePrice()).coinToFiat(getTradeAmount());
}
public String getOfferId() {
return offerId;
}
// We don't include the pubKeyRing as both traders might publish it if the offerer uses an old
// version and update later (taker publishes first, then later offerer)
// We also don't include the trade date as that is set locally and different for offerer and taker
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TradeStatistics)) return false;
TradeStatistics that = (TradeStatistics) o;
if (tradePrice != that.tradePrice) return false;
if (tradeAmount != that.tradeAmount) return false;
if (offerDate != that.offerDate) return false;
if (useMarketBasedPrice != that.useMarketBasedPrice) return false;
if (Double.compare(that.marketPriceMargin, marketPriceMargin) != 0) return false;
if (offerAmount != that.offerAmount) return false;
if (offerMinAmount != that.offerMinAmount) return false;
if (currency != null ? !currency.equals(that.currency) : that.currency != null) return false;
if (direction != null && that.direction != null && direction.ordinal() != that.direction.ordinal())
return false;
else if ((direction == null && that.direction != null) || (direction != null && that.direction == null))
return false;
if (paymentMethod != null ? !paymentMethod.equals(that.paymentMethod) : that.paymentMethod != null)
return false;
if (getOfferId() != null ? !getOfferId().equals(that.getOfferId()) : that.getOfferId() != null) return false;
return !(depositTxId != null ? !depositTxId.equals(that.depositTxId) : that.depositTxId != null);
}
@Override
public int hashCode() {
int result;
long temp;
result = currency != null ? currency.hashCode() : 0;
result = 31 * result + (direction != null ? direction.ordinal() : 0);
result = 31 * result + (int) (tradePrice ^ (tradePrice >>> 32));
result = 31 * result + (int) (tradeAmount ^ (tradeAmount >>> 32));
result = 31 * result + (paymentMethod != null ? paymentMethod.hashCode() : 0);
result = 31 * result + (int) (offerDate ^ (offerDate >>> 32));
result = 31 * result + (useMarketBasedPrice ? 1 : 0);
temp = Double.doubleToLongBits(marketPriceMargin);
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + (int) (offerAmount ^ (offerAmount >>> 32));
result = 31 * result + (int) (offerMinAmount ^ (offerMinAmount >>> 32));
result = 31 * result + (getOfferId() != null ? getOfferId().hashCode() : 0);
result = 31 * result + (depositTxId != null ? depositTxId.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "TradeStatistics{" +
"currency='" + currency + '\'' +
", direction=" + direction +
", tradePrice=" + tradePrice +
", tradeAmount=" + tradeAmount +
", tradeDate=" + tradeDate +
", paymentMethod='" + paymentMethod + '\'' +
", offerDate=" + offerDate +
", useMarketBasedPrice=" + useMarketBasedPrice +
", marketPriceMargin=" + marketPriceMargin +
", offerAmount=" + offerAmount +
", offerMinAmount=" + offerMinAmount +
", offerId='" + getOfferId() + '\'' +
", depositTxId='" + depositTxId + '\'' +
", pubKeyRing=" + pubKeyRing +
", hashCode=" + hashCode() +
'}';
}
}