// $Id: util.js,v 1.1.2.18 2010-07-26 16:37:21 dmondeja Exp $

// minified CVS tag version
var dummy = '$Id: util.js,v 1.1.2.18 2010-07-26 16:37:21 dmondeja Exp $';

var error_list = "";



// add an error
//
function add_error(str) {

	if(error_list.length > 0) {
		error_list += "<br/>";
	}
	error_list += str;
	return 1;
}



// write a select input box
//
function write_select() {

	var sel = arguments[0];
	var i;
	var n;
	var v;
	var sel_tag;

	for(i = 1; i < arguments.length; i += 2) {
		v = arguments[i];
		n = arguments[i + 1];
		sel_tag = (sel == v) ? ' selected=""' : '';
		document.writeln(
			'<option value="' + v + '"' + sel_tag + '>' + n + '</option>'
		);
	}
}



// Swaps images
//
function MM_swapImgRestore() { //v3.0
	var i,x,a=document.MM_sr;

	for(i=0; a && i<a.length && (x=a[i]) && x.oSrc; i++) {
		x.src=x.oSrc;
	}
}



// Preloads images
//
function MM_preloadImages() {
	var d=document;

	if (d.images) {
		if (!d.MM_p) {
			d.MM_p=new Array();
		}
		var i,j=d.MM_p.length,a=MM_preloadImages.arguments;
		for(i=0; i<a.length; i++) {
			if (a[i].indexOf("#") !=0) {
				d.MM_p[j]=new Image;
				d.MM_p[j++].src=a[i];
			}
		}
	}
}


// finds an image element
//
function MM_findObj(n, d) {
	var p,i,x;

	if(!d) {
		d=document;
	}
	if ((p=n.indexOf("?")) > 0 && parent.frames.length) {
		d=parent.frames[n.substring(p+1)].document;
		n=n.substring(0,p);
	}

	if(!(x =d[n]) && d.all) {
		x=d.all[n];
	}

	for (i=0; !x && i<d.forms.length; i++) {
		x=d.forms[i][n];
	}

	for (i=0; !x && d.layers && i<d.layers.length; i++) {
		x=MM_findObj(n,d.layers[i].document);
	}
	if(!x && d.getElementById) {
		x=d.getElementById(n);
	}
	return x;
}



// Swaps images
//
function MM_swapImage() {
	var i,j=0,x,a=MM_swapImage.arguments;

	document.MM_sr=new Array;

	for(i=0; i<(a.length-2); i+=3) {
		if ((x=MM_findObj(a[i])) !=null) {
			document.MM_sr[j++]=x;
			if(!x.oSrc) {
				x.oSrc=x.src;
			}
			x.src=a[i+2];
		}
	}
}



// trim whitespace from a string
OT_util_included = true;


function OT_trim(str) {
	var sl = ""+str.length;
	var i;
	for (i = 0; i < sl; i++) {
		if (str.charAt(i) != ' ' &&
			str.charAt(i) != '\t' &&
			str.charAt(i) != '\n') {
			break;
		}
	}
	start = i;

	for (i = sl-1; i > 0; i--) {
		if (str.charAt(i) != ' ' &&
			str.charAt(i) != '\t' &&
			str.charAt(i) != '\n') {
			break;
		}
	}

	return str.substring(start, i+1);
}


// global replace , with .
function OT_replace_comma_with_dp(str)
{
	str2=str.replace(/[,]/g,".");
	return str2;
}


// split str on any of the characters in delim
// return the substrings as an array
function OT_strtok(str, d)
{
    var a = new Array();
    var i, j;
    var s = ""+str;
    var sl = s.length;
    var dl = d.length;

	if (s.charAt(0) == ".") {
		a[0] = "0";
		var sz = 1;
	} else {
		var sz = 0;
	}

    var st = 0;
    for (i = 0; i < sl; i++) {
		for (j = 0; j < dl; j++) {
		    if (s.charAt(i) == d.charAt(j)) {
				if (st != i) {
					a[sz] = s.substring(st, i);
					sz = sz + 1;
					a.length = sz;
				}
				st = i+1;
      	    }
		}
    }
    if (st != i) {
		a[sz] = s.substring(st, i);
    }
    return a;
}

