/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.arbitration;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.messages.DisputeCommunicationMessage;
import io.bitsquare.common.wire.Payload;
import javafx.beans.property.*;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Arrays;
import java.util.Date;
public final class DisputeResult implements Payload {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
private static final Logger log = LoggerFactory.getLogger(DisputeResult.class);
public enum DisputeFeePolicy {
LOSER,
SPLIT,
WAIVE
}
public enum Winner {
BUYER,
SELLER,
STALE_MATE
}
// only append new values as we use the ordinal value
public enum Reason {
BUG,
USABILITY,
SCAM,
OTHER,
PROTOCOL_VIOLATION,
NO_REPLY
}
public final String tradeId;
public final int traderId;
private DisputeFeePolicy disputeFeePolicy;
private Winner winner;
// Keep it for backward compatibility but use reasonOrdinal to allow changes in the ENum without breaking serialisation
@Deprecated
@Nullable
private Reason reason;
private int reasonOrdinal = Reason.OTHER.ordinal();
private boolean tamperProofEvidence;
private boolean idVerification;
private boolean screenCast;
private String summaryNotes;
private DisputeCommunicationMessage disputeCommunicationMessage;
private byte[] arbitratorSignature;
private long buyerPayoutAmount;
private long sellerPayoutAmount;
private long arbitratorPayoutAmount;
private String arbitratorAddressAsString;
private byte[] arbitratorPubKey;
private long closeDate;
private boolean isLoserPublisher;
transient private BooleanProperty tamperProofEvidenceProperty = new SimpleBooleanProperty();
transient private BooleanProperty idVerificationProperty = new SimpleBooleanProperty();
transient private BooleanProperty screenCastProperty = new SimpleBooleanProperty();
transient private ObjectProperty<DisputeFeePolicy> feePaymentPolicyProperty = new SimpleObjectProperty<>();
transient private StringProperty summaryNotesProperty = new SimpleStringProperty();
public DisputeResult(String tradeId, int traderId) {
this.tradeId = tradeId;
this.traderId = traderId;
disputeFeePolicy = DisputeFeePolicy.LOSER;
init();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
try {
in.defaultReadObject();
init();
} catch (Throwable t) {
log.warn("Cannot be deserialized." + t.getMessage());
}
}
private void init() {
tamperProofEvidenceProperty = new SimpleBooleanProperty(tamperProofEvidence);
idVerificationProperty = new SimpleBooleanProperty(idVerification);
screenCastProperty = new SimpleBooleanProperty(screenCast);
feePaymentPolicyProperty = new SimpleObjectProperty<>(disputeFeePolicy);
summaryNotesProperty = new SimpleStringProperty(summaryNotes);
tamperProofEvidenceProperty.addListener((observable, oldValue, newValue) -> {
tamperProofEvidence = newValue;
});
idVerificationProperty.addListener((observable, oldValue, newValue) -> {
idVerification = newValue;
});
screenCastProperty.addListener((observable, oldValue, newValue) -> {
screenCast = newValue;
});
feePaymentPolicyProperty.addListener((observable, oldValue, newValue) -> {
disputeFeePolicy = newValue;
});
summaryNotesProperty.addListener((observable, oldValue, newValue) -> {
summaryNotes = newValue;
});
}
public BooleanProperty tamperProofEvidenceProperty() {
return tamperProofEvidenceProperty;
}
public BooleanProperty idVerificationProperty() {
return idVerificationProperty;
}
public BooleanProperty screenCastProperty() {
return screenCastProperty;
}
public void setDisputeFeePolicy(DisputeFeePolicy disputeFeePolicy) {
this.disputeFeePolicy = disputeFeePolicy;
feePaymentPolicyProperty.set(disputeFeePolicy);
}
public ReadOnlyObjectProperty<DisputeFeePolicy> disputeFeePolicyProperty() {
return feePaymentPolicyProperty;
}
public DisputeFeePolicy getDisputeFeePolicy() {
return disputeFeePolicy;
}
public void setReason(Reason reason) {
this.reasonOrdinal = reason.ordinal();
}
public Reason getReason() {
if (reasonOrdinal < Reason.values().length)
return Reason.values()[reasonOrdinal];
else
return Reason.OTHER;
}
public void setSummaryNotes(String summaryNotes) {
this.summaryNotesProperty.set(summaryNotes);
}
public StringProperty summaryNotesProperty() {
return summaryNotesProperty;
}
public void setDisputeCommunicationMessage(DisputeCommunicationMessage disputeCommunicationMessage) {
this.disputeCommunicationMessage = disputeCommunicationMessage;
}
public DisputeCommunicationMessage getDisputeCommunicationMessage() {
return disputeCommunicationMessage;
}
public void setArbitratorSignature(byte[] arbitratorSignature) {
this.arbitratorSignature = arbitratorSignature;
}
public byte[] getArbitratorSignature() {
return arbitratorSignature;
}
public void setBuyerPayoutAmount(Coin buyerPayoutAmount) {
this.buyerPayoutAmount = buyerPayoutAmount.value;
}
public Coin getBuyerPayoutAmount() {
return Coin.valueOf(buyerPayoutAmount);
}
public void setSellerPayoutAmount(Coin sellerPayoutAmount) {
this.sellerPayoutAmount = sellerPayoutAmount.value;
}
public Coin getSellerPayoutAmount() {
return Coin.valueOf(sellerPayoutAmount);
}
public void setArbitratorPayoutAmount(Coin arbitratorPayoutAmount) {
this.arbitratorPayoutAmount = arbitratorPayoutAmount.value;
}
public Coin getArbitratorPayoutAmount() {
return Coin.valueOf(arbitratorPayoutAmount);
}
public void setArbitratorAddressAsString(String arbitratorAddressAsString) {
this.arbitratorAddressAsString = arbitratorAddressAsString;
}
public String getArbitratorAddressAsString() {
return arbitratorAddressAsString;
}
public void setArbitratorPubKey(byte[] arbitratorPubKey) {
this.arbitratorPubKey = arbitratorPubKey;
}
public byte[] getArbitratorPubKey() {
return arbitratorPubKey;
}
public void setCloseDate(Date closeDate) {
this.closeDate = closeDate.getTime();
}
public Date getCloseDate() {
return new Date(closeDate);
}
public void setWinner(Winner winner) {
this.winner = winner;
}
public Winner getWinner() {
return winner;
}
public void setLoserIsPublisher(boolean loserPublisher) {
this.isLoserPublisher = loserPublisher;
}
public boolean isLoserPublisher() {
return isLoserPublisher;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DisputeResult)) return false;
DisputeResult that = (DisputeResult) o;
if (traderId != that.traderId) return false;
if (tamperProofEvidence != that.tamperProofEvidence) return false;
if (idVerification != that.idVerification) return false;
if (screenCast != that.screenCast) return false;
if (buyerPayoutAmount != that.buyerPayoutAmount) return false;
if (sellerPayoutAmount != that.sellerPayoutAmount) return false;
if (arbitratorPayoutAmount != that.arbitratorPayoutAmount) return false;
if (closeDate != that.closeDate) return false;
if (tradeId != null ? !tradeId.equals(that.tradeId) : that.tradeId != null) return false;
if (disputeFeePolicy != that.disputeFeePolicy) return false;
if (reasonOrdinal != that.reasonOrdinal) return false;
if (reason != that.reason) return false;
if (disputeFeePolicy != null && that.disputeFeePolicy != null && disputeFeePolicy.ordinal() != that.disputeFeePolicy.ordinal())
return false;
else if ((disputeFeePolicy == null && that.disputeFeePolicy != null) || (disputeFeePolicy != null && that.disputeFeePolicy == null))
return false;
if (reason != null && that.reason != null && reason.ordinal() != that.reason.ordinal())
return false;
else if ((reason == null && that.reason != null) || (reason != null && that.reason == null))
return false;
if (winner != null && that.winner != null && winner.ordinal() != that.winner.ordinal())
return false;
else if ((winner == null && that.winner != null) || (winner != null && that.winner == null))
return false;
if (summaryNotes != null ? !summaryNotes.equals(that.summaryNotes) : that.summaryNotes != null) return false;
if (disputeCommunicationMessage != null ? !disputeCommunicationMessage.equals(that.disputeCommunicationMessage) : that.disputeCommunicationMessage != null)
return false;
if (!Arrays.equals(arbitratorSignature, that.arbitratorSignature)) return false;
if (arbitratorAddressAsString != null ? !arbitratorAddressAsString.equals(that.arbitratorAddressAsString) : that.arbitratorAddressAsString != null)
return false;
if (!Arrays.equals(arbitratorPubKey, that.arbitratorPubKey)) return false;
return true;
}
@Override
public int hashCode() {
int result = tradeId != null ? tradeId.hashCode() : 0;
result = 31 * result + traderId;
result = 31 * result + (disputeFeePolicy != null ? disputeFeePolicy.ordinal() : 0);
result = 31 * result + reasonOrdinal;
result = 31 * result + (reason != null ? reason.ordinal() : 0);
result = 31 * result + (winner != null ? winner.ordinal() : 0);
result = 31 * result + (tamperProofEvidence ? 1 : 0);
result = 31 * result + (idVerification ? 1 : 0);
result = 31 * result + (screenCast ? 1 : 0);
result = 31 * result + (summaryNotes != null ? summaryNotes.hashCode() : 0);
result = 31 * result + (disputeCommunicationMessage != null ? disputeCommunicationMessage.hashCode() : 0);
result = 31 * result + (arbitratorSignature != null ? Arrays.hashCode(arbitratorSignature) : 0);
result = 31 * result + (int) (buyerPayoutAmount ^ (buyerPayoutAmount >>> 32));
result = 31 * result + (int) (sellerPayoutAmount ^ (sellerPayoutAmount >>> 32));
result = 31 * result + (int) (arbitratorPayoutAmount ^ (arbitratorPayoutAmount >>> 32));
result = 31 * result + (arbitratorAddressAsString != null ? arbitratorAddressAsString.hashCode() : 0);
result = 31 * result + (arbitratorPubKey != null ? Arrays.hashCode(arbitratorPubKey) : 0);
result = 31 * result + (int) (closeDate ^ (closeDate >>> 32));
return result;
}
}