// Copyright 2009 Latitude Technologies Inc. All rights reserved.

/**
 * @fileOverview Collection of JavaScript utility functions for WebSentinal.
 * @name WebSentinal Utility Functions
 **/

/**
 * Logs message to console if availalble
 * @param {String} msg The message to be logged.
 */
function clog(msg)
{
	if (typeof(console) != 'undefined')
		console.log(msg);
	else
		console.log('huh?');
}

/**
 * A debugging function for dumping an object's information.
 * @param {Object} obj The object to be described in the console.
 */
function DumpObject(obj)
{
	for (var key in obj)
	{
		if (typeof(obj[key]) == 'object')
			DumpObject(obj[key]);
		else
			clog(key + ': ' + obj[key])
	}
/*
	$.each(obj.items, function(i, obj)
	{
		clog(i);
		clog(obj);
	});
*/
}

//TODO: complete documentaion.
/* Ajax dubugging function
 * @param {String} event
 */
function DebugAjax(event, xhr, status)
{
//	var html = $('div#msgsDiv').html();
//	$('div#msgsDiv').html('Event: ' + event + '; readyState:' + xhr.readyState + '; status ' + xhr.status + '; text:' + xhr.responseText);
	clog('Event: ' + event + '; readyState:' + xhr.readyState + '; status ' + xhr.status + '; text:' + xhr.responseText);
	var key;
	for (key in event)
		clog(key + ':' + event[key]);
	clog('status');
	for (key in status)
		clog(key + ':' + status[key]);
}

/**
 * Utility function for creating a new div element.
 * @returns {String} The id of the new div element that was created.
 */
function CreateDiv()
{
	var id = 'TmpDiv' + new Date().getTime();
	var newdiv = document.createElement('div');
	newdiv.setAttribute('id', id);
	document.body.appendChild(newdiv);
	return id;
}

   /*
   if (width) {
       newdiv.style.width = 300;
   }

   if (height) {
       newdiv.style.height = 300;
   }

   if ((left || top) || (left && top)) {
       newdiv.style.position = "absolute";

       if (left) {
           newdiv.style.left = left;
       }

       if (top) {
           newdiv.style.top = top;
       }
   }

   newdiv.style.background = "#00C";
   newdiv.style.border = "4px solid #000";

   if (html) {
       newdiv.innerHTML = html;
   } else {
       newdiv.innerHTML = "nothing";
   }
*/

/**
 * Takes an Array of aircraft JSON objects and pulls the tail numbers applying \
 * them to a given select element.
 * @param {Array} aircraft An array of JSON objects containing aircraft 
 * information.
 * @parma {String} listname The name of the select element on the page to be
 * populated with the tail numbers.
 */
function FillTailSels(aircraft, listname)
{
	var i, j;
	var list = new Array();
	var ht = "<option>no selection</option>";
	for (i = 0; i < aircraft.length; i++)
		list[i] = aircraft[i].tail;

	var swapped;
	do
	{
		swapped = false;
		for (i = 0; i < list.length - 1; i++)
		{
			var a = list[i];
			var b = list[i+1];
			if (b < a)
			{
				list[i] = b;
				list[i+1] = a;
				swapped = true;
			}
		}
	} while(swapped);

	for (i = 0; i < list.length; i++)
		ht += "<option>" + list[i] + "</option>";
	$('select#' + listname).html(ht);
}

/**
 * For the given Array of JSON objects return the JSON aircraft object with the
 * given tail number.
 * @param {Array} aircraft An array of JSON aircraft objects.
 * @param {String} tail The tail number of the aircraft object to be returned.
 * @return {Object} Returns a JSON object containing all the data for a given 
 * aircraft, returns null if the aircraft can not be found.
 */