BROKEN_NAN = false;

if (!isNaN(parseInt('a'))) {
    BROKEN_NAN = true;
}



function pad(str, len, ch) {
    var i;
    for (i = len - str.length; i > 0; i--) {
	str += ch;
    }
    return str;
}


function OT_round(str, dp)
{

    var len = 0;
    var a = OT_strtok(str, ".");
    var i, n;

    if (a.length == 0) {
		return pad("0.", dp+2, "0");
    } else if (a.length == 1) {
		len=Number(a[0].length)+Number(dp)+1;
		return pad(a[0]+".", len, "0");
    } else {
		if (a[1].length <= dp) {
			len=Number(a[0].length)+Number(dp)+1;
			return pad(a[0]+"."+a[1], len, "0");
		} else {
			if (Number(a[1].substring(Number(dp), Number(dp)+1)) >= 5) {
				var rem = 1;
			} else {
				var rem = 0;
			}

			var tail ="";
			for (i = dp-1; i >= 0; i--) {
				n = Number(a[1].substring(i, i+1))+Number(rem);
				if (n >= 10) {
				   rem = 1;
				   n = Number(n)-10;
				   tail = ""+n+tail;
				} else {
					return a[0]+"."+a[1].substring(0, i)+n+tail;
				}
			}
	    }

	    if (rem > 0) {
			a[0]=Number(a[0])+Number(rem);
	    }
	    return a[0]+"."+tail;
	}
}



// functions to build up and retrieve a list of errors

var otErrStr = "";
var otNErrs = 0;

function OT_ErrReset() {
    otErrStr = "";
    otNErrs = 0;
}

function OT_ErrAdd(str) {
    otErrStr += str;
    otNErrs++;
    return otNErrs;
}

function OT_ErrStr() {
    return otErrStr;
}

function OT_ErrCount() {
    return otNErrs;
}


function OT_ErrStr() {
    return otErrStr;
}

function OT_ErrCount() {
    return otNErrs;
}



function fs (sz) {
    return '<font face="Arial, Helvetica, Sans-serif" size="'+sz+'">';
}

//////////////////////////////////////////////
// Print money in appropriate currency format
// Use Pound sign for GBP and just pass
// currency code if no amount is supplied
//////////////////////////////////////////////
function print_ccy (amt, ccy) {

    var str = "";

    amt = OT_round(amt,2);

    // If amt is negative remove minus so that it can be put before currency symbol
    if (Number(amt) < 0) {
	str = '-';
	amt = Number(amt) * -1;
    }

    str += print_ccy_symbol(ccy);

    // tag on amount - still to add comma separation of 1000s etc
    if (amt != "") {
	str += amt;
    }

    return str;
}

function print_ccy_symbol (ccy) {

    if (ccy == "GBP" || ccy == "") {
		str = "&pound;";
    } else if (ccy == "IEP") {
		str = "IR&pound; "
    } else if (ccy == "USD") {
		str = "US$ "
	} else if (ccy == "AUS") {
		str = "AUS$ "
	} else if (ccy == "EUR") {
		str = "EUR&euro;"
	} else {
		str=ccy;
	}
    return str;
}

function chip_ccy_convert(funds, direction) {

	var converted_funds = 0.0;

	// if going from dollars, need to invert the exchange rate,
	// BUT we want to keep the value known in the util.exch_rate object
	var exch_rate = util.exch_rate;
	if (direction == "from_usd") {
		exch_rate = 1 / exch_rate;
	}

	if (!isNaN(parseFloat(funds))) {
		converted_funds = parseFloat(funds) * exch_rate;
	}

	converted_funds = Math.round(converted_funds * 100) / 100;

	return converted_funds;
}

