// ==UserScript==
// @name           Swoopo Profits
// @author 		     Ben Hollis
// @namespace      http://brh.numbera.com/software/greasemonkey/
// @description    Shows Swoopo's estimated profit on auctions
// @include        http://*swoopo.tld/*
// @version        1.0 (10-8-2009)
// ==/UserScript==

// Don't need to recalculate these each time ( set up in setup() )
var bidAmount, worthUpTo, bidCost, locale;
  
// Talk to firebug
function log(message) {
  //if (unsafeWindow.console) {
  //  unsafeWindow.console.log(message);
  //}
}

var printedCurrentPrice = false;

// Called on a timer, updates profit as the price ticks up
function updateProfit() {
  // Get the current price, plus any leading or trailing currency symbols (for displaying the result in local currency)
  var currentPriceElem = getCurrentPriceElem();
  
  var leadingCurrency = '';
  var trailingCurrency = '';
  
  if (currentPriceElem.innerHTML.indexOf('$') >= 0) {
    leadingCurrency = '$';
  } else if (currentPriceElem.innerHTML.indexOf('€') >= 0) {
    trailingCurrency = ' €';
  } else if (currentPriceElem.innerHTML.indexOf('£') >= 0) {
    leadingCurrency = '£';
  }

  var currentPrice = findMoney(currentPriceElem);
  if (!printedCurrentPrice) {
    log("current price: " + leadingCurrency + currentPrice + trailingCurrency);
  }
  
  // Kind of a verbose, but easy to follow way of calculating estimated profit
  var profit = ((currentPrice - bidAmount) / bidAmount) * bidCost + currentPrice - worthUpTo;
    if (!printedCurrentPrice) {
    log("current profit: " + leadingCurrency + (Math.round(profit*100.0)/100.0) + trailingCurrency);
  }
  printedCurrentPrice = true;
  document.getElementById('swoopo_profit').innerHTML = leadingCurrency + (Math.round(profit*100.0)/100.0) + trailingCurrency;
}

// Find the "bid amount" - the price the auction starts at, and the amount the price rises per bid
function getBidAmount() {
  // Look for text explaining how much each bid increases the price
  var bidButton = document.getElementById('bttext');
  if ( bidButton ) {
    var bidHelpText = bidButton.getElementsByTagName('div')[0];
    bidHelpText = bidHelpText.lastChild;
    return findMoney(bidHelpText);
  }  
  
  // This text is sometimes elsewhere
  var bidButton = document.getElementById('gebotsbutton');
  if ( bidButton ) {
    var bidHelpText = bidButton.nextSibling;
    while ( bidHelpText && bidHelpText.nodeName.toLowerCase() != 'div' ) {
      bidHelpText = bidHelpText.nextSibling;   
    } 
    return findMoney(bidHelpText);
  }
 
  // Ugh. Look at the "flag" on the product image and extract the filename to look up in this table.
  var flagToCost = {
    "onecent": 0.01,
    "5cents": 0.06,
    "2cents": 0.02,
    "20cents": 0.24
  }
  var productimage = document.getElementById('bilder_top2')
  if ( productimage ) {
    productimage = productimage.getElementsByTagName('img')[0];
    
    var imageSrc = /flag=flg_([^\.]+).png/.exec(productimage.src);
    if ( imageSrc && imageSrc.length >= 2 ) {
      flag = imageSrc[1];
      if ( flagToCost[flag] ) {
        return flagToCost[flag];
      }
    }
  }
  
  log("defaulting bid amount");
  return 0.12;
}

function getBidCost() {
  // Trickier. Look for the number of bids placed by the winner, and the total they spent on bids, to find bid price
  var summary = findAuctionSummary();

  if ( summary && summary.length >= 4 ) {
    var numBids = parseInt(summary[1][0].innerHTML.match(/\d+/));
    var totalBidAmount = findMoney(summary[1][1]);
    
    if (numBids > 0 && totalBidAmount > 0) {
      return totalBidAmount / numBids;
    }
  }
  
  log("defaulting bid cost");
  // Use a lookup on the locale
  var costMap = {
    'us': 0.60,
    'uk': 0.50,
    'es': 0.50,
    'de': 0.50,
    'at': 0.50,
    'ca': 0.65
  }
  
  return costMap[locale];
}

