if (nickname == '') nickname='SIMuser';

FLIPS_SHOW = 11;
NUM_RANDOM_BIDS = 10;
NUM_SEQ_BIDS = 10;
IMAGE_DIR = '../images/';
ICON_IMAGE_DIR = '/console_images/';
GRAFIX_DIR = '/graphics/';
NUM_BIDROWS_ABOVE = 5;  // number rows above current bid
NUM_BIDROWS_BELOW = 7;  // number rows below current bid
BIDROW_HEIGHT = 30; // height of each bid row
SCROLL_ADJUST = 15; // pixels to add to each scroll to centre row

// restore the window.open method just in case it has been changed by norton
window.onerror = null;
window.open    = sida_realopen;

bcfrm = null;
randcount = 0;
lube_auctions = new Array();
lube_consoles = null;
lube_msgs = 0;
lube_seqno = 0;
lube_selectcount = 0;
lube_offsettime = 0; // clock-server offset

var attemptBid = 'none';

var currentAuction = null;

function current(aid) {
  return currentAuction['aid'] == aid;
}

function getAuction( auctionid ) {
  var index = -1; 
  for (var i=0; i<lube_auctions.length; i++) {
    
    if (lube_auctions[i]['aid'] == auctionid) {
      index = i;
      break;
    }
  }
  if (index == -1) {
    index = lube_auctions.length;
    var auc = new Array();
    auc['aid'] = auctionid;
    auc['bids'] = new Array();
    auc['enabled'] = 0; // used to deselect
    auc['title'] = '';
    auc['acode'] = '';
    auc['valuation'] = 0;
    auc['image path'] = '';
    auc['maxbids'] = 0;
    auc['minbidval'] = 0.01;
    auc['maxbidval'] = 0;
    auc['lock time'] = null; // date object
    auc['start time'] = null; // date object
    auc['flips'] = new Array();
    auc['focus'] = '';
    auc['state'] = 0;
    auc['bemsg'] = '';
    auc['seqno'] = 0;
    if (auc['xbooked'] == null) auc['xbooked'] = true;
    
    lube_auctions[index] = auc;
    return auc;
  }
  else return lube_auctions[index];
}

function selectAuction( aid, atitle, acode, abook ) {
// alert("selectAuction: a="+aid+" t="+atitle+" v="+aview);
  var auc = getAuction(aid);
  currentAuction = auc;
  var tabselect = true;
  if (selectAuction.arguments.length >= 3) {
    auc['aid']    = aid;
    auc['title']  = atitle;
    auc['acode']  = acode;
    
    auc['xbooked'] = true; 
    if ((selectAuction.arguments.length == 4) && (abook == 'look')) {
      auc['booked']  = false;
      auc['xbooked'] = false;
    }
    tabselect = false;
  }
  
  if ((lube_selectcount == 0) || tabselect) currentAuction = auc;
  if ((auc['enabled'] == 0) && !tabselect) lube_selectcount++;
  auc['enabled'] = 1;

  displayTabs(currentAuction['aid']);

  txa_send( "getinit|"+ auc['aid'] );
}

function deselectAuction( aid ) {
  var auc = getAuction(aid);
  if (auc['enabled'] == 1) {
    auc['enabled'] = 0;
  
    lube_selectcount--;
  
  // if we are deselecting the active auction then
  // we find another one to make active

    if ((currentAuction != null) && (currentAuction['aid'] == aid)) {
      for (var i=0; i<lube_auctions.length; i++) {
        if (lube_auctions[i]['enabled'] == 1) {
          aid = lube_auctions[i]['aid'];
          selectAuction( aid );
          break;
        }
      }
    }
  }
  
  displayTabs();
  if (lube_selectcount == 0) {
    currentAuction = null;
    setConsoleView();
  }
}

function txa_send(data) {
  if (lube_local) localAction(data);
  else lube_txasync.send(data);
}

function lubeinit() {
  bcfrm = top.frames['bidconsole'];
  fetchConsoles();
  if (!lube_local) {
    closecomms();
    initcomms_con();
  }
}

function lubeclose() {
  closecomms();
}

function setConsoleView() {
  var auc = currentAuction;

  var view = 'none';
  if (auc != null) view = asView(); 

  attemptBid = '';
  
  //if (tbd) if not changing view dont rewrite- just call setinit direct

  var html = lube_consoles.get(view);
  if (bcfrm == null) bcfrm = top.frames['bidconsole'];
  bcfrm.document.close();
  bcfrm.document.write( html );
  bcfrm.document.close();
}

function asView() {
  var state = currentAuction['state'];
  var booked = currentAuction['booked'];
//  alert("state="+state+" booked="+booked);
  if      (state == -2)   return "none";
  else if (booked) {
    if (state == -1) return "live";
    else if (state == 2)  return "qbid";
    else if (state == 3)  return "qbid";
    else if (state == 4)  return "live";
    else if (state == 5)  return "live";
  }
  else {
    if      (state == -1) return "look";
    else if (state == 4)  return "look";
    else if (state == 3)  return "look";
    else if (state == 5)  return "look";
  }
  return "none";
}

function stateText(state) {
  switch (state) {
    case 5 : return 'live';
    case 4 : return 'paused';
    case 3 : return 'locked';
    case 2 : return 'booked';
    case -1 : return 'closed';
    case -2 : return 'cancelled';
    default : return 'none';
  }
}

//TBD store last and current state so only send messages on change
function stateChange() {
  //if ( currentAuction['state'] == 5 ) displayMessage('joining live auction: "' + currentAuction['acode'] + '"');
  if (currentAuction['state'] < 0) {
    if ( typeof( currentAuction['winBid'] ) == 'undefined' ) {
      txa_send( "getclose|" + currentAuction['aid'] ); // request closing status info
      //displayMessage('auction closed: ' + currentAuction['acode']);
    }
    else setClosedText();
  }
  displayMessages();
	displayTime();
  displayFlips();
  if ( ( currentAuction['state'] == 5 || currentAuction['state'] == 2 ) && currentAuction['booked'] ) getFocus('amount');
}