function FindAircraft(aircraft, tail)
{
	for (var i = 0; i < aircraft.length; i++)
		if (aircraft[i].tail == tail)
			return aircraft[i];
	return null;
}
// TODO: document function.
function Tail2Lmc(aircraft, tail)
{
	var air = FindAircraft(aircraft, tail);
	if (air == null)
		return '70000000';
	return air.lmc_id;
}
/**
 * Format the provided Date object to a HH:MM:SS time format. All values are 
 * zero padded to two digits.
 * @param {Date} dat The Date object to be formatted.
 * @return {String} A string representing the formatted time.
 */
function FormatTime(dat)
{
	return PadNum(dat.getHours()) + ':' + PadNum(dat.getMinutes()) + ':' + PadNum(dat.getSeconds());
}

/**
 * Format the provided Date object to a 'YYYY-MM-DD HH:MM:SS' date-time format. 
 * All values (besides year) are zero padded to two digits.
 * @param {Date} dat The Date object to be formatted.
 * @return {String} A string representing the formatted date-time.
 */
function FormatDateTime(dat)
{
	return dat.getFullYear() + '-' + PadNum(dat.getMonth()+1) + '-' + PadNum(dat.getDate()) + ' ' + FormatTime(dat);
}
/**
 * Format the provided Date object to a HH:MM:SS time format in Coordinated 
 * Universal Time. All values are zero padded to two digits.
 * @param {Date} dat The Date object to be formatted.
 * @return {String} A string representing the formatted UTC time.
 */
function FormatUTC(dat)
{
	return PadNum(dat.getUTCHours()) + ':' + PadNum(dat.getUTCMinutes()) + ':' + PadNum(dat.getUTCSeconds());
}
/**
 * Calculates the number of milliseconds to 4am, or the next 4am if it is 
 * currently between midnight and 4am when function is executed.
 * @return {Number} The number of milliseconds till 4am.
 */
function MSecondsTo4Am()
{
	var diff = 0;
	var n = new Date();
	var w = new Date();
	w.setHours(23, 59, 59, 999);			// midnight
	diff = w.getTime() - n.getTime();
	diff += 4 * 60 * 60 * 1000;				// add 4 hours
	return diff;
}
/**
 * Return a version of the number zero padded to 2 digits.
 * @param {Number} param The integer to be zero padded.
 * @return {String} The number zero padded as a string.
 */
function PadNum(param)
{
	if (param.toString().length == 1)
		return "0" + param;
	return param;
}

/*
function ShortDateTime(dtstr)
{
	var tokens = dtstr.split(' ');
	if (tokens.length != 2)
		return dtstr;
	var ymd = tokens[0].split('-');
	if (ymd.length != 3)
		ymd = tokens[0].split('/');
	var d = new Date();
	if (ymd[0] != d.getUTCFullYear())
		return dtstr;
	if (ymd[1] != (d.getUTCMonth() + 1) || ymd[2] != d.getUTCDate())
		return ymd[1] + '/' + ymd[2] + ' ' + tokens[1];
	return tokens[1];
}
*/
// TODO: document function.
function Hide(divId, hide)
{
//	$('div#' + divId) or just $(divId)
	var item = document.getElementById(divId);
	if (item)
		if (hide)
			item.className='hidden';
		else
			item.className='unhidden';
	// swap:	
	// 		item.className=(item.className=='hidden')?'unhidden':'hidden';
}

var divSizes = new Array();
//TODO: document
function SwapHidden(divId)
{
	var item = document.getElementById(divId);
	item.className = (item.className == 'hidden') ? 'unhidden' : 'hidden';
	if (item.className == 'hidden')
	{
		// if we are hiding, save the size
		divSizes[divId] = $('div#' + divId).height();
		$('div#' + divId).height(0);
	}
	else
		$('div#' + divId).height(divSizes[divId]);
}
// TODO: document function.
function ShowDiv(divId, px)
{
	var item = document.getElementById(divId);
	item.className='unhidden';
	var h = divSizes[divId];
	if (px != 0)
		$('div#' + divId).height(px);
	else if (typeof(h) != 'undefined')
		$('div#' + divId).height(0);
}

