
/*
 * Live Betting Event Static JS (using Orbis LiveServ)
 */

// ensure CVS revision number survives minification
var dummy = '$Id: lb_evt.js,v 1.1.6.34 2010-07-26 16:37:20 dmondeja Exp $';

/* -------- PUBLIC API -------- */

/*
 * Initialise the Live Betting Event Area (& Customise Markets area).
 * Params:
 *   event       = initial state of event
 *   evmkts      = initial state of markets
 *   selcns      = initial state of selections
 *   init_msg_id = last push message id at time initial state was queried
 *   cfg         = config item object; see _lb_evt_cfg for details.
 */
function lb_evt_init(event, evmkts, selcns, init_msg_id, cfg, templates) {

	_lb_evt_store_templates(templates);

	_lb_evt_ev_id       = event.ev_id;
	lb_evt_ev_id       = event.ev_id;

	for (var f in cfg) _lb_evt_cfg[f] = cfg[f];

	// Pretend that the initial state we've just been given has been received
	// as push server messages.

	_lb_evt_got_EVENT(event);
	for (var i = 0; i < evmkts.length; i++) {
		_lb_evt_got_EVMKT(evmkts[i], true);
	}
	lb_evt_upd_market_orders();
	for (var i = 0; i < selcns.length; i++) {
		_lb_evt_got_SELCN(selcns[i]);
	}

	// Normally this happens automatically; however for efficiency
	// we've told the market msg handler to skip it for our first build.
	_lb_evt_mkts_count_refresh();

	// Subscribe to event itself and its children.

	var padded_ev_id = ps_connect_lpad_id(_lb_evt_ev_id);
	var channels = ["sEVENT" + padded_ev_id, "SEVENT" + padded_ev_id];
	ps_connect_register
	  ("lb_evt", _lb_evt_got_msg, channels, init_msg_id);

	return;
}

/* -------- HTML TEMPLATES and ELEMENT IDs -------- */

/*
 * These are the element ids (or prefixes thereof) with special meaning.
*/

var _lb_evt_event_area_id             = "lb_evt_content";
var _lb_evt_mkts_id                   = "markets";
var _lb_evt_mkt_id_prefix             = "market ";
var _lb_evt_selcns_id_prefix          = "mkt_selcns_";
var _lb_evt_selcn_id_prefix           = "selcn_";
var _lb_evt_price_class_name          = "odd";
var _lb_evt_selcn_highlight_id_prefix = "lb_evt_price_con_";
var _lb_evt_price_str_id_prefix       = "lb_evt_price_str_";
var _lb_evt_stake_id_prefix           = "lb_evt_stake_";
var _lb_evt_fb_stake_id_prefix        = "lb_evt_fb_stake_";
var _lb_evt_num_avail_mkts_id         = "enum_avail_mkts";

// used by _lb_evt_highlight
var _lb_evt_highlight_timers = {};

// A generic object to access the hashes in this file.
function lb_evt_object () {
	// Do nothing. We're only interested in the subclasses.
	return;
}

lb_evt_object.prototype.getConfig = function() {

	return _lb_evt_cfg;
}

// Accessor subclasses.
lb_evt_object.prototype.getHash = function(identifier) {

	var ret = "";

	switch(identifier) {
		case "HL_TIMERS":
			if (_lb_evt_highlight_timers) {
				ret = _lb_evt_highlight_timers;
			}
			break;
		default:
			ret = "";
	}

	return ret;
}

lb_evt_object.prototype.getHashId = function(identifier, id) {

	var ret = "";

	switch(identifier) {
		case "HL_TIMERS":
			if (_lb_evt_highlight_timers && _lb_evt_highlight_timers[id]) {
				ret = _lb_evt_highlight_timers[id];
			}
			break;
		default:
			ret = "";
	}

	return ret;
}

lb_evt_object.prototype.getMiscInfo = function(identifier) {

	var ret = "";

	switch(identifier) {
		case "PRICE_CLASS_NAME":
			if (_lb_evt_price_class_name) {
				ret = _lb_evt_price_class_name;
			}
			break;
		default:
			ret = "";
	}

	return ret;
}