function getFocus(id) {
  try {
    var elem = bcfrm.document.getElementById(id);
    if (elem != null) elem.focus();
  }
  catch (e) {
    alert("Error: could not get element id=" + id + ' view=' + asView() + ' auc=' + currentAuction['aid'] + " gave error\n " + e);
  }
}

function setElement(id, text) {
  try {
    var elem = bcfrm.document.getElementById(id);
    if (elem != null) elem.innerHTML = text;
    //else displayElemError(id);
  }
  catch (e) {
    alert("Error: could not get element id=" + id + ' view=' + asView() + ' auc=' + currentAuction['aid'] + " gave error\n " + e);
  }
}

function setTopElement(id, text) {
  try {
    var elem = top.document.getElementById(id);
    if (elem != null) elem.innerHTML = text;
    //else displayElemError(id);
  }
  catch (e) {
    alert("Error: could not get top element id=" + id + ' view=' + asView() + ' auc=' + currentAuction['aid'] + " gave error\n " + e);
  }
}

function setVisible(name, visible) {
  try {
    var elem = bcfrm.document.getElementById(name);
    if (elem != null) {
      if (visible) elem.style.visibility='visible';
      else elem.style.visibility='hidden';
    }
    //else displayMessage("Error: could not set visibility element id=" + name + ' view=' + asView() + ' auc=' + currentAuction['aid'], true);
  }
  catch (e) {
    alert("Error2: could not get element id=" + id + ' view=' + asView() + ' auc=' + currentAuction['aid'] + " gave error\n " + e);
  }
}

function displayElemError(id) {
  if (asView() == 'look') return; // these errors need to be taken acount of in code XXXX
  try {
    displayMessage("Error: no page element id=" + id + ' view=' + asView() + ' auc=' + currentAuction['aid'], true);
  }
  catch (e) {
    alert("Could not get element id=" + id + ' view=' + asView() + ' auc=' + currentAuction['aid'] + " displayMessage migave error\n " + e);
  }
}

function displayTime() {
  try {
    var elem = bcfrm.document.getElementById('auctime');
  }
  catch (e) {
    //alert('Error: displayTime() could not get page element view=' + asView() + ' auc=' + currentAuction['aid'] + " gave error\n " + e);
    return;
  }
  if (elem != null) {
    var start;
    if (currentAuction['state'] == 2) start = currentAuction['lock time'];
    else start = currentAuction['start time'];
//alert("display time for aid=" + currentAuction['aid'] + " " + start + " " + currentAuction['state']);
    if (start != null) {
      var now   = new Date();
      var epoch = now.getTime() + lube_offsettime;
      var secs = Math.round( (epoch - start.getTime())/1000 );
      
      secs = Math.abs(secs); //xxxTBD sanity check has right sign  for state
      
      var s_d = secs % 86400;
      var d = Math.round((secs - s_d) / 86400);
      if (d <= 0) timestr =''; 
      else timestr= '<strong>' + d + '</strong>' + 'd  '; 
 //if (d < 10) d = '0'+d;
     
      var s_h = s_d % 3600;
      var h = Math.round((s_d - s_h) / 3600);
      if ((d <= 0) && (h <= 0)) timestr = ''; 
      else timestr= timestr + '<strong>' + h + '</strong>'  +'h  '; 
//      if (h < 10) h = '0'+h;

      var s_m = s_h % 60;
      var m = Math.round((s_h - s_m) / 60);
       if ((d <= 0) && (h <= 0) && (m <= 0)) timestr = ''; 
      else timestr= timestr + '<strong>' + m + '</strong>'  +'m  '; 
//      if (m < 10) m = '0'+m;
      
      var s = s_m
//      if (s < 10) s = '0'+s;
     
      var timestr = timestr + '<strong>' + s + '</strong>'  + 's';
		
			var msg;

      var state = currentAuction['state'];
      
      if ( state >= 2 || state == -1 ) {
        var status;      
        if ( state == 4 || state == 5 || state == -1 ) status = 'started';
        else if  ( state == 2 ) status = 'lock';
        else if  ( state == 3 ) status = 'live';
        
			  //msg = '<p class="start">' + status + ': <strong>'+start.toGMTString() +'</strong></p>';
			  msg = '<p class="start">' + status + ': <strong>'+start.toLocaleString() +'</strong></p>';
        
        if ( state == 4 || state == 5 ) msg += '<p class="elapse">elapsed time: ';
        else if  ( state == 2 ) msg += '<p class="elapse">locking in: ';
        else if  ( state == 3 ) msg += '<p class="elapse">starting in: ';
        else if ( state == -1 ) msg += '<p class="closed"><span>auction closed!</span><br/>duration: ';
        msg +=  timestr + '</p>';        
      }
      else if ( state == -2 ) msg = '<p class="start">Auction cancelled</p>';
      else msg = '<p class="start">Auction state not known</p>';
      
			elem.innerHTML = msg;
			if ( state == 2 || state == 3 || state == 5 ) setTimeout('displayTime()', 1000); // iterate every second
    }
		else {
      var msg;
      if (lube_local) msg = '<p class="start">place a bid to<br/>start the auction</p>';
      else msg = '<p class="start">Auction start time<br/>not yet assigned</p>';
      elem.innerHTML = msg;
		}
  }  
}

function formatDate(da) {
  dy = da.getFullYear() 	// Get full year (as opposed to last two digits only)
  dm = da.getMonth() + 1 	// Get month and correct it (getMonth() returns 0 to 11)
  dd = da.getDate() 	// Get date within month
  ys = new String(dy) 	// Convert year, month and date to strings
  ms = new String(dm) 	 
  ds = new String(dd) 	 
  if ( ms.length == 1 ) ms = "0" + ms; 	// Add leading zeros to month and date if required
  if ( ds.length == 1 ) ds = "0" + ds; 	 
  return ys + "-" + ms + "-" + ds;
}

function displayClose(data) {
  var s = data.split('|');
  var aid = s[0];
  if ( current(aid) ) {
    currentAuction['winBid'] = s[4];
    currentAuction['winFirst'] = unescape( s[1] );
    currentAuction['winLast']  = unescape( s[2] );
    currentAuction['winLoc']   = unescape( s[3] );
    currentAuction['winNick'] = s[5];
    setClosedText();
  }
}