// Find out how much Swoopo thinks the item in this auction is worth - assume that's how much they'll lose on selling it
function getWorthUpTo() {
  var worthUpToElem = document.getElementById('buy_it_now_price');
  
  if (worthUpToElem) {
    return findMoney(worthUpToElem);
  } else {
    // look in the auction summary
    summary = findAuctionSummary();
    if ( summary && summary.length >= 1 ) {
      return findMoney(summary[0][1]);
    }
  } 
  
  log("Defaulting worth up to");
  // Give up
  return 0.0;
}

// Extract money amount from innerHTML of an element
function findMoney(elem) {
  var elemText = (elem.nodeType == 3) ? elem.nodeValue : elem.innerHTML;
  // TODO: does this work for other number formats?
  return parseMoney(elemText.match(/[\d,\.]+\d\d/)[0]);
}

// International-aware parseFloat
function parseMoney(money) {
  var moneyParts = money.split(/[,\.]/);
  var dollars = parseInt(moneyParts.slice(0,moneyParts.length-1).join(''));
  var cents = parseInt(moneyParts[moneyParts.length-1]);
  return (dollars * 1.0) + ( (1.0 * cents) / 100.0); 
}

// Find the element with the current price (it's different for ended auctions)
function getCurrentPriceElem() {
  var summary = findAuctionSummary();
  if ( summary && summary.length >= 4 ) {
    return summary[3][1];
  }
      
  var currentPriceElem = document.getElementById('a_current_price');
  
  if ( currentPriceElem ) {
    return currentPriceElem;
  }
  
  return null;
}

// Find the summary of an auction, as a list of td elements extracted from the right side of the table
// This is usually a table under the bid button or a summary at the end
function findAuctionSummary() {
  // it's the second "aktgebot" - they use the same id twice so we can't just use getElementById
  var searchResults = document.evaluate('//div[@id="aktgebot"]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

  var auctionSummary = null;
  if ( searchResults.snapshotLength > 1 ) {
    auctionSummary = searchResults.snapshotItem(1);
  } else {
    var summaryElems = document.getElementsByClassName('erspanisnew');
    if ( summaryElems && summaryElems.length ) {
      auctionSummary = summaryElems[0];
    } else {
      summaryElems = document.getElementsByClassName('erspanisnew_ended');
      if ( summaryElems && summaryElems.length ) {
        auctionSummary = summaryElems[0];
      }
    }
  }
  
  if ( !auctionSummary ) {
    return null;
  }
  
  var rows = auctionSummary.getElementsByTagName('tr');
  var values = [];
   
  // Reject rows that are presentational (colspan)
  for(var i = 0; i < rows.length; i++) {
    if (rows[i].getElementsByTagName('td')[0].getAttribute('colspan') != 2) {
      var cells = rows[i].getElementsByTagName('td');
      var images = rows[i].getElementsByTagName('img');
      if (cells && cells.length > 1 && (!images || images.length == 0)) {
        values.push(cells);
      }
    }
  }
  
  return values;
}

// Figure out which site we're using
function getLocale() {
  host = location.hostname.replace('www.','');
  
  hostMap = {
    'swoopo.com': 'us',
    'swoopo.co.uk': 'uk',
    'swoopo.es': 'es',
    'swoopo.de': 'de',
    'swoopo.at': 'at',
    'swoopo.ca': 'ca'
  }
  
  return hostMap[host] || 'us'; 
}

function setup() {
  // Calculate these once
  locale = getLocale();
  log("got locale: " + locale);  
  bidAmount = getBidAmount();
  log("got bid amount: " + bidAmount);
  worthUpTo = getWorthUpTo();
  log("got worth up to: " + worthUpTo);
  bidCost = getBidCost();
  log("got bid cost of: " + bidCost);
    
  var labelCell = document.createElement('div');
  labelCell.innerHTML = '<div>Estimated Swoopo Profit:</div>';
  labelCell.style.fontSize = '12px';
  labelCell.style.marginRight = '264px';
  labelCell.style.marginTop = '5px';
  labelCell.style.textAlign = 'right';
  labelCell.style.fontFamily = 'Verdana,sans-serif';
  
  var profitCell = document.createElement('span');
  profitCell.id = 'swoopo_profit';
  profitCell.innerHTML = 'calculating...';
  profitCell.style.fontSize = '28px';
  profitCell.style.color = 'green';
  profitCell.style.fontWeight = 'bold';  
  labelCell.appendChild(profitCell);
  
  var currentPriceRow = document.getElementById('ptext');
  currentPriceRow.appendChild(labelCell);
  currentPriceRow.style.paddingBottom = 0;
}

// Only activate if we're on an auction page
if ( getCurrentPriceElem() ) {
  setup();
  setInterval(updateProfit, 1000);
}