/*
 * Given new JS data, this function checks in the hashtables for data that
 * is now no longer present but was previously and removes the HTML along with
 * clearing out the hashtables down to a specified level.
 *
 * handler:    the handler object as set in the files using this function.
 * level_from: the starting level.
 * level_to:   the level to which the function will drill down to during clearing.
 * check_data: the latest data we are checking the existing hashes against. This
 *             should be data relating to the "check_level".
 */
var level_hier      = {};
level_hier["CLASS"] = 0;
level_hier["TYPE"]  = 1;
level_hier["EVENT"] = 2;
level_hier["EVMKT"] = 3;
level_hier["EVOC"]  = 4;

var hier_level = {};
hier_level[0]  = "CLASS";
hier_level[1]  = "TYPE";
hier_level[2]  = "EVENT";
hier_level[3]  = "EVMKT";
hier_level[4]  = "EVOC";

var level_data_id = {};
level_data_id[0] = "";
level_data_id[1] = "";
level_data_id[2] = "";
level_data_id[3] = "";
level_data_id[4] = "";

function push_hash_prune_drilldown(
	handler,
	level_from,
	level_to,
	check_level,
	check_data
) {

	// Calculate the maximum level of recursion.
	var max_recursion_level = level_hier[level_to] - level_hier[level_from];

	// Initialise the recursion drilldown.
	push_hash_prune_drilldown_recurse(
		handler,
		0,
		max_recursion_level,
		level_hier[level_from],
		level_hier[check_level],
		check_data,
		0
	);

	return;
}

// current_level and check_level are in the format of an index for hier_level.
// e.g for CLASS as the current level, current_level = 0.
function push_hash_prune_drilldown_recurse (
	handler,
	recursion_level,
	max_recursion_level,
	current_level,
	check_level,
	check_data,
	parent_id
) {

	// Get the hash information for this level.
	if (recursion_level == 0) {
		var id_list = handler.getHash(hier_level[current_level]);
	} else {
		var id_list = handler.getHash(hier_level[current_level - 1])[parent_id].child_hash;
	}

	var info_hash = handler.getHash(hier_level[current_level]);
	var found     = false;
	var i         = 0;
	var scitem_id = "";
	var data_id   = "";

	for (data_id in id_list) {

		found = false;

		if (check_level == current_level) {
			for (i = 0; i < check_data.length; i++) {
				// :(
				switch(hier_level[current_level]) {
					case "CLASS":
						if (check_data[i].ev_class_id == data_id) {
							found = true;
						}
						break;
					case "TYPE":
						if (check_data[i].ev_type_id == data_id) {
							found = true;
						}
						break;
					case "EVENT":
						if (check_data[i].ev_id == data_id) {
							found = true;
						}
						break;
					case "EVMKT":
						if (check_data[i].ev_mkt_id == data_id) {
							found = true;
						}
						break;
					case "EVOC":
						if (check_data[i].ev_oc_id == data_id) {
							found = true;
						}
						break;
					default:
						// Nothing.
				}
			}
		}

		// If this is not found, we must continue.
		if (!found) {

			// Remove the html at the highest level.
			if (check_level == current_level) {
				// Remove the html.
				scitem_id = handler.getIdPrefix(hier_level[check_level]) + data_id;
				if (scone_item_exists(scitem_id)) {
					scone_remove_item(scitem_id);
				}
			}

			if (info_hash[data_id]) {

				// Limit the level to which we recurse.
				if (recursion_level < max_recursion_level) {

					push_hash_prune_drilldown_recurse(
						handler,
						recursion_level + 1,
						max_recursion_level,
						current_level + 1,
						check_level,
						check_data,
						data_id
					);
				}

				// Delete the data from its hash if applicable. Only levels higher or
				// equal to that of check_level.
				if (current_level >= check_level) {
					delete info_hash[data_id];
				}
			}
		}
	}

	return;
}