function setClosedText() {
  // clear old stuff
  setElement('placebid', '<p />');
  setElement('bidstat', '<p />');
  
  var bid = currentAuction['winBid'];
  var lastname = currentAuction['winLast'];
  var nickname = currentAuction['winNick'];
  if ( typeof(bid) != 'undefined' ) {
    bid = parseInt(bid);
    if ( bid > -1 ) {
      var textbid = 'lowest unique bid at close: <strong>' + formatCurrency(bid / 100) + '</strong>';
      if (nickname != lastname) textbid += 'placed by <strong>' + nickname + '</strong>';
      var textbidder = '<strong>' + currentAuction['winFirst'] + ' ' + lastname + '</strong><br/>';
      var location = currentAuction['winLoc'];
      if (location != '') textbidder += location;
      
      setElement('closeinfo', "<p id='closedbid'>" + textbid + '</p>' + "<p id='closedbidder'>" + textbidder + '</p>') 
    }
    else {
      var msg = "<p id='closedbid'><strong>no unique bids</strong><br/>lowest bid value with two bids will be selected<br/>";
      msg += 'first bid placed for this value is the successful bid';
      setElement('closeinfo', msg);
    }
  }
}

function lube_addEvent(elem, etype, handler) {
  if (typeof elem.addEventListener == 'undefined')
        elem.attachEvent('on'+etype, handler);
  else  elem.addEventListener(etype, handler, false);
}

function parseUpdate( text ) {
  if (currentAuction == null) return; // ignore all messages
  if (text == null || text == '') return;
  var id,type,val;
  var index = text.indexOf('<upd');
  if (index == -1 ) {
    //alert('Badly formed message ' + text);
    return;
  }

  //var bidupd = 0;
  //var count = 0;
  while ( ( type = getAttribute('typ', text, index) ) != null ) {
    val  = getAttribute('val', text, index);
    //if (type == 'bidupd') bidupd++;
    //count++;
    update_console(id, type, val);
    index = text.indexOf('/>', index);
    if (index == -1 ) {
      //alert('Badly formed message ' + text);
      break;
    }
    else index++;
  }
  //displayMessage('parse: ' + count + ' ' + bidupd);
}

function getAttribute(aname, text, index) {
  var i,j,val = null;
  var index = text.indexOf(aname, index);
  if (index > -1) {
    i = text.indexOf("'", index);
    if (i > -1) {  
      i ++;
      j = text.indexOf("'", i);
      if (j > -1) val = text.substring(i,j);
    }
  }
  return val;
}

// called by onLoad event
function setAuction() {
  displayAuctionItem();
  setVisible( 'placebid', ( currentAuction['state'] == 5 || currentAuction['state'] == 2 ) );
  txa_send( "setauct|" + currentAuction['aid'] ); // request auction data
  stateChange();
  
  // hack to make first bid work in ie7. cold booted machine will not submit
  // bid with just carriage return otherwise.
  
  //var elem = bcfrm.document.getElementById("amount");
  //if (elem != null) elem.focus(); 
  return false;
}

function displayTabs() {
  var tabs = null;
  if (! lube_local) { 
    var s = '<ul>';
    for (var i=0; i<lube_auctions.length; i++) {
      if (lube_auctions[ i ]['enabled'] == 1) {
        var auctid = lube_auctions[ i ]['aid'];
        var title  = lube_auctions[ i ]['acode'];
        if ((currentAuction != null) && (auctid == currentAuction['aid']))
              s += '<li><a class="selected" ';
        else  s += '<li><a class="not_selected" ';
        s += 'href="javascript://" onclick="top.selectAuction('+auctid+')" >'+title+'';
        s += '&#160; <img src="/images/cross.png" onclick="top.deselectAuction('+auctid+')" /></a></li>';
      }
    }
    s += '</ul>';
    setTopElement("submenu", s);
  }
}

function sendRandomBids() {
  randcount++;
  if (randcount <= NUM_RANDOM_BIDS) {
    var bid = randomBid() / 100;
    sendBid( bid + '');
    setTimeout('sendRandomBids()', 200);
  }
  else {
    randcount = 0;
  }
}

function randomBid() {
    return 1 + Math.floor(Math.random() * currentAuction['maxbidval'] * 100);
}

function sendSequentialBids() {
  randcount++;
  if (randcount <= NUM_SEQ_BIDS) {
    var bid = randcount;
    sendBid( bid + '');
    setTimeout('sendSequentialBids()', 200);
  }
  else {
    randcount = 0;
  }
}


function submitBid(form) {
  var bid = form.amount.value;
//  alert('bid=' + bid);
	bid = bid.rtrim().ltrim();
  form.amount.value = '';
  if (bid == '') return;
  else if (bid == 'rand') sendRandomBids();
  else if (bid == 'seq') sendSequentialBids();
  else sendBid(bid);
  form.amount.focus();
  return false;
}

function load(repeats) {
  var html = '';
  for (var i=0; i<repeats; i++) html += i;
}

//tryCount = 0;

function sendBid( bid ) {

/*  if ( attemptBid != '' ) {
    // dont accept bids before have reply from last
    displayMessage('please wait for the status of your last bid, bid <b>'+ formatCurrency(bid) +'</b> not placed', true);
    if (tryCount++ > 0) attemptBid = '';
    return;
  }
  else tryCount = 0;
*/
  
  if ( ! checkCurrency(bid) ) {
    displayMessage('invalid value: <b>"'+bid+'"</b> is not a valid bid', true);
  }
  else if (bid < currentAuction['minbidval']) {
    displayMessage('invalid bid value: <b>'+bid+'</b> is too low', true);
  }
  else if (bid > currentAuction['maxbidval']) {
    displayMessage('invalid bid value: <b>'+bid+'</b> is too high', true);
  }
  else {
    var moneyStr = formatCurrency(bid);
    var bids = currentAuction['bids'];
    if ( attemptBid == moneyStr || getBidTableRow(bids, moneyStr) != -1) {
      displayMessage('you have already placed bid value: <b>'+moneyStr+'</b>!', true);
      if ( typeof(testmode) == 'undefined' || ! testmode ) return;
    }
    attemptBid = moneyStr;
    
    bidcent = toPence(bid);
    var data = 'bid|'+ currentAuction['aid'] +'|'+bidcent;
    if (lube_local) data += '|'+ nickname;
    txa_send(data);
  }
}