lb_evt_object.prototype.getIdPrefix = function(identifier) {

	var ret = "";

	switch(identifier) {
		case "SELCN_HL":
			if (_lb_evt_selcn_highlight_id_prefix) {
				ret = _lb_evt_selcn_highlight_id_prefix;
			}
			break;
		default:
			ret = "";
	}

	return ret;
}

lb_evt_object.prototype.gotPushData = function(identifier, data) {

	switch(identifier) {
		case "PRICE":
			_lb_evt_got_PRICE(data);
			break;
		case "SELCN":
			_lb_evt_got_SELCN(data);
			break;
		case "MHCAP":
			_lb_evt_got_MHCAP(data);
			break;
		case "EVMKT":
			_lb_evt_got_EVMKT(data);
			break;
		case "EVENT":
			_lb_evt_got_EVENT(data);
			break;
		default:
			// Unknown message.
	}

	return;
}

// Create a generic object to access the hashes in this file. This is the handler.
var lb_evt_obj = new lb_evt_object();

// Create a new comparsion object.
var lb_evt_cmp_objects = new function () {};
lb_evt_cmp_objects = new push_hash_cmp_objects();

// We must overwrite the cmpEvMkts function.
lb_evt_cmp_objects.cmpEvMkts = function (cmpMode, evmktA, evmktB) {

	var d = evmktA.disporder - evmktB.disporder;

	if (d) {
		return d;
	}

	return  evmktA.ev_mkt_id - evmktB.ev_mkt_id;

	return d;
}

/*
* These variables hold the original ordering of markets
* as well as the ordering set up by the customer if they
* drag stuff about.
*/
var _lb_evt_market_ordering = {};
var _lb_evt_market_original_ordering = {};

/*
 * These are the templates used to construct and update the live betting
 * event page and customise markets area. See tmpl.js for syntax details.
 */
function _lb_evt_store_templates(templates) {

	for (tmpl_name in templates) {
		tmpl_value = templates[tmpl_name];
		tmpl_store(tmpl_name, tmpl_value);
	}

	return;
}

/* ---------- PRIVATE --------- */

// Default config items: (can be overriden by lb_evt_init call) */
var _lb_evt_cfg = {
	lang                    : "en",
	price_str_type          : "ODDS",
	price_str_type_ah       : "DECIMAL",
	price_str_type_hl       : "DECIMAL",
	price_str_sep           : "-",
	quickbet_amounts        : [10, 25, 50],
	highlight_duration      : 4000,
	img_url                 : "/img",
	bir_sort                : "--",
	hl_class_decrease       : "_d",
	hl_class_increase       : "_i",
	hl_class_same           : ""
};

var _lb_evt_ev_id            = -1;
// Create a global one that can be accessed by other files
var lb_evt_ev_id            = -1;
var _lb_evt_event            = null;
var _lb_evt_evmkt_hash       = {};
var _lb_evt_selcn_hash       = {};
var _lb_evt_new_mkt_timers   = {};

/* These are used by the flash header thing for horse-racing */
var _lb_hr_evt_last_msg_id   = -1;
var _lb_hr_evt_event         = {};
_lb_hr_evt_event.name = '';
_lb_hr_evt_event.BIDS_status = '';

var _lb_evt_lowest_disporder = 9999999;
var _lb_evt_lowest_disporder_ev_mkt_id = -1;
var _lb_evt_redirect_timer = null;

/*
 * Called whenever we receive any published message from the Push Server.
 */
function _lb_evt_got_msg(msg) {

	bir_got_msg(lb_evt_obj, msg);

	if (_lb_evt_cfg['bir_sort'] == 'HR') {
		_lb_hr_evt_last_msg_id = msg.subject_id;
	}

	return;
}