/*
	var hide = (item.className=='hidden')?'unhidden':'hidden';
	if (item)
		if (hide == 'unhidden')
		{
			$('div#' + divId).height(0);
			item.className='hidden';
		}
		else
		{
			$('div#' + divId).height(100);
			item.className='unhidden';
		}
*/

/*
function ResetSessionTimeout()
{
	clearInterval(sessionTimer);
	sessionTimer = setTimeout('Log out();', 50 * 60 * 1000);
}
*/

/*
function ShowDialog(divid, name, html)
{
	var dialogOpts = { show: 'slide', dialogClass: '', title: name };
	$('#' + divid).dialog(dialogOpts);
	$('#' + divid).html(html);
	$('#' + divid).dialog('open');
}
*/

/*
function Lo gout()
{
	var jvar = '{ "lo gout" : "log out" }';
	$.getJSON("SkyAdmURL", jvar, function()
	{
		window.location = "index.jsp";
	});
}
*/
/**
 * Creates a yes/no dialog box with given message and invokes desired function
 * based on action.
 * @param {String} div Name of the div to apply the dialog box to.
 * @param {String} head Heading message for the dialog box.
 * @param {String} body Body content for the dialog.
 * @param {String} yesfun Function call to execute if 'Yes' is selected. Leave 
 * null if no action is desired.
 * @param {String} nofun Function call to execute if 'No' is selected. Leave 
 * null if no action is desired.
 */
function YNDialog(div, head, body, yesfun, nofun)
{
	var dialogOpts = { show: 'highlight', modal: true, closeOnEscape: true, dialogClass: 'ui-dialog', title: head, buttons:
			{
                "Yes": function()
                {
                    $(this).dialog('close');
					if (yesfun != null)
						eval(yesfun);
                },
                "No": function()
                {
                    $(this).dialog('close');
					if (nofun != null)
						eval(nofun);
                }
			}};

	$('div#' + div).dialog(dialogOpts);
	$('div#' + div).html(body);
	$('div#' + div).dialog('open');
}
// TODO: document function.
/**
 * Creates a dialgo box applied to the given div.
 * @param {String} div Name of the div to apply the dialog box to.
 * @param {String} head Heading message for the dialog box.
 * @param {String} body Body content for the dialog.
 * @param {Boolean} mod Determines if the dialog box is modal. Defaults to true
 * if undefined.
 * @param {Boolean} wide Indicates if the dialog box is to be wide (600).
 */