// initialisation or state change or data update
function setState(data) {
  var s = data.split('|');

  var aid = s[0];
  var auc = getAuction(aid);
  
  auc['state'] = parseInt(s[1]);
  
  if ( current(aid) ) setConsoleView();
}

// initialisation or state change or data update
function initAuction(data) {
  var s = data.split('|');

  var aid = s[0];
  var auc = getAuction(aid);
  
  auc['title'] = s[1];
  auc['value'] = s[2];
  auc['type']  = s[3];
  auc['state'] = parseInt(s[4]);
  auc['booked'] = (1 == parseInt(s[5])); // boolean from 1 = booked
  if (!auc['xbooked']) auc['booked'] = false; 
  auc['minbidval'] = parseFloat(s[6]);
  auc['maxbidval'] = parseFloat(s[7]);
  auc['bidsperseat'] = parseInt(s[8]);

  if (s[9] > 0) {
	  var d = new Date(parseInt(s[9]));
    auc['lock time'] = d;
  }  
  if (s[10] > 0) {
	  d = new Date(parseInt(s[10]));
    auc['start time'] = d;
  }  
  if (s[11] > 0) {
    clockSynch( parseInt(s[11]) );
  }

  if ( s[12] != '' ) auc['image path'] = s[12];
  
// alert('initialised auction ' + aid + ' ' + auc['start time'] + ' path=' + auc['image path']);
  
  if ( current(aid) ) setConsoleView();
}

// compute offset between server timestamp and user machine
function clockSynch(serverTime) {
  if ( checkInteger(serverTime) && serverTime > 0) {
    d = new Date();
    lube_offsettime = serverTime - d.getTime();
    // alert('lube_offsettime mins=' + lube_offsettime/60000);
    //if (Math.abs(lube_offsettime) < 5000) lube_offsettime = 0;
  }
}

function displayAuctionItem() {
  setElement('banner_left', currentAuction['title']);
  setElement('banner_right', currentAuction['type'] + ': ' + stateText( currentAuction['state'] ) );

  if (currentAuction['image path'] != '') {
    try {
      var el = bcfrm.document.getElementById( 'auc_image' );
      el.setAttribute('src', currentAuction['image path']);
    }
    catch (e) {
      //alert('Error: displayAuctionItem() could not get page element auc_image view=' + asView() + ' auc=' + currentAuction['aid'] + " gave error\n " + e);
    }
  }

  setElement('minbidval', formatCurrency(currentAuction['minbidval']) );
  
  setElement('maxbidval', addCommas(formatCurrency(currentAuction['maxbidval'])) );
  
  var valuation = formatCurrency(currentAuction['value'])
  setElement('valuation', addCommas(valuation) );
  
  try {
    var el = bcfrm.document.getElementById( 'titlebanner' );
  
    var img = bannerImage(currentAuction['state']);
    if (img != '') el.style.backgroundImage = 'url("' + ICON_IMAGE_DIR + img + '")';
  }
  catch (e) {
      //alert('Error: displayAuctionItem() could not get page element titlebanner view=' + asView() + ' auc=' + currentAuction['aid'] + " gave error\n " + e);
  }
}

function bannerImage(state) {
  switch(state) {
    case 5: return 'livebanner.jpg'; //live
    case 4: return 'pausedbanner.jpg'; //paused
    case 3: return 'lockedbanner.jpg'; //locked
    case 2: return 'bookingbanner.jpg'; //booking
    case -1: return 'closedbanner.jpg'; //closed
    case -2: return 'cancelledbanner.jpg'; // cancelled
    default: return ''; // other ()
  }
}

function clearMessages() {
  currentAuction['bemsg'] = '';
  setElement('bemsgs', '');
}

function displayMessage(msg, err) {
  var bg = 0;
  if (lube_msgs % 2 == 1) bg = 1;
  if ((err != null) && (typeof(err) != 'undefined')) bg = 'err'; 
  lube_msgs++;
  var hist = currentAuction['bemsg'];
  hist = '<span class="bemsg'+bg+'">'+getTimestamp()+'</span>'+'<span class="bemsg'+bg+'">'+msg+'</span><br />' + hist;
  currentAuction['bemsg'] = hist;
  
  displayMessages();
}

function displayMessages() {
  var hist = currentAuction['bemsg'];
  if (bcfrm == null) bcfrm = top.frames['bidconsole'];
  try {
    var el = bcfrm.document.getElementById( 'bemsgs' );
    if (el != null) el.innerHTML = hist;
  }
  catch (e) {
    alert('Error: displayMessages() could not get page element view=' + asView() + ' auc=' + currentAuction['aid'] + " gave error\n " + e);
  }
}

function getTimestamp() {
  var now = new Date();
  now = new Date( now.getTime() + lube_offsettime );
  var date = zeropad(now.getHours()) + ":" + zeropad(now.getMinutes()) + ":" + zeropad(now.getSeconds());
  //var date = zeropad(now.getUTCHours()) + ":" + zeropad(now.getUTCMinutes()) + ":" + zeropad(now.getUTCSeconds());
  date += ' -&#160;';
  return date;
}

function zeropad ( item ) {
  if (item < 10) item = '0' + item;
  return item;
}

function toPence(pence) {
  return Math.round(pence * 100);
}
function formatCurrency( val ) {
	if( isNaN(val) ) { return null; }
	val = Math.abs(val);
	val = toPence(val);
	val = val / 100;
	var s = new String(val);
	if(s.indexOf('.') < 0) { s += '.00'; }
	if(s.indexOf('.') == (s.length - 2)) { s += '0'; }
	return s + ' ';
}

function checkCurrency( str ) {
	if ( str.match(/^[0-9]{0,12}(\.[0-9]{1,2})?$/) ) return true;
  else return false; 
}

function checkInteger(n) {
  return (n == Math.floor(n));
}