// Handle event message.
function _lb_evt_got_EVENT(data) {

	// Is this the event which we're displaying?

	if (data.ev_id != _lb_evt_ev_id) {

		// Wait a minute, is this for the pre bir ev? If so we should handle it
		// elsewhere are there are only certain details we want (BIDS status!)
		if (data.ev_id == document.lb_pre_bir_ev_id) {
			_lb_evt_got_PREBIR_EVENT(data);
		}

		return;
	}

	// Determine if this is a new item and if not, make a note of
	// some of the original properties of the item. We then copy
	// fields from the message to the item's info object.

	var info = _lb_evt_event;
	var is_new_item = !info;
	var orig_bettable;

	if (is_new_item) {
		info = data;
		_lb_evt_event = info;
	} else {
		orig_bettable = info.bettable;
		for (var f in data) {
			info[f] = data[f];
		}
	}

	// Derive additional properties of the item.

	info.name = info.names[_lb_evt_cfg.lang];
	info.start_time_xl = info.start_time_xls[_lb_evt_cfg.lang];
	// TODO - little bit more to it?
	info.bettable = (info.status == "A");

	if (_lb_evt_cfg['bir_sort'] == 'HR') {
		if (info.is_off == 'N') {
			info.bettable = false;
		}
		if (info.is_off == '-' && info.in_future && info.in_future == 1) {
			info.bettable = false;
		}
	}

	// Generate new html.

	var html = tmpl_play("lb_evt_event", info);
	var event_el = document.getElementById(_lb_evt_event_area_id);

	if (is_new_item) {
		event_el.innerHTML = html;
		// Create empty container to hold the markets.
		scone_create(_lb_evt_mkts_id, {}, lb_evt_cmp_objects.cmpEvMkts, null);
		
	// id of the element (and scone) holding the markets.
		var pscone_id = _lb_evt_mkts_id;
	
		// If the parent is not visible, there is no need to do any display work.
		if (scone_exists(pscone_id)) {
			// Add, item.
			var sort_info = {
				disporder: 2147483647,
				ev_mkt_id: 0
			}

			_lb_evt_market_original_ordering[0] = 2147483647;
			var scitem_id = _lb_evt_mkt_id_prefix + 0;

			//Manually grab html for the event grouping/next_n_races section.
			var html = '';
			if (_lb_evt_cfg['bir_sort'] == 'HR') {
				html = $j('#next_n_races_container').html();
				$j('#next_n_races_container').empty();
			} else {
				html = $j('#linkedEvsContainer').html();
				$j('#linkedEvsContainer').empty();
			}
			html = '<div class="ifItem" id="bir-mkt 0"> <div id="market 0">' + html + '</div></div>';
			scone_add_item(pscone_id, scitem_id, html, sort_info);
		}
	} else {
		// Save and restore the markets container.
		var saved_mkts = scone_cut(_lb_evt_mkts_id);
		event_el.innerHTML = html;
		scone_paste(_lb_evt_mkts_id, saved_mkts);
	}

	// Make any changes needed elsewhere.
	// Some changes require us to progagate dummy msgs to our children.

	if (!is_new_item && orig_bettable != info.bettable) {
		for (var ev_mkt_id in _lb_evt_evmkt_hash) {
			_lb_evt_got_EVMKT({
				ev_id:      data.ev_id,
				ev_mkt_id:  ev_mkt_id
			});
		}
	}

	if (_lb_evt_cfg['bir_sort'] == 'HR') {
		_lb_hr_evt_event.name = info.name;

		// the bids status of the non BIR event takes precedence
		if (info.pre_bir_bids_status && info.pre_bir_bids_status != '') {
			_lb_hr_evt_event.BIDS_status = bids_status_xl(info.pre_bir_bids_status);
		} else if (info.bids_status && info.bids_status != '') {
			_lb_hr_evt_event.BIDS_status = bids_status_xl(info.bids_status);
		}
	}

	_lb_evt_mkts_count_refresh();
	updatePeriodClock(data);

	if (!is_new_item) {
		LHSDraggable();
	}
	
	return;
}