function Dialog(div, head, body, mod, wide)
{
	var modal = true;
	if (typeof(mod) != 'undefined')
		modal = mod;
	/*
	Close button looks nice - but takes up a huge amount of space
	var dialogOpts = { show: 'highlight', modal: modal, closeOnEscape: true, dialogClass: 'ui-dialog', title: head, buttons:
			{
                "Close": function()
                {
                    $(this).dialog('close');
                }
			}};
	*/
	var dialogOpts;
	if (wide)
		dialogOpts = { show: 'highlight', modal: modal, closeOnEscape: true, dialogClass: 'ui-dialog', title: head, width: 600 };
	else
		dialogOpts = { show: 'highlight', modal: modal, closeOnEscape: true, dialogClass: 'ui-dialog', title: head };
	$('div#' + div).dialog(dialogOpts);
	$('div#' + div).dialog('option', 'title', head);
	$('div#' + div).html(body);
	$('div#' + div).dialog('open');
}
// TODO: document function.
function ConvertLat(glat, hem)
{
	if (glat == 0)
		return glat;
	if (hem == 'S')
		glat = glat * -1;
	return glat; // .toFixed(6);
}
// TODO: document function.
function ConvertLong(glong, hem)
{
	if (hem == 'W')
		glong = glong * -1;
	return glong; // .toFixed(6);
}
// TODO: document function.
function GetDegrees(decimal, hem)
{
	if (decimal < 0)
		decimal = decimal * -1;
	var degrees = Math.floor(decimal);
	var minutes = decimal - degrees;
	minutes = minutes * 60;
	minutes = minutes.toFixed(2);
	return degrees + ' ' + minutes + ' ' + hem;
}
function FixLatLong(decimal, val1, val2)
{
	var hem = val1;
	if (decimal < 0)
	{
		decimal = decimal * -1;
		hem = val2;
	}
	var degrees = Math.floor(decimal);
	var minutes = decimal - degrees;
	minutes = minutes * 60;
	minutes = minutes.toFixed(2);
	return degrees + ' ' + minutes + ' ' + hem;
}
function IsLanding(code)
{
	if (code == 192 || code == 201)
		return true;
	return false;
}
function IsTakeoff(code)
{
	if (code == 193 || code == 200)
		return true;
	return false;
}
// TODO: document function.
function ShouldHighlight(code)
{
	if (code == 129 || code == 128 || code == 135 || code == 232)
		return false;
	return true;
}
// TODO: document function.
function IsPosition(code)
{
	if (code == '52' || code == '129' || code == '135' || code == '232')
		return true;
	return false;
}
// TODO: document function.
function ClearIt(id)
{
	$('#' + id).html('&nbsp;');
}
// TODO: document function.
function GetReasonCode(hash, noblanks)
{
	if (typeof(hash.code) != 'undefined')
		if (hash.code.length > 0 || !noblanks)
			return hash.code;
	if (noblanks)
		return GetCodeNoBlanks('' + hash.rc);
	else
		return GetCode('' + hash.rc);
}
// TODO: document function.
function GetCodeNoBlanks(code)
{
	var c = GetCode(code);
	if (c.length > 0)
		return c;
	if (IsPosition(code))
		return 'Position';
	return code;
}
// TODO: document function.
function GetCode(code)
{
	switch(code)
	{
	case  '52': return ''; // Position Report';
	case  '53': return 'Takeoff Heristic (LMC)';
	case  '54': return 'Landing Heristic (LMC)';
	case  '55': return 'Takeoff (LMC)';
	case  '56': return 'Landing (LMC)';
	case  '80': return 'Access';		// RMM
	case  '81': return 'Rearmed';		// RMM
	case  '83': return 'Authorized';	// RMM
	case  '80': return 'Access';
	case  '90': return 'Low Voltage';	// RMM
	case  '92': return 'Voltage Critical';	// RMM
	case  '97': return 'Power Up';
	case  '98': return 'Power Down';
	case  '99': return 'Event Button';
	case '128': return 'Old Protocol 128';
	case '129': return ''; // Position Report';
	case '130': return 'Startup/First Fix';
	case '131': return 'ShutDown Imminent';
	case '132': return 'Emergency';
	case '133': return 'Polled';
	case '134': return 'Pausing/Taxiing';
	case '135': return 'On Ground';
	case '136': return 'Non-Standard Startup';
	case '137': return 'Vehicle Stop';
	case '138': return 'Poll Acknowledgement';
	case '143': return 'Heartbeat';		// RMM
	case '144': return 'Ignition On';
	case '145': return 'Ignition Off';
	case '152': return 'Emergency On';
	case '153': return 'Emergency Off';
	case '154': return 'WOW Switch On/On Ground';
	case '155': return 'WOW Switch Off/In Air';
	case '156': return 'Event 1 On';
	case '157': return 'Event 1 Off';
	case '158': return 'Event 2 On';
	case '159': return 'Event 2 Off';
	case '160': return 'Event 3 On';
	case '161': return 'Event 3 Off';
	case '162': return 'Tracking Disable Engaged';
	case '163': return 'Tracking Disable Disengaged';
	case '165': return 'Event 4 On';
	case '166': return 'Event 4 Off';
	case '167': return 'Event 5 On';
	case '168': return 'Event 5 Off';
	case '169': return 'Event 6 On';
	case '170': return 'Event 6 Off';
	case '192': return 'Landing Heuristic';
	case '193': return 'Takeoff Heuristic';
	case '194': return 'Altitude above threshold';
	case '195': return 'Altitude below threshold';
	case '196': return 'Altitude Exception: Rapid Elevation Decrease';
	case '197': return 'Geofence Exception';
	case '198': return 'Out of gate';
	case '199': return 'In Gate';
	case '200': return 'Non-standard Takeoff';
	case '201': return 'Non-standard Landing';
	case '202': return 'Landing Approach';
	case '203': return 'Entering Safe Region';
	case '232': return '';		// old position
	case '245': return 'Data';
	case '246': return 'Data with Time';
	case '247': return 'Text Message'; // Data with GPS/Time';
	case '248': return 'Data with GPS/Time/IO';
	case '250': return 'PTA12 Msg';
	case '257': return 'Late Reporting';
	case '258': return 'Enter Geo-fence';
	case '259': return 'Exit Geo-fence';
	default: return code;
	}
}
// TODO: document function.
function Status(name, json, successmsg)
{
	if (typeof(json.error) != 'undefined')
	{
		$(name).html('Failure: ' + json.error + '<br/>');
		$(name).toggleClass('failed', true);
		$(name).toggleClass('succeeded', false);
	}
	else
	{
		$(name).html(successmsg + " <br/>");
		$(name).toggleClass('failed', false);
		$(name).toggleClass('succeeded', true);
	}
}
// TODO: document function.
function GetRow(v1, v2)
{
	return '<tr><td>' + v1 + '</td><td>' + v2 + '</td></tr>';
}
// TODO: document function.
function GetTd(v)
{
	return '<td>' + v + '</td>';
}
// TODO: document function.
function GetTdClass(v, cla)
{
	return '<td class="' + cla + '">' + v + '</td>';
}
/* An HTML generation function for creating a table data element with a given 
 * style and value.
 * @param {String} v The value for the td field.
 * @param {String} style The name of the style to be applied to the given td
 * element.
 * @return {String} The HTML for the td element ready to be applied to the 
 * document.
 */