function checkSeq(inp) {
  var s = inp.split('|');
  var msgseq = s[1];
  
//  displayMessage("msgseq="+msgseq+" aucseq="+ aucseq);
  if (msgseq != lube_seqno) {
    displayMessage("comms : got "+msgseq+" expected "+ lube_seqno +" - reinitialising");
    //txa_send( "getinit|"+ auc['aid'] );
  }
  else {
    //displayMessage("comms : correctly got "+ lube_seqno);

  }
}

// receives the xml string, parses it and updates the console.
// we do not use the built in xml parser

function update_console(id, type, val) {
//  alert("cmd="+type + " val=" + val); // debug
  try {
    if (type == 'seq') {
      checkSeq(val);
    }
    else if (type == 'setinit') {
      attemptBid = '';
      initAuction(val);
    }
    else if (type == 'setstate') {
      setState(val);
    }
    else if (type == 'bidupd') {
      updateAuction(val);
    }
    else if (type == 'summary') {
      updateSummary(val);
    }
    else if (type == 'leaderb') {
      updateLeaderBoard(val);
    }  
    else if (type == 'flips') {
      updateFlips(val);
    }  
    else if (type == 'progress') {
      updateProgress(val);
    }  
    else if (type == 'msg') {
      displayMessage(val);
    }
    else if (type == 'errmsg') {
      attemptBid = ''; // xxx TBD make sure get ermsg for all conditions
      //alert('=' + val);
      displayMessage(val, true);
    }
    else if (type == 'close') {
      logout();
    }
    else if (type == 'prompt') {
      displayPrompt();
    }
    else if (type == 'closestate') {
      displayClose(val);
    }
    else displayMessage('unknown command (' + type + ')');
  }
  catch (e) {
  //   alert("cmd="+type + " val=" + val + " gave error " + e);
  }
}

function logout() {
  if (!lube_local) closecomms();
  var elem = document.getElementById("logout");
  if ( elem == null ) {
    alert("Session logged out");
    return;
  }
  elem.click();
}

function displayPrompt() {
  var elem = document.getElementById("areyouthere");
  if ( elem == null ) return; //err
  elem.style.visibility='visible';
}

function answerPrompt() {
  txa_send("prompt");
  var elem = document.getElementById("areyouthere");
  if ( elem == null ) return;
  elem.style.visibility='hidden';
  return false;
}

function updateProgress( data ) {
  if (currentAuction == null) return;
  var inp = data.split('|'); // last element empty
  if (inp.length > 3) {
    //aid not transmitted with this message
    if (!lube_local) clockSynch( parseInt(inp[0]) );
    setInk(inp[1], inp[2], inp[3]);
  }
}

function setInk(total, left, right) {
  var div = bcfrm.document.getElementById('tube');
  if (div != null) {
    div.style.width = total;
    div = bcfrm.document.getElementById('inkleft');
    div.style.width = left + 'px';
    div = bcfrm.document.getElementById('inkright');
    div.style.width = right + 'px';
  }
  // tbd else errmsg
}

function updateSummary(data) {
  if (currentAuction == null) return;
  var inp = data.split('|'); // last element empty
  if (inp.length > 1) {
    var aid = inp[0];
    if (! current(aid) ) return;
    if ( currentAuction['state'] < 2 ) return;
    if (currentAuction['booked'] ) {
      setElement('bidsplacednum', inp[2]);
      if (currentAuction['state'] == 3) setVisible('bidsmax', false);
      else setElement('bidsmaxnum', inp[1]);
    }
  }
}

function updateFlips(data) {
  if (currentAuction == null) return;
  var inp = data.split('|'); // last element empty
  if (inp.length > 1) {
    var aid = inp[0];
    if (! current(aid) ) return;
		var auc = getAuction(aid); 
    var flips = auc['flips'];
		var j = inp.length-1;
    for (var i=j-1; i>0; i--) {
      var diff = inp[i].split(',');
      remove(flips, diff[0]);
			flips[flips.length] = diff[0];
      if (diff[1] == '+') displayMessage( 'your bid of ' + formatCurrency(diff[0]/100) + ' is now the lowest unique bid!' );
      else if (diff[1] == '-') displayMessage( 'your bid of ' + formatCurrency(diff[0]/100) + ' is no longer the lowest unique bid' );
		}
    displayFlips();
  }
}

function displayFlips() {
  if ( asView() != 'live' ) return;
  var flips = currentAuction['flips'];
  var s = '';
  // show most recent entries
  var headstart = Math.max(0, flips.length - FLIPS_SHOW);
  for (var i=headstart; i<flips.length; i++) {
    var amnt = flips[i];
    var money = formatCurrency(amnt / 100);
    s += '<span onclick="top.showBids(' + currentAuction['aid'] + ', ' + money + ', true, true)"><a>' + money + '</a></span>';
    
    if (i < flips.length-1) s += '<span>&#149;</span>';
  }
  if (flips.length > FLIPS_SHOW) s = '<span>&#149;</span>' + s;
  setElement('flips', s);
}

//remove item from array
function remove(array, item) {
	var i = 0;
	while (i < array.length) {
		if (array[i] == item) {
			array.splice(i, 1);
			break;
		}
		else i++;
	}
}

function updateLeaderBoard( data ) {
  if (currentAuction == null) return;
  var inp = data.split('|'); // last element empty
  if (inp.length > 1) {
    var aid = inp[0];
    if (! current(aid) ) return;
    
    var tbl = bcfrm.document.getElementById('lead');
    if (tbl == null) {
      displayElemError('lead');
      return;
    }
    
    var i;
    for (i=1; i<inp.length-1; i++) {
      var leader = inp[i];
      if (leader == 'null') leader = '---';
      displayLeader(tbl, i, leader);
    }
    // delete any excess rows
    var count = inp.length-2;
    clearLeaderBoard(tbl, count);
    if (count == 0) displayMessage('NO BID is currently unique!');
    //      else if (count == 1) displayMessage(inp[1] + ' has the only unique bid!');
    else if (count == 1) displayMessage('currently only ' + count + ' bid is unique' );
    else if (count < 10) displayMessage('currently only ' + count + ' bids are unique');
  }
}