// Format a price.
function get_price_str (handler, lp_num, lp_den, lp_avail, mkt_sort) {

	var handler_config = handler.getConfig();

	if (typeof lp_avail == "undefined") {
		lp_avail = "Y";
	}

	if (typeof mkt_sort == "undefined") {
		mkt_sort = "--";
	}

	var price_str_type = handler_config.price_str_type;

	if ( mkt_sort == "AH" && handler_config.price_str_type_ah != "") {
		price_str_type = handler_config.price_str_type_ah;
	}

	if ( mkt_sort == "HL" && handler_config.price_str_type_hl != "") {
		price_str_type = handler_config.price_str_type_hl;
	}

	if (lp_avail == "N") {
		return "SP";
	}

	if (lp_num == "" && lp_den == "") {
		return "-";
	}

	var price_str;

	if (price_str_type == "DECIMAL") {

		var dps = (lp_den > 100) ? 3 : 2;
		var dp = 1.0 + (lp_num / lp_den);
		var scaled_dp = "" + Math.round(dp * Math.pow(10,dps) - 0.5);
		var int_part  = scaled_dp.substr(0, scaled_dp.length - dps);
		var frac_part = scaled_dp.substr(scaled_dp.length - dps);
		if (int_part  == "") int_part  = "";
		if (frac_part == "") frac_part = "";
		var price_str = int_part + "." + frac_part;
	} else {

		if (lp_den == "") {
			lp_den = 1;
		}

		if (lp_num == lp_den) {
			price_str = "evens";
		} else {
			price_str = lp_num + handler_config.price_str_sep + lp_den;
		}
	}

	return price_str;
}

// A generic object to provide default class/type/event etc comparison functions.
function push_hash_cmp_objects() {
	return;
}

/*
** Although these are all similar and can combined into a single generic function,
** I'm deliberately not doing so, so that they can be customised per instance used,
** should the logic need to change slightly. An example of this would be the
** comparison of events in lb_cal_live.js where we must order first by start time,
** as opposed to disporder.
*/
push_hash_cmp_objects.prototype.cmpClasses = function (cmpMode, classA, classB) {

	var d = classA.disporder - classB.disporder;

	if (d) {
		return d;
	}

	return classA.ev_class_id - classB.ev_class_id;
}

push_hash_cmp_objects.prototype.cmpTypes = function (cmpMode, typeA, typeB) {

	var d = typeA.disporder - typeB.disporder;

	if (d) {
		return d;
	}

	return typeA.ev_type_id - typeB.ev_type_id;
}

push_hash_cmp_objects.prototype.cmpEvents = function (cmpMode, evA, evB) {

	var d = evA.disporder - evB.disporder;

	if (d) {
		return d;
	}

	return evA.ev_id - evB.ev_id;
}

push_hash_cmp_objects.prototype.cmpEvMkts = function (cmpMode, mktA, mktB) {

	var d = mktA.disporder - mktB.disporder;

	if (d) {
		return d;
	}

	return mktA.ev_mkt_id - mktB.ev_mkt_id;
}

push_hash_cmp_objects.prototype.cmpSelcns = function (cmpMode, selcnA, selcnB) {

	var d = selcnA.disporder - selcnB.disporder;

	if (d) {
		return d;
	}

	if (selcnA.lp_num && !selcnB.lp_num) {
		return -1;
	} else if (!selcnA.lp_num && selcnB.lp_num) {
		return +1;
	} else if (selcnA.lp_num && selcnB.lp_num) {
		o = (selcnA.lp_num * selcnB.lp_den) - (selcnA.lp_den * selcnB.lp_num);

		if (o) {
			return o;
		}
	}

	return selcnA.ev_oc_id - selcnB.ev_oc_id;
}