function GetTdStyle(v, style)
{
	return '<td style="' + style + '">' + v + '</td>';
}

/**
 * A Utility function for casting different data types boolean data. If the 
 * value can not be sucessfully cast then the orriginal value is returned.
 * @param {Object} val The value to be converted to a boolean type. For integers
 * 0,'false','False' all equate to false and 1, 'true', 'True' all equate to 
 * true.
 * @return {Object} The boolean version of the value if possible.
 */

function CastBool(val)
{
	if (typeof(val) == 'boolean')
		return val;
	if (val == '1' || val == 'true' || val == 'True' || val == 'Y')
		return true;
	if (val == '0' || val == 'false' || val == 'False' || val == 'N')
		return false;
	return val;
}

/*
function setCookie(name, value) 
{
	var d = new Date(2020, 1, 1, 0, 0, 0);
	document.cookie = name + '=' + value + '; expires=' + d + '; path=/';
}

//	$.cookie(name, value, 365);

//	var exdate = new Date();
//	exdate.setDate(exdate.getDate() + expiredays);
//	document.cookie = c_name + "=" + escape(value); //  + ((expiredays==null) ? "" : ";expires=" + exdate.toGMTString());

*/
/**
 * Load a value from the cookie.
 * @param {string} name The variable being pulled.
 * @param {string} defvalue A defualt value to be returned if the variable is 
 * not contianed in the cookie.
 **/