function clearLeaderBoard(tbl, rows) {
  if (clearLeaderBoard.arguments.length == 0) rows = 0;
  while (tbl.rows.length > rows) { 
    tbl.deleteRow(tbl.rows.length-1);
  }
}

function displayLeader(tbl, pos, leader) {
  var lead_elid  = 'lead_'+pos;
  var row = getLeaderRow(tbl, lead_elid);
  row.cells[0].innerHTML = leader;
  row.cells[0].className = 'bidder';
  row.cells[1].innerHTML = "<img src='" + ICON_IMAGE_DIR + "leader"+pos+".png' border='0' />";
  row.cells[1].className = 'number';
}

function getLeaderRow(tbl, rowid) {
  var row = bcfrm.document.getElementById( rowid );
  if (row == null) {
    var c = tbl.rows.length;
    row = tbl.insertRow(c);
    row.id = rowid;
    row.className = 'bidline';
    row.insertCell(0);
    row.insertCell(0);
  }
  return row;
}

function updateAuction( data ) {
  if (currentAuction == null) return;
  //displayMessage("updateAuction="+data);
  var inp = data.split('|');
  if (inp.length > 1) {
    var aid = inp[0];
    if (! current(aid) ) return;
    var fresh = (inp[1] == 'y');
    var bids = currentAuction['bids'];
		if (fresh) currentAuction['focus'] = attemptBid;
    
    for (var i=2; i<inp.length; i++) {
      var chg = inp[i].split(',');
      if (chg.length == 2) {
        updateBid(bids, chg[0], chg[1]);
        if (fresh && chg[1] == 1) {
          var money = formatCurrency(chg[0]/100);
          if (money == attemptBid) displayMessage('your bid of ' + money + ' is the lowest unique bid!');
        }
      }
    }
    sortbids(bids);
		showBids(aid, currentAuction['focus'], fresh, false);
    if (fresh) attemptBid = ''; // finished processing
  }
}

// update the scrolling bid display
function showBids(aid, focus, doScroll, removeFlip) {
  //alert('showbids aid=' + aid + ' focus=[' + focus + '] doscroll=' + doScroll);
  if (! current(aid)) return;
	var bids = currentAuction['bids'];
  if ( focus == '' && bids.length > 0 ) focus = bids[0][0];
	var rownum;
  if (focus == '') rownum = 0;
  else {
    focus = formatCurrency(focus);
    currentAuction['focus'] = focus;
    rownum = getBidTableRow(bids, focus);
  }
	var topPad = redisplayBids(aid, bids, rownum, focus);
	if (doScroll) setScroll(rownum + topPad - NUM_BIDROWS_ABOVE);
	if (removeFlip) {
		var flips = currentAuction['flips'];
		remove(flips, toPence(focus));
		displayFlips();
	}
}

function getBidTableRow(bids, amnt) {
  for (var i=0; i < bids.length; i++) {
    if (bids[i][0] == amnt) return i;
  }
  return -1;
}

function setScroll(j) {
  var div = bcfrm.document.getElementById( 'auctscroll' );
  if (div != null) {
    if (j < 0) j = 0; 
    div.scrollTop = j * BIDROW_HEIGHT;
  }
  else displayElemError('auctscroll');
}

function clearBidStatus() {
  var tbl = bcfrm.document.getElementById('auct');
  if (tbl != null) {
    while (tbl.rows.length > 0) { 
      tbl.deleteRow(0);
    }
  }
  else displayElemError('auct');
}

function updateBid(bids, amnt, bstat) {
  var amnt = formatCurrency(amnt / 100);
  var pos = -1;
  for (var i=0; i<bids.length; i++) {
    if (bids[i][0] == amnt) {
      bids[i][1] = bstat;
      pos = i;
      break;
    }
  }
  
  // see if this a new bid in which case we create a new entry
  if (pos == -1) {
    pos = bids.length; 
    bids[pos] = new Array(2);
    bids[pos][0] = amnt;
    bids[pos][1] = bstat;
  }
}

// return amount of top padding
function redisplayBids(aid, bids, currentIndex, focus) {
  //displayMessage("index="+currentIndex);
  var pad = bcfrm.document.getElementById('scrollpadtop');
  if (pad == null) displayElemError('scrollpadtop');
  else {
    var toppadrows = Math.max(0, NUM_BIDROWS_ABOVE - currentIndex);
    pad.style.height = (toppadrows * BIDROW_HEIGHT + SCROLL_ADJUST) + 'px'; //add scroll fudge factor
  }
  
  pad = bcfrm.document.getElementById('scrollpadbot');
  if (pad == null) displayElemError('scrollpadbot');
  else {
    if (currentIndex > NUM_BIDROWS_ABOVE) { // may need padding below
      var botpadrows = 1 + Math.max(0, NUM_BIDROWS_BELOW - bids.length + currentIndex + 1); // number rows below current bid
      //displayMessage("pad rows below="+botpadrows);
      pad.style.height = (botpadrows * BIDROW_HEIGHT) + 'px';
    }
    else pad.style.height = 0;
  }
  
  for (var i=0; i<bids.length; i++) {
    displayBid(i, bids[i][0], bids[i][1], focus);
  }
  return toppadrows;
}

function displayBid(pos, amnt, bstat, focus) {
  var bid_elid  = 'bid_'+pos;
  var row = getBidRow(bid_elid);
  var big = '';
  row.cells[0].innerHTML = amnt;
// displayMessage('amnt='+amnt +' focus='+focus);
  if (amnt == focus) {
    row.className = 'justbid';
    big = 'big';
  }
  else row.className = 'bidrow';
  row.cells[0].className = 'bidamount';
//displayMessage("bstat="+bstat+" amount="+amnt);
  // bstat: -1 queued, 0 none, 1-5 status code
  row.cells[1].innerHTML = "<img src='" + ICON_IMAGE_DIR + "bidstatus"+bstat+big+".png' border='0' />";
  row.cells[1].className = 'bidicon';
}

function getBidRow(rowid) {
  var row = bcfrm.document.getElementById(rowid);
  if ( row == null ) {
    var tbl = bcfrm.document.getElementById('auct');
    if (tbl != null) {
      var c = tbl.rows.length;
      row = tbl.insertRow(c);
      row.id = rowid;
      row.insertCell(0);  
      row.insertCell(1); 
    }
    else displayElemError('auct');
  }
  return row;
}