// Handle market message.
function _lb_evt_got_EVMKT(data, first_build) {

	// Get parent item info.

	var parent_info = _lb_evt_event;

	// not from our event - guess it's on the betslip or somewhere
	if (data.ev_id != parent_info.ev_id) return;

	// Determine if this is a new item and if not, make a note of
	// some of the original properties of the item. We then copy
	// fields from the message to the item's info object.

	var info = _lb_evt_evmkt_hash[data.ev_mkt_id];
	var is_new_item = !info;

	var orig_displayed;
	var orig_disporder;
	var orig_name;
	var orig_bettable;
	var orig_hcap_values;
	var orig_settled;

	if (is_new_item) {
		info = data;
		_lb_evt_evmkt_hash[data.ev_mkt_id] = info;
		info.child_hash = {};
		
		// locate the market with the lowest disporder
		if (info.disporder < _lb_evt_lowest_disporder) {
			_lb_evt_lowest_disporder = info.disporder;
			_lb_evt_lowest_disporder_ev_mkt_id = info.ev_mkt_id
		}
		
	} else {
		orig_displayed   = info.displayed;
		orig_disporder   = info.disporder;
		orig_name        = info.name;
		orig_bettable    = info.bettable;
		orig_hcap_values = info.hcap_values;
		orig_settled     = info.settled;

		for (var f in data) {
			info[f] = data[f];
		}
	}
	
	

	// Derive additional properties of the item.

	info.is_new = 
	  (is_new_item  && !first_build) || 
	  (!is_new_item && orig_displayed != info.displayed && info.displayed == "Y");
	info.name = info.names[_lb_evt_cfg.lang];
	info.bettable = (info.status == "A") && parent_info.bettable;
	if (info["blurb"] == undefined) {
		info.blurb = "";
	}

	// Update original display order so that we insert new market in the right positions
	if ( data.disporder != undefined ) {
		_lb_evt_market_original_ordering[data.ev_mkt_id] = data.disporder;
	}

	if (info.is_new) {
		var normal_disporder = 0;
		//update display order and set to what it should be.
		// Could do this a bit more efficiently by keeping a sorted array.
		for (var ev_mkt_id in _lb_evt_market_ordering) {
			if ( _lb_evt_market_original_ordering[ev_mkt_id] < data.disporder ) {
				normal_disporder++;
			}
		}
		normal_disporder = normal_disporder + 0.5;

		// Save original display order
		_lb_evt_market_original_ordering[data.ev_mkt_id] = data.disporder;
		
		// Update display order
		info.disporder = normal_disporder;
	}

	//override the ordering if it exists
	var cust_market_disporder = _lb_evt_market_ordering[data.ev_mkt_id];
	if (cust_market_disporder) {
		info.disporder = cust_market_disporder;
	}

	// Id of the element (and scone item) for the market.
	var scitem_id = _lb_evt_mkt_id_prefix + data.ev_mkt_id;
	// id of the element (and scone) holding the markets.
	var pscone_id = _lb_evt_mkts_id;

	// If the parent is not visible, there is no need to do any display work.

	if (!scone_exists(pscone_id)) {
		return;
	}

	// Generate new html.

	var html = tmpl_play("lb_evt_evmkt", info);

	// Add, replace or remove visible item.

	var was_visible = scone_item_exists(scitem_id);
	var now_visible = (info.displayed == "Y");

	var sort_info = {
		disporder: info.disporder,
		ev_mkt_id: info.ev_mkt_id
	}

	if (!was_visible && now_visible) {
		scone_add_item(pscone_id, scitem_id, html, sort_info);
		// Create a scone to hold the selections' HTML.
		var cscone_id = _lb_evt_selcns_id_prefix + data.ev_mkt_id;
		scone_create(cscone_id, {}, lb_evt_cmp_objects.cmpSelcns, null);
	} else if (was_visible && now_visible) {
		// This will preserve the selections' HTML.
		scone_replace_item(scitem_id, html, sort_info, true);
	} else if (was_visible && !now_visible) {
		scone_remove_item(scitem_id);
	}

	// Make any changes needed elsewhere.
	// Some changes require us to progagate dummy msgs for our children.

	if ( now_visible &&
	     (
	       !was_visible ||
	       orig_bettable != info.bettable || 
	       _lb_evt_diff_objs_brief(orig_hcap_values, info.hcap_values)
	     ) ) {
		for (var ev_oc_id in info.child_hash) {
			_lb_evt_got_SELCN({
				ev_oc_id:  ev_oc_id,
				ev_mkt_id: info.ev_mkt_id
			});
		}
	}

	if ( !first_build && (
	       is_new_item || 
	       (orig_displayed != info.displayed) ||
	       (orig_name      != info.name)      ||
	       (orig_disporder != info.disporder) ||
	       (orig_bettable  != info.bettable)
	     ) ) {
		_lb_evt_mkts_count_refresh();
	}

	if (info.is_new) {
		_lb_evt_highlight_new_mkt(info.ev_mkt_id);
		lb_evt_upd_market_orders();
	}

	if (!first_build) {
		LHSDraggable();
	}

	// Update Collapse All/Expand All
	if (now_visible) {
		$j("#toogle_live_events_wrap").html('<a href="javascript:void(0)" title="'+bir_collapse_all+'" class="expand">'+bir_collapse_all+'</a> | '+bir_expand_all);
	}
	
	// do we need to redirect to another event (or the homepage)
	// only follow the lowest disporder market and only do this
	// for non horse racing
	if (_lb_evt_lowest_disporder_ev_mkt_id == info.ev_mkt_id && _lb_evt_cfg['bir_sort'] != 'HR' && _lb_evt_cfg['use_ev_bir_redirect'] == 1) {
		
		var redirect_overlay = document.getElementById('event_redirect_overlay');
		
		if (info.settled == "Y" && orig_settled == "N" && _lb_evt_redirect_timer == null) {
			
			// schedule a redirection of the event page to the next event or the homepage
			var delay = Math.round(_lb_evt_cfg['ev_bir_redirect_time_window'] + Math.random() * 2000);
			_lb_evt_redirect_timer = window.setTimeout("_lb_evt_redirect()", delay);
			
			//show the overlay
			redirect_overlay.style.display = '';
		} else if (info.settled == "N" && orig_settled == "Y" && _lb_evt_redirect_timer != null) {
			
			// de-schedule the redirection
			clearTimeout(_lb_evt_redirect_timer);
			_lb_evt_redirect_timer = null;
			
			//hide the overlay
			redirect_overlay.style.display = 'none';
		}
	}

	return;
}