function getCookie(name, defvalue)
{
	//cookies are stored as a semicolin delimited list split them up and 
        //itereate through each element.    
	var cookies = document.cookie.split(';');
	for (var i = 0; i < cookies.length; i++)
		if (cookies[i].indexOf(name) > -1) // stupid javascript, don't use names that are substrings of other names!
		{
			var tmp = cookies[i].split('=');
			return tmp[1];
		}
	return '' + defvalue;
}
// TODO: document function.
function setCookie(name, value)
{
	var date = new Date();
	date.setTime(date.getTime() + (365*24*60*60*1000));
	var expires = "; expires=" + date.toGMTString();
	document.cookie = name+"=" + value+expires+"; path=/";
	//c log('save cookie ' + document.cookie);
}

// note boolean returned as string
/*
function getCookie(name, defval)
{
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++)
	{
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return defval;
}
*/
// TODO: document function.
function eraseCookie(name)
{
	createCookie(name,"",-1);
}

/*
// the name is used in 2 places: as the "input" field and as the cookie name
function SetFromCookie(name)
{
	try
	{
		var tmp = $.cookie(name);
		if (tmp != null)
			$('input#' + name).val(tmp);
	}
	catch(e)
	{
		alert(cook + ' issue: ' + e);
	}
}
*/

	/*
	var tmp = $.cookie(name);
	if (tmp == null)
		setCookie(name, defvalue);
		return defvalue;
	return tmp;
	if (document.cookie.length > 0)
		c_start = document.cookie.indexOf(c_name + "=");
		if (c_start != -1)
			c_start = c_start + c_name.length+1;
			c_end = document.cookie.indexOf(";", c_start);
			if (c_end==-1)
				c_end = document.cookie.length;
			return unescape(document.cookie.substring(c_start,c_end));
	*/
// TODO: document function.
// for B.C. only, ignorning DST
function GetLocalTime_donotuse(utc)
{
	// dst: March 8, 2009 at 2:00AM - Nov. 1, 2009 at 2:00AM
	var dat = new Date(RemoveMilliseconds(utc));
	var milli = dat.getTime();
	dat.setTime(milli - (8 * 60 * 60));		// less 8 hours
//	if (dat.getMonth()+1 == 11 && dat.getDate() == 1)
//		if (dat.getHours() >= 2)
	return dat.toDateString() + ' ' + FormatTime(dat);
}

// TODO: document function.
// 0: emergency
// 1: very slow or (slow and way past reporting interval) or way past reporting interval (grey)
// 2: slow but not way past reporting interval (yellow)
// 3: at speed and reporting on time (green)
// 4: at speed but reporting is late (purple)
function CurrentState(lmc, dbutc, speedstr, connintstr, rc, enovdu)
{
	if (rc == '152' || rc == '132')	// emergency
		return 0;	// red
	//if (rc == '135' || rc == '154')	// on ground
	//	return 1;	// grey
	//if (speed < 5)
	//	return 1;	// grey
	// clog('get state ' + lmc + ' ' + dbutc + ' ' + speedstr + ' ' + connintstr + ' ' + enovdu);
	var onground = rc == 135 || rc == 137 || rc == 192 || rc == 201 || rc == 202 || rc == 154;
	var seclate = SecondsLate(dbutc);
	var speed = parseFloat(speedstr);
	var repint = 600;
	if (typeof(connintstr) != 'undefined' && connintstr != 'n/a')
		repint = parseInt(connintstr, 10);

	var minspeed = 20;
	var threshold = 60 * 15;

	// order here matters:
	if (seclate > repint + 1800)	// 30 min late
		return 1;	// grey
	if (speed < minspeed && seclate > repint + 300)
		return 1;	// grey
//clog('not slow and late');
	if (speed < minspeed || onground)
		return 2;	// yellow
//clog('not slow and on ground');
	if (seclate < repint + threshold)
		return 3;	// green
//clog('not green');
	if (!enovdu)
		return 2;	// yellow
//clog('not enovdu');
	if (seclate >= repint + threshold)
	{
		if (IsPacificCoastal(lmc))
			if (rc == 156 || speed < 40)	// 156: down and clear
				return 2;
//clog('not paccoastal');
		return 4;	// purple
	}
	clog('Unexpected current state; late: ' + seclate + '; speed: ' + speedstr + '; conn: ' + connintstr + '; rc: ' + rc);
	return 4;
}
// TODO: document function.
function IsPacificCoastal(lmc)
{
	if (lmc == '70010254')
		return true;
	if (lmc == '70010255')
		return true;
	if (lmc == '70010258')
		return true;
	if (lmc == '70010259')
		return true;
	if (lmc == '70010260')
		return true;
	if (lmc == '70010268')
		return true;
	if (lmc == '70010290')
		return true;
	if (lmc == '70010406')
		return true;
	return false;
}