function sortbids(bids) {
  bids.sort( sortcmp );
  
  function sortcmp(a, b) {
    if (b == null) return 9999999;
    if (a == null) return -9999999;
    return b[0] - a[0];
  }
}
  
// -------------------------------------------
// class - provides Java like HashMap behavior
// -------------------------------------------
function Lube_HashMap() {
  this.all = '|';
  this.size = 0;
}

Lube_HashMap.prototype = {
  
  get : function(name) {
    if ((name != null) && (name != '')) {
      if (name == '*') name = "asterix_";
      name = name.replace(/-/g, "_minus_");
      var v = eval('this.'+name);
      if (typeof(v) != 'undefined') return v;
    }
    return null;
  },
  
  put : function(name,value) {
    var realname = name;
    if ((name != null) && (name != '')) {
      if (name == '*') name = "asterix_";
      name = name.replace(/-/g, "_minus_");
      var _value =value;
      eval('this.'+name+'=_value');
      if (this.all.indexOf('|'+realname+'|') == -1) {
        this.all += realname+'|';
        this.size++;
      }
    }
  },
  
  remove : function(name) {
    var realname = name;
    if ((name != null) && (name != '')) {
      if (name == '*') name = "asterix_";
      name = name.replace(/-/g, "_minus_");
      var i = this.all.indexOf('|'+realname+'|');
      if (i > -1) {
        eval('this.'+name+'=null');
        this.all = this.all.substring(0, i) + this.all.substring(i+realname.length+1);
        this.size--;
      }
    }
  },
  
  keys : function() {
    if (this.all.length > 1) {
      var keys = this.all.substring(1).split('|');
      return keys;
    }
    return null;
  }
 
}

// ------------------------------------------------------------------------
// the Lube_Comms object is used for all communications.
// it can operate using xmlhttp or via an iframe as xmlhttp
// object can get blocked by personal firewalls like norton.
// can operate in synchronous or asynchronous mode. in asynch mode
// it will queue requests. always waits for a response before sending
// the next message.
// ------------------------------------------------------------------------
function Lube_Comms(_name, _source, _callback, _useq, _useo) {
  this.name   = _name;
  this.source = _source;
  this.callback = _callback;
  this.useq = _useq;
  this.async = this.useq;
  this.useo = _useo;
  this.conn = _useo ? null : this.getHTTPObject();
  this.qlen  = 20;
  this.queue = new Array(this.qlen);
  this.qip   = 0;
  this.qop   = 0;
  this.tmp   = null;
  this.gotdata = false;
  this.errmsg = null;
}

Lube_Comms.prototype = {

  // callback is passed in the constructor but we also allow it to be reset 
  
  setCallback : function(_callback) {
    this.callback = _callback;
  },
  
  // sends the request. if we are in asynchronous mode then we
  // queue the request and only pass it on directly if this is
  // the first in the queue.
  
  send : function(cmd, instance) {
    var inst = this;
    if ((instance != null) && (typeof(instance) != 'undefined')) inst = instance;
    if (inst.useq) {
      if (cmd != null) {
        if (inst.putQ(cmd)) {
          cmd = inst.getQ();
          inst.recv(cmd);
        }
      }
      else {
        
        // here if called by 'done' in async mode
        
        cmd = inst.getQ();
        if (cmd != null) inst.recv(cmd);
      }
    }
    else {
      
      // here if a synchronous request
      
      inst.recv(cmd);  
    }
  },
  
  // only used in asynchronous mode. it is called by the 'callnext' function
  // remove the request from the queue and to cause the next one to be sent.
  
  done : function() {
    if (this.useq) {
      if ( !this.delQ() ) setTimeout(this.name+'.send(null,'+this.name+')', 1);
    }
  },
  
  // this does the actual send and sets up to receive a reply
  // it currently aborts everthing and starts again as this avoids the
  // many problems we have found with the xmlhttp object.
  // TBD: this could be made browser specific
  
  recv : function(cmd) {
    var conn = this.conn;
    if (conn.readyState != 4 && conn.readyState != 0) {
      //alert(' dbug: aborting comms');
      this.abort();
    }
    if (conn != null) {
      conn = this.getHTTPObject();
      this.conn = conn;
    }
    this.gotdata = false;

    // set up html request string
    
//    debug.msg('recv: ' + cmd);
    var req = this.source;
    if (cmd != null) {
      cmd = escape(cmd);
      req = req.replace('ccmmdd', cmd);
    }  

    // we always add a random element to prevent caching
    // TBD xxx clashes????

    if (req.indexOf('?') > -1) req += '&rand=' + this.rand();
    else                       req += '?rand=' + this.rand();

    // now issue the request
    
    if (conn != null) {
//alert("conn="+(conn != null)+" readystate="+conn.readyState+" req="+req);
 	    if (conn.readyState == 4 || conn.readyState == 0) {
        conn.open("GET", req, this.async);
        if (this.async) conn.onreadystatechange = this.callback;
        try      { conn.send(null); }
        catch(e) { conn.send(null); }
      }
      if ((!this.async) && (this.callback != null)) this.callback(this);
	  }
    else {
      var frm = open(req, 'lube_commframe');
    }
  },

  rxHandler : function() {
    var conn = this.conn;
    
    // in w2k-firefox, reading the status can cause exceptions so we trap these
    // also callback can get called twice sometimes so we check 'gotdata'
    
    var status = -1;
    try { status = conn.status; } catch(e) {} 
//    alert("status="+status);
    if (lube_local && (status == 0)) status = 200;
    
    if (!this.gotdata) {
      if ((conn.readyState == 4) && (status == 200)) {
        this.gotdata = true;
        var data = conn.responseText;
//      if (data == '') alert("no data status=" + status);
        return data;
      }
      else if ((conn.readyState == 4) && (status != 200) && (status != 0)) {
        var readyState = conn.readyState;
        this.errmsg = 'read error: name='+this.name+' state='+readyState+' status='+status;
        //conn.abort();
      }
    }

    return null;
  },

  // get error status
  
  geterr : function() {
    var errmsg = this.errmsg;
    this.errmsg = null;
    return errmsg;
  },
  
  // abort the current read
  
  abort : function() {
    if (this.conn != null) {
      this.conn.abort();
      this.conn.abort();
    }
  },

  // abort the current read
  
  clearQ : function() {
    this.qip = 0;
    this.qop = 0;
  },

  // add a message to the queue
  // we check to see if this is the only message in the queue
  // and return true if that is the case
  
  putQ : function(msg) {
    var first = (this.qip == this.qop);
    this.queue[ this.qip ] = msg;
    this.qip++;
    this.qip = this.qip % this.qlen;

    // check we are not overwriting the tail of the queue
    // if we are then we drop the oldest item
    
    if (this.qip == this.qop) {
//      debug.msg('queue overrun: dropping message');
displayMessage("queue overrun: dropping message="+msg);
      this.qop++;
      this.qop = this.qop % this.qlen;
    }
    
    return first;
  },
 
  // get a message from the queue
  // we do not delete it from the queue until we
  // have received a response
  
  getQ : function() {
    var msg = null;
    if (this.qip != this.qop) {
      msg = this.queue[ this.qop ];
    }
    return msg;
  },

  // delete a message from the queue.
  
  delQ : function() {
    if (this.qip != this.qop) {
      this.qop++;
      this.qop = this.qop % this.qlen;
    }
    return (this.qop == this.qip);
  },

  rand : function() {
    var r = Math.floor(Math.random() * 1000000);
    return r;
  },
  
  //instantiates an XMLHttpRequest object in a browser independent way

  getHTTPObject : function() {
    var xmlhttp;
    /*@cc_on
    @if (@_jscript_version >= 5)
      try {
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
      } catch (e) {
        try {
          xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (E) {
          xmlhttp = false;
        }
      }
    @else
    xmlhttp = false;
    @end @*/
    if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
      try {
        xmlhttp = new XMLHttpRequest();
      } catch (e) {
        xmlhttp = false;
      }
    }
    return xmlhttp;
  }
}  