function _lb_evt_redirect() {
	_lb_evt_redirect_timer = null;
	// reload the page on the next event
	goBIRNextEvent();
}

// Highlight the fact that a new market has come into being.
// We'll also need to make the highlight disappear after a while.
function _lb_evt_highlight_new_mkt(ev_mkt_id) {

	var duration = _lb_evt_cfg.highlight_duration * 3;

	_lb_evt_show_global_new_mkt(true);

	var old_timer = _lb_evt_new_mkt_timers["global"];
	if (old_timer != null) {
		window.clearTimeout(old_timer);
	}
	var cmd = "_lb_evt_show_global_new_mkt(false)";
	_lb_evt_new_mkt_timers["global"] = window.setTimeout(cmd, duration);

	var old_timer = _lb_evt_new_mkt_timers[ev_mkt_id];
	if (old_timer != null) {
		window.clearTimeout(old_timer);
	}
	var cmd = "_lb_evt_hide_new_mkt(" + ev_mkt_id + ")";
	_lb_evt_new_mkt_timers[ev_mkt_id] = window.setTimeout(cmd, duration);
}

function _lb_evt_show_global_new_mkt(show) {
	var el = document.getElementById("new_market_img_div");
	if (el) el.style.display = show ? "" : "none";
	var el = document.getElementById("new_market_img_div2");
	if (el) el.style.display = show ? "" : "none";
}

function _lb_evt_hide_new_mkt(ev_mkt_id) {
	var el = document.getElementById("new_market_img_" + ev_mkt_id);
	if (el) {
		el.parentNode.removeChild(el);
	}
	var info = _lb_evt_evmkt_hash[ev_mkt_id];
	if (info && info.is_new) {
		info.is_new = false;
		_lb_evt_mkts_count_refresh();
	}
}

// Handle market handicap message.
function _lb_evt_got_MHCAP(data) {

	// Get parent & item info.

	var parent_info = _lb_evt_event;
	var info = _lb_evt_evmkt_hash[data.ev_mkt_id];

	if (!parent_info || !info) return;

	// Copy fields from the message to the item's info object.

	for (var f in data) {
		info[f] = data[f];
	}

	// Progagate handicap change to children with dummy msgs.

	for (var ev_oc_id in info.child_hash) {
		_lb_evt_got_SELCN({
			ev_oc_id:  ev_oc_id,
			ev_mkt_id: info.ev_mkt_id
		});
	}

	return;
}