// TODO: document function.
function TrimArray(arr)
{
	if (typeof(arr) == 'undefined' || arr.length == 0)
		return new Array();
	var tmp = new Array();
	tmp[0] = arr[0];
	return tmp;
}

/*
function SecondsDiff(dat1, dat2)
{
	var fix1 = RemoveMilliseconds(dat1).replace('-','/').replace('-','/');
	var fix2 = RemoveMilliseconds(dat2).replace('-','/').replace('-','/');
	var milli1 = Date.parse(fix1);
	var milli2 = Date.parse(fix2);
	if (milli1 > milli2)
		return (milli1 - milli2)/1000;
	return (milli2 - milli1)/1000;
}
*/

// TODO: document function.
function SecondsLate(dbutc)
{
	if (typeof(dbutc) == 'undefined')
		return 'huh?';
	var fixed = RemoveMilliseconds(dbutc).replace('-','/').replace('-','/');
	var milli1 = Date.parse(fixed + " GMT-0000");

	// would be nice if this was easier...
	var now = new Date();
	var nowutc = Date.UTC(
		now.getUTCFullYear(),
		now.getUTCMonth(),
		now.getUTCDate(),
		now.getUTCHours(),
		now.getUTCMinutes(),
		now.getUTCSeconds()
	);
	return (nowutc - milli1)/1000;
}

// TODO: document function.
function RemoveMilliseconds(date)
{
	try
	{
		var dot = date.indexOf('.');
		if (dot < 0)
			return date;
		return date.substr(0, dot);
	}
	catch(e)
	{
	}
}

// TODO: document function.
function RemoveTime(date)
{
	var space = date.indexOf(' ');
	if (space < 0)
		return date;
	return date.substr(0, space).replace('-','/').replace('-','/');
}

/*
function ReasonCode2Text(code)
{
	var red = '<span style="background-color: #ff5465;">';
	var yel = '<span style="background-color: #f6ffbf;">';
	var blu = '<span style="background-color: #a0fff2;">';
	var gre = '<span style="background-color: #a6ff59;">';
	if (code == 0x50)
		return blu + 'Door open</span>';
	if (code == 0x51)
		return gre + 'System rearmed</span>';
	if (code == 0x52)
		return red + 'Door open alarm (man down)</span>';
	if (code == 0x53)
		return blu + 'Authorized iButton</span>';
	if (code == 0x54)
		return red + 'Unauthorized iButton</span>';
	if (code == 0x55)
		return red + 'No iButton scanned</span>';
	if (code == 0x5A)
		return red + 'Low voltage alarm</span>';
	if (code == 0x8F)
		return gre + 'Heartbeat</span>';
	return yel + 'Unknown</span>';
}
*/

// TODO: document function.
function StatusText(div, text)
{
	//var msg = FormatTime(new Date()) + ' ' + text;
	var msg = text;
	if (text == '' || text == ' ')
		msg = ' ';
	$(div).html(msg);
}

// TODO: document function.
function CheckDate(date)
{
	if (date.length < 8 || date.length > 10)
		return false;
	var tokens = date.split('/');
	if (tokens.length != 3)
		return false;
	if (isNaN(tokens[0]) || isNaN(tokens[1]) || isNaN(tokens[2]))
		return false;
	var y = parseInt(tokens[0], 10);
	var m = parseInt(tokens[1], 10);
	var d = parseInt(tokens[2], 10);
	if (y < 2000 || y > 2030)
		return false;
	if (m < 1 || m > 12)
		return false;
	if (d < 1 || d > 31)
		return false;
	return true;
}