// -------------------------------------------
// now start the tx comms channels
// -------------------------------------------

// deals with responses to commands.
// most commands that are sent just get 'OK' back.
// if a command gets anything longer in response then we treat
// it as a response that needs interpreting.

function lube_tx(inst) {
  var tmp = inst.rxHandler();
  var err = lube_txasync.geterr();
  if ( err != null ) {
//    displayMessage(err);
    displayMessage("Problem with connection- try reloading page", true);
  }
  else if (tmp != null) {
    tmp = tmp.rtrim();
    if (tmp != 'OK') {
      parseUpdate(tmp);
    }
    inst.done();
  }
}

// just a dummy. gets reset via setCallback
function lube_rx() {}

function lube_txasync_h() { lube_tx(lube_txasync); }

// handlers that call the generic handler.
// the xmlhttp object calls an event handler without passing anything to give you
// a clue as to which xmlhttp object caused the event so you have to have individual
// event handlers for each object... don't get me started !

function lube_txasync_h() { lube_tx(lube_txasync); }
function lube_txsync_h()  { lube_tx(lube_txsync);  }

// instantiate a tx and rx comms channel.

function initcomms_con() {
  
  // get the comms object for receiving commands
  // and set the rx handler callback to our local function

  if ((typeof(lube_txasync) != 'undefined') && (lube_txasync != null)) {
    lube_txasync.abort();
  }
  
  lube_txasync = new Lube_Comms('lube_txasync', '/pub?pg=console.send&uid='+lube_uid+'&cmd=ccmmdd', lube_txasync_h, true, false); 
}


// we get a copy of the console
//xxx TBD just load as needed and cache
function fetchConsoles() {
  var lube_rxsync;
  var view;
  //if (!lube_local)
  lube_rxsync = new Lube_Comms('lube_rxsync', '/pub?pg=ccmmdd', fetchrx, false, false);
  //else  lube_rxsync = new Lube_Comms('lube_rxsync', '/ccmmdd'+'.html', fetchrx, false, false);
  
  lube_consoles = new Lube_HashMap();
  
  view = 'live'; lube_rxsync.send('console_live.ifrm'); // paused same as live but no submit box
  if (!lube_local) {
    view = 'none'; lube_rxsync.send('console_none.ifrm');
    view = 'look'; lube_rxsync.send('console_look.ifrm');
    view = 'qbid'; lube_rxsync.send('console_qbid.ifrm'); // locked same as qbid but no submit box
  }  
  
  function fetchrx() {
    var tmp = lube_rxsync.rxHandler();
    if (tmp != null ) {
      if (tmp.toLowerCase().indexOf("error") > -1) alert("error loading view: "+view);
      else lube_consoles.put(view, tmp);
    }
  }
}

function closecomms() {
  if ((typeof(lube_rxasync) != 'undefined') && (lube_rxasync != null)) lube_rxasync.abort();
  if ((typeof(lube_txasync) != 'undefined') && (lube_txasync != null)) lube_txasync.abort();
}

// local handler to issue the reads through the rx comms object

function lube_issueRead() {
  if (!lube_readIssued) {
    lube_readIssued = true;
    lube_rxasync.recv(null);
  }
}

// the rx callback function
// this processes the incoming command

function lube_rx() {
  if ( typeof(lube_rxasync) == 'undefined' ) return;
  var tmp = null;
  try { tmp = lube_rxasync.rxHandler(); 
  } catch(e) {alert("read failed:"+e);}
  if (tmp != null ) {
//    alert("tmp="+tmp);
    try { lube_processRead(tmp); } catch(e) { alert("process read failed"); }
    
    setTimeout('lube_issueRead()', 1);
  }
}
  
function lube_processRead(xmlstr) {
  lube_readIssued = false;
  var to = xmlstr.indexOf("timeout");
  if (to == -1) {
    //try
    { parseUpdate(xmlstr); }
    //catch(e) { alert('UPDATE EXCEPTION: '+e); };
  }
  else {
    //      top.debug.msg('NO COMMAND: '+tmp);
  }
}

lubeinit();