// Handle selection message.
function _lb_evt_got_SELCN(data) {

	// Check we've heard of the parent - ignore if not.
	// Otherwise, get info for parent and ensure he knows of us.

	var parent_info = _lb_evt_evmkt_hash[data.ev_mkt_id];
	if (!parent_info) {
		return;
	}
	parent_info.child_hash[data.ev_oc_id] = true;

	// Determine if this is a new item and if not, make a note of
	// some of the original properties of the item. We then copy
	// fields from the message to the item's info object.

	var info = _lb_evt_selcn_hash[data.ev_oc_id];
	var is_new_item = !info;

	var orig_lp_num;
	var orig_lp_den;

	if (is_new_item) {
		info = data;
		_lb_evt_selcn_hash[data.ev_oc_id] = info;
	} else {
		orig_lp_num   = info.lp_num;
		orig_lp_den   = info.lp_den;
		orig_hcap_values = info.hcap_values;
		for (var f in data) {
			info[f] = data[f];
		}
	}

	// Derive additional properties of the item.

	info.name = info.names[_lb_evt_cfg.lang];
	if ( info.fb_result && 
	     parent_info.hcap_values ) {
		info.hcap_value = parent_info.hcap_values[info.fb_result];
	}
	info.bettable = (info.status == "A") && parent_info.bettable;

	// Id of the element (and scone item) for the selection.
	var scitem_id = _lb_evt_selcn_id_prefix + data.ev_oc_id;
	// Id of the element (and scone) holding the selections.
	var pscone_id = _lb_evt_selcns_id_prefix + info.ev_mkt_id;

	// If the parent is not visible, there is no need to do any display work.

	if (!scone_exists(pscone_id)) {
		return;
	}

	// Generate new html.

	info.price_str = get_price_str(
		lb_evt_obj,
		info.lp_num,
		info.lp_den,
		parent_info.lp_avail,
		parent_info.mkt_sort
	);

	var html = tmpl_play("lb_evt_selcn", info);

	// Add, replace or remove visible item.

	var was_visible = scone_item_exists(scitem_id);
	var now_visible = (info.displayed == "Y");

	var sort_info = {
		disporder : info.disporder,
		lp_num    : info.lp_num,
		lp_den    : info.lp_den,
		ev_oc_id  : info.ev_oc_id
	}

	var saved_stake = ["",""];
	if (was_visible) {
		//Bet now stake
		var el1 = document.getElementById(_lb_evt_stake_id_prefix + info.ev_oc_id);
		if (el1) saved_stake[0] = el1.value;
		//Fast bet stake
		var el2 = document.getElementById(_lb_evt_fb_stake_id_prefix + info.ev_oc_id);
		if (el2) saved_stake[1] = el2.value;

	}

	if (!was_visible && now_visible) {
		scone_add_item(pscone_id, scitem_id, html, sort_info);
	} else if (was_visible && now_visible) {
		scone_replace_item(scitem_id, html, sort_info, false);
	} else if (was_visible && !now_visible) {
		scone_remove_item(scitem_id);
	}

	if (now_visible && (saved_stake[0] != "" || saved_stake[1] != "")) {
		//Bet now stake
		var el1 = document.getElementById(_lb_evt_stake_id_prefix + info.ev_oc_id);
		if (el1) el1.value = saved_stake[0];
		//Fast bet stake
		var el2 = document.getElementById(_lb_evt_fb_stake_id_prefix + info.ev_oc_id);
		if (el2) el2.value = saved_stake[1];
	}

	// Make any changes needed elsewhere.

	if (!is_new_item && now_visible) {
		push_highlight_price_change(
			lb_evt_obj,
			info.ev_oc_id,
			info.lp_num,
			info.lp_den,
			orig_lp_num,
			orig_lp_den
		);
	}

	return;
}

