package com.jbidwatcher.auction;
/*
* Copyright (c) 2000-2007, CyberFOX Software, Inc. All Rights Reserved.
*
* Developed by mrs (Morgan Schweers)
* Date: Aug 17, 2005
* Time: 9:59:47 PM
*
* TODO - Create a 'Bid' equivalent of this class.
*/
import com.jbidwatcher.auction.server.AuctionServer;
import com.jbidwatcher.util.UpdateBlocker;
import com.jbidwatcher.util.config.JConfig;
import com.jbidwatcher.util.html.JHTML;
import com.jbidwatcher.util.http.CookieJar;
import com.jbidwatcher.util.queue.MQFactory;
public class Snipe {
public final static int SUCCESSFUL=0;
public final static int RESNIPE=1;
public final static int FAIL=2;
public static final int DONE = 3;
private final MultiSnipeManager mMultiManager;
private CookieJar mCJ = null;
private AuctionEntry mEntry;
private JHTML.Form mBidForm = null;
private LoginManager mLogin;
private Bidder mBidder;
public Snipe(MultiSnipeManager multiManager, LoginManager login, Bidder bidder, AuctionEntry ae) {
mLogin = login;
mEntry = ae;
mBidder = bidder;
mMultiManager = multiManager;
}
public int fire() {
if(mEntry.getSnipeAmount().getValue() < 0.0) {
mEntry.setLastStatus("Snipe amount is negative. Not sniping.");
return FAIL;
}
// Two stage firing. First we fill the cookie jar. The second time we submit the
// bid confirmation form.
if(mCJ == null) {
return preSnipe();
} else {
return doSnipe();
}
}
private int doSnipe() {
// Just punt if we had failed to get the bidding form initially.
if(mBidForm == null) return FAIL;
UpdateBlocker.startBlocking();
MultiSnipe ms = mMultiManager.getForAuctionIdentifier(mEntry.getIdentifier());
if(ms != null) {
// Make sure there aren't any update-unfinished items.
if(ms.anyEarlier(mEntry)) {
mEntry.setLastStatus("An earlier snipe in this multisnipe group has not ended, or has not been updated after ending.");
mEntry.setLastStatus("This snipe is NOT being fired, as it could end up winning two items.");
UpdateBlocker.endBlocking();
return RESNIPE;
}
}
MQFactory.getConcrete("Swing").enqueue("Sniping on " + mEntry.getTitle());
mEntry.setLastStatus("Firing actual snipe.");
// Metrics
JConfig.getMetrics().trackEvent("snipe", "fired");
int rval = mBidder.placeFinalBid(mCJ, mBidForm, mEntry, mEntry.getSnipeAmount(), mEntry.getSnipeQuantity());
boolean success = (rval == AuctionServer.BID_WINNING || rval == AuctionServer.BID_SELFWIN);
// Metrics
if(success) {
JConfig.getMetrics().trackEvent("snipe", "success");
} else {
JConfig.getMetrics().trackEventValue("snipe", "fail", Integer.toString(rval));
}
JConfig.increment("stats.sniped");
String snipeResult = getSnipeResult(rval, mEntry.getTitle(), mEntry);
mEntry.setLastStatus(snipeResult);
MQFactory.getConcrete("Swing").enqueue("NOTIFY " + snipeResult);
JConfig.log().logDebug(snipeResult);
mEntry.snipeCompleted();
UpdateBlocker.endBlocking();
return DONE;
}
private int preSnipe() {
UpdateBlocker.startBlocking();
mEntry.setLastStatus("Preparing snipe.");
// Log in
mCJ = mLogin.getSignInCookie(null);
if (mCJ == null) {
// Alert somebody that we couldn't log in?
mEntry.setLastStatus("Pre-snipe login failed. Snipe will be retried, but is unlikely to fire.");
MQFactory.getConcrete("Swing").enqueue("NOTIFY Pre-snipe login failed.");
JConfig.log().logDebug("Pre-snipe login failed.");
UpdateBlocker.endBlocking();
return RESNIPE;
}
int presnipeResult = SUCCESSFUL;
// Get Bid Key/Form
try {
JConfig.increment("stats.presniped");
mBidForm = mBidder.getBidForm(mCJ, mEntry, mEntry.getSnipeAmount());
if(mBidForm.getInputValue("maxbid").length() == 0) {
// We have a problem.
mBidForm.setText("maxbid", mEntry.getSnipeAmount().getValueString());
}
// Metrics
JConfig.getMetrics().trackEvent("presnipe", "success");
} catch (BadBidException bbe) {
String result = getSnipeResult(bbe.getResult(), mEntry.getTitle(), mEntry);
mEntry.setLastStatus(result);
MQFactory.getConcrete("Swing").enqueue("NOTIFY " + result);
JConfig.log().logDebug(result);
presnipeResult = FAIL;
// Metrics
JConfig.getMetrics().trackEventValue("presnipe", "fail", Integer.toString(bbe.getResult()));
}
UpdateBlocker.endBlocking();
return presnipeResult;
}
public static String getSnipeResult(int snipeResult, String aucTitle, AuctionEntry aeFire) {
String snipeOutput;
if(snipeResult == AuctionServerInterface.BID_WINNING || snipeResult == AuctionServerInterface.BID_SELFWIN) {
snipeOutput = "Successfully sniped a high bid on " + aucTitle + '!';
JConfig.increment("stats.sniped.success");
} else {
switch(snipeResult) {
case AuctionServerInterface.BID_ERROR_UNKNOWN:
snipeOutput = "Unknown error sniping on " + aucTitle + " (" + aeFire.getIdentifier() + ")";
JConfig.increment("stats.sniped.unknown_error");
break;
case AuctionServerInterface.BID_ERROR_ENDED:
case AuctionServerInterface.BID_ERROR_CANNOT:
snipeOutput = "Snipe apparently failed, as the auction cannot be bid on anymore: " + aucTitle;
JConfig.increment("stats.sniped.too_late");
break;
case AuctionServerInterface.BID_ERROR_BANNED:
snipeOutput = "Snipe failed, as you are disallowed from bidding on " + aeFire.getSellerName() + "'s items.";
JConfig.increment("stats.sniped.banned");
break;
case AuctionServerInterface.BID_ERROR_TOO_LOW:
snipeOutput = "Snipe was too low, and was not accepted.";
JConfig.increment("stats.sniped.too_low");
break;
case AuctionServerInterface.BID_ERROR_TOO_LOW_SELF:
snipeOutput = "Your bid was below or equal to your previous high bid, and was not accepted.";
JConfig.increment("stats.sniped.too_low");
break;
case AuctionServerInterface.BID_ERROR_RESERVE_NOT_MET:
snipeOutput = "Your snipe was successful, but it did not meet the reserve price.";
JConfig.increment("stats.sniped.too_low");
break;
case AuctionServerInterface.BID_ERROR_AMOUNT:
snipeOutput = "There is an error with the amount for the snipe on " + aucTitle + " (Probably snipe too low vs. current bids).";
JConfig.increment("stats.sniped.too_low");
break;
case AuctionServerInterface.BID_ERROR_OUTBID:
snipeOutput = "You have been outbid in your snipe on " + aucTitle;
JConfig.increment("stats.sniped.outbid");
break;
case AuctionServerInterface.BID_ERROR_CONNECTION:
snipeOutput = "Snipe failed due to connection problem. Probably a timeout trying to reach eBay.";
JConfig.increment("stats.sniped.connection_error");
break;
case AuctionServer.BID_ERROR_AUCTION_GONE:
snipeOutput = "Your snipe failed because the item was removed from JBidwatcher before the bid executed.";
JConfig.increment("stats.sniped.removed");
break;
case AuctionServer.BID_ERROR_ACCOUNT_SUSPENDED:
snipeOutput = "You cannot interact with any auctions, your account has been suspended.";
JConfig.increment("stats.sniped.suspended");
break;
case AuctionServer.BID_ERROR_CANT_SIGN_IN:
snipeOutput = "Sign in failed repeatedly during bid. Check your username and password information in the Configuration Manager.";
JConfig.increment("stats.sniped.sign_in");
break;
case AuctionServer.BID_ERROR_WONT_SHIP:
snipeOutput = "You are registered in a country to which the seller doesn't ship.";
JConfig.increment("stats.sniped.wont_ship");
break;
case AuctionServer.BID_ERROR_REQUIREMENTS_NOT_MET:
snipeOutput = "You don't meet some requirement the seller has set for the item. Check the item details for more information.";
JConfig.increment("stats.sniped.requirement_not_met");
break;
case AuctionServer.BID_ERROR_SELLER_CANT_BID:
snipeOutput = "Sellers are not allowed to bid on their own items.";
break;
case AuctionServerInterface.BID_ERROR_MULTI:
snipeOutput = "There is a problem with the multisnipe, an earlier entry hasn't finished updating. Trying again shortly.";
JConfig.increment("stats.sniped.multisnipe_problem");
break;
default:
snipeOutput = "Something really bad happened, and I don't know what.";
JConfig.increment("stats.sniped.really_bad");
break;
}
}
return snipeOutput;
}
public AuctionEntry getItem() {
return mEntry;
}
}