/*
** Called when the price of a selection may have changed; will bring
** change to the attention of the user.
*/
function push_highlight_price_change(
	handler,
	ev_oc_id,
	lp_num,
	lp_den,
	old_lp_num,
	old_lp_den
) {

	if (isNaN(lp_num) || isNaN(old_lp_num)) {
		return;
	}

	var d = lp_num * old_lp_den - lp_den * old_lp_num;

	if (d == 0) {
		return;
	}

	var price_id = handler.getIdPrefix("SELCN_HL") + ev_oc_id;

	push_highlight(handler, price_id, handler.getMiscInfo("PRICE_CLASS_NAME"), d);

	return;
}

/*
 * Called when the level for a selection may have changed; will bring
 * change to the attention of the user.
 */
function push_highlight_level_change(
	handler,
	ev_oc_id,
	old_hcap_str,
	new_hcap_str
) {

	if (old_hcap_str == new_hcap_str) {
		return;
	}

	var old_hcap = _bir_extract_hcap(old_hcap_str);
	var new_hcap = _bir_extract_hcap(new_hcap_str);

	if (old_hcap == new_hcap) {
		return;
	}

	var level_container  = handler.getIdPrefix("LEVEL_CONTAINER");
	var level_id         = level_container + ev_oc_id;
	var level_class_name = handler.getMiscInfo("LEVEL_CLASS_NAME");

	push_highlight(handler, level_id, level_class_name, new_hcap - old_hcap);
}

// Extract handicap value from a string (by removing parentheses).
function _bir_extract_hcap(hcap_str) {
	return hcap_str.replace(/[ ()]/g,'');
}

/*
** Highlight a change to an element by giving it base_class + "red"
** if dir is negative, or base_class + "blue" if positive, or unhighlight
** it if dir is zero. The highlight is removed after a time interval.
*/
function push_highlight(
	handler,
	id,
	base_class,
	dir
) {

	var el = document.getElementById(id);

	if (!el) {
		return;
	}

	var highlight_class = "";
	var handler_config  = handler.getConfig();

	if (dir < 0) {
		highlight_class = base_class + handler_config.hl_class_decrease;
	} else if (dir > 0) {
		highlight_class = base_class + handler_config.hl_class_increase;
	} else {
		highlight_class = base_class + handler_config.hl_class_same;
	}

	var classes = el.className.split(" ");
	var found   = false;

	for (var i = 0; i < classes.length; i++) {
		if (classes[i] == base_class + handler_config.hl_class_same     ||
		    classes[i] == base_class + handler_config.hl_class_increase ||
		    classes[i] == base_class + handler_config.hl_class_decrease
		) {
			classes[i] = highlight_class;
			found = true;
			break;
		}
	}

	if (!found) {
		classes.push(highlight_class);
	}

	el.className = classes.join(" ");

	var timeout_info = handler.getHash("HL_TIMERS");

	if (timeout_info[id] != null) {
		window.clearTimeout(timeout_info[id]);
		delete timeout_info[id];
	}

	var self = this;

	if (dir != 0) {
		timeout_info[id] = window.setTimeout(function(){self.push_highlight(handler, id, base_class, 0)}, handler_config.highlight_duration);
	}

	return;
}

function push_schedule_unhighlight_new_item(handler, type, id) {

	var handler_config = handler.getConfig();
	var self = this;

	window.setTimeout(function(){self.push_unhighlight_new_item(handler, type, id)}, handler_config.highlight_duration);
}

function push_unhighlight_new_item(handler, type, id) {

	var label = document.getElementById(handler.getIdPrefix("NEW_ITEM") + type + "_" + id);

	if (label) {
		label.style.display = "none";
	}
}

function push_get_ev_counts(handler, type, id) {

	var count = handler.getHash("EV_COUNT")[type+id];

	if(!count) {
		return 0;
	} else {
		return count;
	}
}

/*
** Add a bet selection to the slip.
*/
function bir_add_bet(handler, ev_oc_id) {

	var selcn = handler.getHashId("EVOC", ev_oc_id);
	var evmkt = handler.getHashId("EVMKT", selcn.ev_mkt_id);

	BS_set_leg("selections",  ev_oc_id);
	BS_set_leg("price_type",  "L");
	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();

	return;
}