// Handle price message.
function _lb_evt_got_PRICE(data) {

	// Check we've heard of the selection and market.

	var info = _lb_evt_selcn_hash[data.ev_oc_id];
	if (!info) return;

	var parent_info = _lb_evt_evmkt_hash[info.ev_mkt_id];
	if (!parent_info) return;

	// Copy data from message to info object, making
	// a note of some original properties first.

	var orig_lp_num = info.lp_num;
	var orig_lp_den = info.lp_den;

	for (var f in data) {
		info[f] = data[f];
	}

	// The element id (and scone item id) for the selection.

	var scitem_id = _lb_evt_selcn_id_prefix + data.ev_oc_id;
	if (!scone_item_exists(scitem_id)) return;

	// Selections are sorted by price (amongst other things),
	// so we may need to reposition the selection.

	var sort_info = {
		disporder : info.disporder,
		lp_num    : info.lp_num,
		lp_den    : info.lp_den,
		ev_oc_id  : info.ev_oc_id
	};
	scone_set_item_info(scitem_id, sort_info);

	// Find where the new price needs to go.

	var price_id = _lb_evt_price_str_id_prefix + info.ev_oc_id;
	var price_el = document.getElementById(price_id);
	if (!price_el) return;

	// Generate new price string and store it.

	info.price_str = get_price_str(
		lb_evt_obj,
		info.lp_num,
		info.lp_den,
		parent_info.lp_avail,
		parent_info.mkt_sort
	);
	price_el.innerHTML = info.price_str;

	push_highlight_price_change(
		lb_evt_obj,
		info.ev_oc_id,
		info.lp_num,
		info.lp_den,
		orig_lp_num,
		orig_lp_den
	);

	return;
}

/*
 * Add a bet on a live betting event selection to the slip.
 */
function lb_evt_add_bet(ev_oc_id, stake, fast_bet) {

	// Check fast_bet param
	var fb = typeof fast_bet === 'boolean' && fast_bet;

	if (!stake) {
		var el = '';
		if (fb) {
			el = document.getElementById(_lb_evt_fb_stake_id_prefix + ev_oc_id);
		} else {
			el = document.getElementById(_lb_evt_stake_id_prefix + ev_oc_id);
		}
		if (el) {
			stake = el.value;
			if (fb) {
				//Clear Fast Bet stake box
				el.value = "";

				//Error when fast bet places with no stake entered
				if (isNaN(stake) || isNaN(parseFloat(stake))) {
					//On remote betslip
					if (get_pref('BETSLIP_STYLE') == "Detached") {
						//If window is open
						try {
							popped_out_betslip.BS_display_error(betslipbody.msg.BS_FASTBET_STAKE_INVALID_TITLE, betslipbody.msg.BS_FASTBET_STAKE_INVALID_TXT);
							popped_out_betslip.focus();
						} catch(e) {
							//Otherwise open it and execute the function when window is loaded
							BS_pop_out("DisplayError=FASTBET_STAKE_INVALID");
						}
						return;
					} else {
						BS_display_error(betslipbody.msg.BS_FASTBET_STAKE_INVALID_TITLE, betslipbody.msg.BS_FASTBET_STAKE_INVALID_TXT, 'BS_close_betslip()');
						BS_open_betslip();
						return;
					}
				}

			}
		}
	}	

	var selcn = _lb_evt_selcn_hash[ev_oc_id];
	var evmkt = _lb_evt_evmkt_hash[selcn.ev_mkt_id];

	BS_set_leg("selections",  ev_oc_id);
	BS_set_leg("price_type",  "L");
	BS_set_leg("stake",       stake);
	BS_set_leg("lp_num",      selcn.lp_num);
	BS_set_leg("lp_den",      selcn.lp_den);
	BS_set_leg("hcap_value",  evmkt.raw_hcap);
	BS_set_leg("bir_index",   evmkt.bir_index);
	BS_set_leg("market_tags", "");

	BS_go_bet(fb);

	return;
}

// Refresh the market counts.
function _lb_evt_mkts_count_refresh() {

	var num_mkts_avail = 0;

	for (ev_mkt_id in _lb_evt_evmkt_hash) {
		var mkt = _lb_evt_evmkt_hash[ev_mkt_id];
		if (mkt.displayed == "Y") num_mkts_avail++;
	}

	var el = document.getElementById(_lb_evt_num_avail_mkts_id);
	if (el)	el.innerHTML = num_mkts_avail;

	return;
}