// TODO: document function.
function WrongOrder(d1, t1, d2, t2)
{
	var argh1 = new Date(d1 + ' ' + t1);
	var argh2 = new Date(d2 + ' ' + t2);
	return argh2.getTime() < argh1.getTime();
}

// TODO: document function.
function CheckTime(time)
{
	var tokens = time.split(':');
	if (tokens.length != 2)
		return false;
	if (isNaN(tokens[0]) || isNaN(tokens[1]))
		return false;
	var hours = parseInt(tokens[0], 10);
	if (hours < 0 || hours > 23)
		return false;
	var minutes = parseInt(tokens[1], 10);
	if (minutes < 0 || minutes > 59)
		return false;
	return true;
}

// TODO: document function.
function getRawOffset()
{
	var today = new Date();
	return -1 * today.getTimezoneOffset();
}

// TODO: document function.
// text version for display
function getOffset(off)
{
	var today = new Date();
	off = -1 * today.getTimezoneOffset();
   	if (off > 0)
   		return '+' + (off/60);
   	else
		return '' + (off/60);
}

// TODO: document function.
/**
 *
 */
function MergeAir(aircraft, json)
{
	if (typeof(json) == 'undefined')
		return;
	for (var i = 0; i < json.length; i++)
		MergeAircraft(aircraft, json[i]);
}
// TODO: document function.
// called in loop by MergeAir()
function MergeAircraft(aircraft, hmap)
{
	for (var i = 0; i < aircraft.length; i++)
	{
		if (hmap.lmc_id != aircraft[i].lmc_id)
			continue;
		aircraft[i].speed = hmap.speed;
		aircraft[i].utc = hmap.utc;
		aircraft[i].local = hmap.local;
		aircraft[i].rc = hmap.rc;
		aircraft[i].code = hmap.code;
		aircraft[i].ustate = hmap.ustate;
		aircraft[i].degrees = hmap.degrees;
		aircraft[i].altitude = hmap.altitude;
		aircraft[i].time_t = hmap.time_t;
		aircraft[i].lat = hmap.lat;
		aircraft[i].lng = hmap.lng;
		aircraft[i].tail = hmap.tail;
		// c log('merge ' + hmap.tail + ' ' + hmap.degrees + ' ' + aircraft[i].degrees);
		break;
	}
}
/**
 * Scrubs a string removing a number of unwanted characters. 
 * @param {String} string A string desired to be cleared of any unwanted 
 * characters.
 * @return {String} A string with unwanted characters removed.
 */
function FixString(string) 
{
	var fix = string.replace('<','').replace('>','').replace('\'','').replace('%', '').replace('#', '');
	while(fix != string)
	{
		string = fix;
		fix = string.replace('<','').replace('>','').replace('\'','').replace('%', '').replace('#', '');
	}
	return fix;
}

/**
 * Prepares a measurement for display. Converts to the approperate units. Inputs
 * are always in meters.
 * @param meters
 * @param prec
 * @param metric
 */
function DisplayDistanceMeasurement(meters, prec, metric)
{
	var result;
	if(metric) 
	{
		result = parseInt(Math.round(parseFloat(meters) * Math.pow(10,prec))/Math.pow(10,prec)).toFixed(prec);
	}
	else 
	{
		result = parseInt(Math.round(parseFloat(meters) * 3.2808399 * Math.pow(10,prec+2))/Math.pow(10,prec+2)).toFixed(prec);
	}
	return result;
}

function DisplayMinorDistanceUnits(metric) {
	var result;
	if(metric)
		result = 'm';
	else
		result = 'ft';
	return  result;
}