/*
 * Called whenever we receive any published message from the Push Server.
 */
function bir_got_msg(handler, msg) {

	var data = {};

	switch(msg.subject_level) {

		case "sPRICE":

			eval("data = " +  msg.data + ";");
			data.ev_oc_id = msg.subject_id;
			handler.gotPushData("PRICE", data);
			break;

		case "sSELCN":

			eval("data = " +  msg.data + ";");
			data.ev_oc_id = msg.subject_id;
			handler.gotPushData("SELCN", data);
			break;

		case "sMHCAP":

			eval("data = " +  msg.data + ";");
			data.ev_mkt_id = msg.subject_id;
			handler.gotPushData("MHCAP", data);
			break;

		case "sEVMKT":

			eval("data = " +  msg.data + ";");
			data.ev_mkt_id = msg.subject_id;
			handler.gotPushData("EVMKT", data);
			break;

		case "sEVENT":

			eval("data = " +  msg.data + ";");
			data.ev_id = msg.subject_id;
			handler.gotPushData("EVENT", data);
			break;
		case "sBRSCR":
			eval("data = " +  msg.data + ";");
			data.ev_id = msg.subject_id;
			handler.gotPushData("BRSCR", data);
			break;

		default:
			// presumably this msg wasn't intended for us
	}

	return;
}

function bir_update_elem (elem_id, elem_value, append) {

	var elem = document.getElementById(elem_id);

	if (!elem) {
		return;
	}

	// Replace or append?
	if (append == 1) {
		elem.innerHTML = elem.innerHTML + " " + elem_value;
	} else {
		elem.innerHTML = elem_value;
	}
}

// Used for ascending numeric array sorting.
function sortNumAsc(a, b) {
	return a - b;
}

// Display the selected tab, and hide the others.
function selectBirCalTab(tab_name) {

	var live_elem     = document.getElementById("liveNow");
	var live_elem_tab = document.getElementById("liveNowTab");
	var upc_elem      = document.getElementById("upcoming");
	var upc_elem_tab  = document.getElementById("upcomingTab");
	var fav_elem      = document.getElementById("myFavourite");
	var fav_elem_tab  = document.getElementById("myFavouriteTab");
	var filter_elem   = document.getElementById("birCalFilter");

	if (live_elem && live_elem_tab && upc_elem && upc_elem_tab && fav_elem && fav_elem_tab && filter_elem) {

		switch(tab_name) {
			case "LIVE":
				// Show the live tab; hide the others.
				if (live_elem.style.display == "none") {
					live_elem.style.display = "";
					live_elem_tab.className = "active";
					upc_elem.style.display  = "none";
					upc_elem_tab.className  = "";
					fav_elem.style.display  = "none";
					fav_elem_tab.className  = "";

					if (filter_elem.style.display == "none") {
						filter_elem.style.display = "";
					}
				}
				break;
			case "UPC":
				// Show the upcoming tab; hide the others.
				if (upc_elem && upc_elem.style.display == "none") {
					upc_elem.style.display  = "";
					upc_elem_tab.className  = "active";
					live_elem.style.display = "none";
					live_elem_tab.className = "";
					fav_elem.style.display  = "none";
					fav_elem_tab.className  = "";

					if (filter_elem.style.display == "none") {
						filter_elem.style.display = "";
					}
				}
				break;
			case "FAV":
				// Show the favourites tab; hide the others.
				if (fav_elem && fav_elem.style.display == "none") {
					fav_elem.style.display    = "";
					fav_elem_tab.className    = "active";
					upc_elem.style.display    = "none";
					upc_elem_tab.className    = "";
					live_elem.style.display   = "none";
					live_elem_tab.className   = "";
					filter_elem.style.display = "none";
				}
				break;
			default:
				// Do nothing.
		}
	}
}