// Format an each-way terms string.
function lb_evt_mk_ew_terms (ew_places, ew_fac_num, ew_fac_den) {
	if (ew_places == "" || ew_places == 1) return "";
	return tmpl_ml_printf(
	  "BET_EW_TERMS_EW", ew_fac_num + "/" + ew_fac_den, ew_places
	);
}

// Truncate string s to length len if needed, appending suffix to indicate
// truncation has occurred. The length of the suffix is taken into account.
function _lb_evt_truncate(s, len, suffix) {
	if (s.length <= len) return s;
	var keep = len - suffix.length;
	return s.substr(0, keep >= 0 ? keep : 0) + suffix;
}

// Do two objects differ in any way?
function _lb_evt_diff_objs_brief(a, b) {
	for (var f in a) {
		if (b[f] == undefined) return true;
	}
	for (var f in b) {
		if (a[f] == undefined) return true;
	}
	for (var f in a) {
		if (b[f] == undefined) continue;
		var va = a[f]; var vb = b[f];
		if (typeof va != typeof vb) {
			return true;
		} else if (typeof va == "object") {
			if (_lb_evt_diff_objs_brief(va, vb)) return true;
		} else if (va != vb) {
			return true;
		}
	}
	return false;
}



function _lb_evt_got_PREBIR_EVENT(data) {

	if (_lb_evt_cfg['bir_sort'] == 'HR') {
		var BIDS_status = '';
		if (data.bids_status) {
			BIDS_status = data.bids_status;
		}
		_lb_evt_event.pre_bir_bids_status = BIDS_status;
		_lb_hr_evt_event.BIDS_status = bids_status_xl(BIDS_status);
	}
}


function toggleArrow(ob, cName) {
	if (cName == "expanded") {
		ob.className = "collapsed";
	} else {
		ob.className = "expanded";
	}
}

function lb_evt_get_BIDS_status() {
	//return _lb_hr_evt_event.BIDS_status;
	return _lb_hr_evt_event.BIDS_status;
}


// sets up the the hahses containing the ordering of types and classes
// to override what came from the DB
// we have to do it this way, using childNodes, rather than using the scone
// library function 'scone_get_items' as we care about the actual order items
// are displayed on the screen and the 'scone_get_items' doesn't give
// us the id's with that ordering preserved
function lb_evt_upd_market_orders() {
	
	// reset the hash containing the ordering
	_lb_evt_market_ordering = {}
	
	var market_container = document.getElementById(_lb_evt_mkts_id);
	var m_disporder = 0;

	//TODO: take into account linkedEvsContainer
	
	//loop through all the the current classes storing the current displayed order
	for (var c = 0; c < market_container.childNodes.length; c++) {
		var market_name = market_container.childNodes[c].id;
		
		var market_matches = market_name.match("bir-mkt"+"*");
		
		if (market_matches) {
			
			m_disporder++;
			
			var market_id = market_name.substring("bir-mkt ".length,market_name.length);

			//store the current disporder of this item in a hash
			_lb_evt_market_ordering[market_id] = m_disporder;
		}
	}

	// And now update the scones information.
	for (var market_id in _lb_evt_market_ordering) {

		var market_elem_name = _lb_evt_mkt_id_prefix + market_id;

		// store the disporder in the sorting info associated with the scone
		var market_sort_info = {
			disporder: _lb_evt_market_ordering[market_id],
			ev_mkt_id: market_id
		};

		scone_set_item_info(market_elem_name, market_sort_info,true);
	}

}


function get_clock_string () {

	var clock = {
		clock: _lb_evt_event.clock,
		period_xl: _lb_evt_event.period_xl
	};

	if (clockList[_lb_evt_event.ev_id].active) {
		return clock;
	} else {
		return null;
	}

}

function get_event_info () {

	var event_info = {
		start_time_xls: _lb_evt_event.start_time_xls,
		name: evt_type_name,
		class_name: evt_class_name,
		score_home: _lb_evt_event.score_home,
		score_away: _lb_evt_event.score_away,
		score_extra_info: _lb_evt_event.score_extra_info,
		venue: _lb_evt_event.venue
	};

	return event_info;

}
