////////////////////////////////////////////////////////////////////////////////
// sourcefile:  ./main.js
// TODO - remove all DOM ids from this file, every function in here should be
// generic. If ids are needed the js should be in the template
//
///////////////////////////////////////////////////////////////////////////////
// Extend jQuery with functions for PUT and DELETE requests.

function _ajax_request(url, data, callback, type, method) {
	if (jQuery.isFunction(data)) {
		callback = data;
		data = {};
	}
	return jQuery.ajax({
		type: method,
		url: url,
		data: data,
		success: callback,
		dataType: type
		});
}

jQuery.extend({
	put: function(url, data, callback, type) {
		return _ajax_request(url, data, callback, type, 'PUT');
	},
	delete_: function(url, data, callback, type) {
		return _ajax_request(url, data, callback, type, 'DELETE');
	}
});

///////////////////////////////////////////////////////////////////////////////
// Generic function to check form submissions have no empty fields
function formCheck(fieldlist, fieldnames, theForm) {

	for (var i = 0; i < fieldlist.length; i++) {
		if (fieldlist[i].value == '') {
			theForm.submitted = false;
			alert('Please fill in the group ' + fieldnames[i] + '!');
			return false;
		}
	}
	theForm.submitted = true;
	theForm.submit();
}

///////////////////////////////////////////////////////////////////////////////
// functions for personal codes (for business cards)
function code_random() { 
	var elem = document.getElementById("result_random");
	elem.innerHTML = '<img src="' + baseUrl + 'static/images/remembermilk_orange.gif" />';
	elem = document.getElementById("result_custom");
	if(elem) { elem.innerHTML = ''; }
	elem = document.getElementById("custom");
	if(elem) { elem.value = ''; }
	
	//Jemplate.process('code_random.tt2', baseUrl+'code/random', '#result_random');
	//t = document.getElementById("result_random");
	//alert(t.innerHTML);
	//pausecomp(100);
	//alert(t.innerHTML);
	//Jemplate.process('code_info.tt2', baseUrl+'code/current', '#userocodeinfo');
	
	var data = Jemplate.Ajax.get( baseUrl+'code/random' );
	var obj = JSON.parse(data);
    elem = document.getElementById('result_random');
    Jemplate.process('code_random.tt2', obj, elem);
} 

function code_custom() { 
	var elem = document.getElementById("result_random");
	elem.innerHTML = '';
	elem = document.getElementById("result_custom");
	elem.innerHTML = '';
	var theInput = document.getElementById("custom");
	var theCode = theInput.value;

	var codeOK = checkcode(theCode);
	if (! codeOK) return false;
    
	//Jemplate.process('code_custom.tt2', , '#result_custom');
	//pausecomp(1000);
	//Jemplate.process('code_info.tt2', baseUrl+'code/current', '#userocodeinfo');

	var data = Jemplate.Ajax.get( baseUrl+'code/custom/'+theCode );
	var obj = JSON.parse(data);
    elem = document.getElementById('result_custom');
    Jemplate.process('code_custom.tt2', obj, elem);
} 

function code_confirm(which) {
	var data = Jemplate.Ajax.get( baseUrl+'code/confirm' );
	var obj = JSON.parse(data);
    elem = document.getElementById('result_'+which);
    Jemplate.process('code_'+which+'.tt2', obj, elem);
	if(obj.code) {
		elem = document.getElementById('userocodeinfo');
		Jemplate.process('code_info.tt2', obj, elem);
	}
}

function checkcode(theCode) { 
	if (theCode == null || theCode === "") {
        alert('Code can not be empty; please enter a code and try again.');
        return false;
    }
    
	if (theCode.match(/ /)) {
        alert('Sorry, your code can not contain a space.');
        return false;
    }
    
	if (theCode.match(/[^a-zA-Z0-9]/)) {
        alert('Sorry, your code can only contain numbers and letters.');
        return false;
    }
    
	if (theCode.match(/^[YyNn][0-9]+/)) {
        alert('Sorry, your code can not start with Y or N followed by digits.');
        return false;
    }
    
	// rely on server-side check only. This effectively allows Twilio unique codes to
	// be all digits, but shortcode codes still cannot.
	//if (theCode.match(/^[0-9]+$/)) {
    //    alert('Sorry, your code cannot be all digits.');
    //    return false;
    //}
    
    // TODO: this should use $self->{custom}->{mincodelength}
	if (theCode.length < 3) {
        alert('Sorry, your code must be at least 3 characters long.');
        return false;
    }
    
	return true;
} 


function pausecomp(millis)
{
var date = new Date();
var curDate = null;

do { curDate = new Date(); }
while(curDate-date < millis);
}

///////////////////////////////////////////////////////////////////////////////

var editedField = null;
var focusField = null;
var origContent = null;
var saving = 0;

function view_contact(id) { 
	$j.getJSON(baseUrl+'rest/contact/'+id, function(data) {
		if (data.error) jsonError(data);
		Jemplate.process('contact_card.tt2', data, '#contactShadow');

		$j("#contactShadow").fadeIn('slow');
		
		// format the date fields
		$j("input.carddate").dateFormat(gDateformat);
	
		// Only setup events if we own this contact
		if (data.contact.user_id == gUserid) {
			setupevents();
		}
		else {
			disablefields("readonly");
		}
    });
} 

function add_contact() { 
	$j.post(baseUrl+'rest/contact/-1', { contact: -1 }, function(data) {
		if (data.error) jsonError(data);
		Jemplate.process('contact_card.tt2', data, '#contactShadow');

		$j("#contactShadow").fadeIn('slow');
		setupevents();
		
    }, "json" );
} 

function disablefields(state) {
	editedField = null;
	focusField = null;
	origContent = null;

	var attr = "readonly";
	if(state == "disabled") {
		attr = "disabled";
	}
	
	$j("#cardName").append(" (Read only)");
	$j("input.cardfld").attr(attr,attr);
	$j("input.cardspecial").attr(attr,attr);
	$j("textarea.cardfld").attr(attr,attr);
	$j("span.lblpop").attr(attr,attr);
	$j("div.add").remove();
	$j("div.remove").remove();
}


function setupevents() {
	editedField = null;
	focusField = null;
	origContent = null;

	$j("input:text.cardfld").focus( function (event) {
		focusfield(this);
	});
	$j("input:text.cardfld").keyup( $j.throttle( 250, function (event) {
		keyupfield(this, event.keyCode);
	}));
	$j("input:text.cardfld").change( function() {
		changefield(this);
	});
	//
	$j("input:radio.cardfld").click( function (event) {
		focusfield(this);
		changefield(this);
	});
	$j("input:checkbox.cardfld").click( function (event) {
		focusfield(this);
		changefield(this);
	});
	//
	$j("textarea.cardfld").focus( function (event) {
		focusfield(this);
	});
	//$j("textarea.cardfld").keyup( function (event) {
	//	keyupfield(this, event.keyCode);
	//});
	$j("textarea.cardfld").keyup( $j.throttle( 250, function (event) {
		keyupfield(this, event.keyCode);
	}));
	
	$j("textarea.cardfld").change( function() {
		changefield(this);
	});
	
	
	$j("span.lblpop").click( function() {
		showpopup(this);
	});
	
	$j("span.varclick").click( function (event) {
		insertvar(this);
	});	
}

function focusfield(field) {
	if(focusField) {
		focusField.parentNode.parentNode.style.backgroundColor='white';
	}
	if (field.className.indexOf('hilite') > -1) {
		// use blue3
		field.parentNode.parentNode.style.backgroundColor='#dee5ef';
	}
	origContent = field.value;
	focusField = field;
}

function blurfield(field) {
	field.parentNode.parentNode.style.backgroundColor='white';
	focusField = null;
}

function keyupfield(field, key) {
	// don't do anything if tab or return is pressed
	if (key != 9 && key != 13) {
		//if a key was pressed but content is the same as it was when this
		// field first got focus, we got back to our orig state, so set
		// colour to black
		if (origContent == field.value) {
			field.style.color='black';
		}
		else {
			// else flag that it has changed
			field.style.color='red';
			//alert(key);
			editedField = field;
		}
	}
	if (field.id =='custommessage' ) {
		customMsgCount(field);
	}
}

function changefield(field) { 	
	//alert(field.id);
	//alert(field.value);
	//alert(field.className);
	
	//var data = Jemplate.Ajax.post( baseUrl+'rest/field?id='+field.id+'&val='+field.value );
	//var data = Jemplate.Ajax.post( baseUrl+'rest/field/'+field.id+'/'+field.value );
	//var obj = JSON.parse(data);
	//var data = $j.put( baseUrl+'rest/field', { id: field.id, val: field.value } );
	
	//alert("Field type: " + field.type + ".");
	
	var theVal;
	if (field.type == 'checkbox') {
		theVal = field.checked;
	}
	else if (field.className.indexOf('carddate') > -1) {
		// a date field was changed, so we need to parse the date and display it in the local format
		theVal = field.value;
		// first try parsing using display format
		//var theDate = o2s.parseDate(theVal, gDateformat);
		// if that fails, try without the format - this tryies several different styles
		//if (theDate == null) {
			var theDate = o2s.parseDate(theVal);
		//}
		if (theDate == null) {
			alert("Sorry, I couldn't understand that date, please try again.");
			return false;
		}
		theVal = o2s.format(theDate, 'yyyy-mm-dd');
		field.value = o2s.format(theDate, gDateformat);
	}
	else if ((field.className.indexOf('lblpop') > -1) && (field.value == 'Other')) {
		// Other was chosen in a popup - switch to an input field
		var tId = field.id;
		field.parentNode.innerHTML = '<input type="text" value="Other" size="8" id="'+ field.id +'" name="'+ field.id +'" maxlength="100" class="cardfld hilite" style="border: none;" />';
		var tElem = document.getElementById(tId);
		setupevents();
		focusfield(tElem);
		theVal = field.value;
	}
	else if (field.id =='custommessage') {
		/* Don't trim!
		theVal = customMsgText(field);
		// trim to 130 or 160 chars or whatever
		if (theVal.length > customMsgMax) {
			var endText = customMsgTextEnd(field);
			var endLen = endText.length;
			field.value = customMsgTextStart(field).substring(0, (customMsgMax - endLen));
			customMsgCount(field);
		}
		*/
		theVal = customMsgTextStart(field);
	}
	else if (field.id =='customurl') {
		theVal = field.value;
		customUrlChange(theVal);
	}
	else {
		theVal = field.value;
		// get rid of Windows line ends from IE
		theVal = theVal.replace(/\r/g, "");
	}
	
	// we're going to try to save, so show some user entertainment
	var theNameElem = document.getElementById("autosave");
	var theName = theNameElem.innerHTML;
	theNameElem.innerHTML = "Saving new details...";
	$j("#autosave").fadeIn('slow');

	saving = 1;
	editedField = null;
	//$j.put( baseUrl+'rest/field/'+field.name+'_'+escape(theVal)+'?val='+escape(theVal), { name: field.name }, function(data){
	$j.put( baseUrl+'rest/field/'+field.name+'_?val='+escape(theVal), { name: field.name }, function(data){
		if (data.error) jsonError(data);
		$j("#autosave").fadeOut('slow');
		field.style.color='black';
		saving = 0;		
	}, "json" );
}

function close_contact() { 
	//HideContent('contactShadow');
	if (editedField != null) {
		//alert("Saving field:" + editedField.name);
		changefield(editedField);
	}
	$j("#contactShadow").fadeOut('slow');
	ClearContent('contactLayer');
} 

// TODO
// change this to a jemplate action instead - don't like this being in javascript
// also we should fetch and cache the lists from the db, instead of hard coding them
function showpopup(field) {
	var tstr = '<select id="'+ field.id +'" name="'+ field.id +'" onchange="changefield(this);" onfocus="focusfield(this);" class="lblpop hilite">';
	
	var tList;
	var tType = field.id;
	tType = tType.replace(/_.*/,"");
	switch (tType)
	{
		case "phone":
			tList = ['Home', 'Work', 'Mobile', 'Fax', 'Other' ];
			break;
		case "email":
			tList = ['Home', 'Work', 'Other' ];
			break;
		case "im":
			tList = ['AIM', 'Google', 'Skype', 'MSN', 'Jabber', 'Twitter', 'Facebook', 'ICQ', 'Other' ];
			break;
		case "address":
			tList = ['Home', 'Work', 'Other' ];
			break;
		case "mydate":
			tList = ['Anniversary', "Wife's birthday", 'Other' ];
			break;
		case "other":
			tList = ['Web page', 'Spouse', 'Interests', 'Children', 'Notes', 'Custom', 'Other' ];
			break;
		default:
			tList = [];
	}
	
	var found = 0;
	for (var i = 0; i < tList.length; i++) {
		if (field.innerHTML == tList[i]) {
			tstr = tstr + '<option value="'+tList[i]+'" selected="selected">'+tList[i]+'</option>';
			found = 1;
		}
		else {
			tstr = tstr + '<option value="'+tList[i]+'">'+tList[i]+'</option>';
		}
	}
	// tack on the current selection if it wasn't in the list
	if (found == 0) {
			tstr = tstr + '<option value="'+field.innerHTML+'" selected="selected">'+field.innerHTML+'</option>';
	}
	tstr = tstr + '</select>';
	var tId = field.id;
	var tPar = field.parentNode;
	if (tPar) {
		tPar.innerHTML = tstr;
	} else {
		// sometimes we get in here, but the previous statement seems to have worked anyway. go figure!
		//alert('bug!');
	}
	var tElem = document.getElementById(tId);
	focusfield(tElem);
}

function addItem(theTable, contact_id) {
	$j.post( baseUrl+'rest/newitem/'+theTable+'/'+contact_id, { contact: contact_id }, function(data) {
		if (data.error) jsonError(data);
		Jemplate.process('contact_card_'+theTable+'.tt2', data, '#'+theTable+'ListDiv');
		// format the date fields
		$j("input.carddate").dateFormat(gDateformat);
		setupevents();
		
		// scroll to end of div and end of tab - div for IE/Safari, tab for FF
		var tDiv = document.getElementById(theTable+'ListDiv')
		tDiv.scrollTop = tDiv.scrollHeight;
		var tTab = document.getElementById(theTable+'List')
		tTab.scrollTop = tTab.scrollHeight;
		
		// get next to last row (last one is a blank)
		var lastRow = tTab.rows[tTab.rows.length - 2];
		// get last td of row - last node is a textnode
		var lastCell = lastRow.cells[lastRow.cells.length - 1];
		// get child of last td, which should be the input field
		focusField = lastCell.childNodes[0];
		// give it focus after 100ms (delay required for IE - FF works without)
		setTimeout("focusField.focus();", 200);
		
    }, "json" );
    
}

function delItem(theTable) {
	var theName = theTable;
	if (theName == 'mydate') { theName = 'date'; }
	if (theName == 'im') { theName = 'IM'; }
	if (theName == 'other') { theName = 'other info'; }
	
	// check something has focus
	if (!focusField) {
		alert("You must select one "+theName+" item to remove.");
		return (false);
	}

	// check that the item that has focus is the right type of thing for this button
	// focusField.name should be something like phone_phone_1
	if (focusField.name.indexOf('contact_') == 0) {
		alert("You can't delete this field.");
		return (false);
	}
	if (focusField.name.indexOf(theTable) != 0) {
		alert("You must select at least one "+theName+" to remove.");
		return (false);
	}
	
	var doit=confirm("Do you really want to delete this "+theName+"?");
	if (doit== false) {
		return (false);
	}

	$j.delete_( baseUrl+'rest/field/'+focusField.name+'_'+focusField.value, { name: focusField.name }, function(data){
		if (data.error) jsonError(data);
		Jemplate.process('contact_card_'+theTable+'.tt2', data, '#'+theTable+'ListDiv');
		// format the date fields
		$j("input.carddate").dateFormat(gDateformat);
		setupevents();
	}, "json" );

}

function customMsg(tCheckbox, theTextareaName, theSpanName) {
	var theTextarea = document.getElementById(theTextareaName);
	theTextarea.value = '';
	if (tCheckbox.checked) {
		theTextarea.style.display = "block";
		
		$j.put( baseUrl+'rest/custommsg/1', {}, function(data) { 
			if (data.card) {
				theTextarea.value = data.card;
				customMsgCount(theTextarea, theSpanName);
			}
			else {
				theTextarea.value = 'Sorry, an error occurred fetching the card info';
			}
		}, "json" );
	}
	else {
		$j.put( baseUrl+'rest/custommsg/0' );
		theTextarea.style.display = "none";	
	}
	customMsgCount(theTextarea, theSpanName);
}

function customUrlChange(theVal) {
	var msgField = document.getElementById('custommessage');
	var endField = document.getElementById('custommessageend');
	var endUrl = document.getElementById('custommessageshorturl');
	var endDefault = document.getElementById('custommessageenddefault');
	if(endField && endUrl && endDefault) {
		if(theVal == '') {
			endField.value = endDefault.value;
		}
		else {
			endField.value = endUrl.value + ' \n' + endDefault.value;			
		}
		customMsgCount(msgField);
		changefield(msgField);
	}
	else if (endField && endUrl) {
		if(theVal == '') {
			endField.value = '';
		}
		else {
			endField.value = endUrl.value;
		}
		customMsgCount(msgField);
		changefield(msgField);	
	}
}

function customMsgTextStart(theTextarea) {
	var theText = theTextarea.value;
	if(!theText) { return ''; }
	// get rid of Windows line ends from IE
	theText = theText.replace(/\r/g, "");
	//alert('Start: "' + theText + '"');
	return theText;
}

function customMsgTextEnd(theTextarea) {
	var theText = '';
	var theEnd = document.getElementById(theTextarea.id + 'end');
	if (theEnd && theEnd.value) {
		theText = ' \n' + theEnd.value;
	}
	// get rid of Windows line ends from IE
	theText = theText.replace(/\r/g, "");
	//alert('End: "' + theText + '"');
	return theText;
}

function customMsgText(theTextarea) {
	var theText = '';
	theText = customMsgTextStart(theTextarea) + customMsgTextEnd(theTextarea);
	return theText;
}

var customMsgMax = 160;
function setMsgMax(tMax) {
	customMsgMax = tMax;
}

var subPatterns;
function customMsgSubVarLengths(theText) {
	if (subPatterns == undefined) {
		//alert("Setting subPatterns");
		subPatterns = new Array;
		var tTxt = $j('#customvariablelengths').html();
		if (tTxt == undefined) return theText;
		var pairs = tTxt.split(",");
		for (var i = 0; i < pairs.length; i++) {
			if (pairs[i]) {
				var dat = pairs[i].split(":");
				var tStr = "";
				if (dat[2]) {
					tStr = dat[2];				
				}
				else {
					for (var j = 0; j <= dat[1]; j++) tStr = tStr + "X";
				}
				subPatterns.push({pat: new RegExp(dat[0], "g"), rep:tStr});
			}
		}
	}
	//console.log(subPatterns);
	for (var i=0;i<subPatterns.length;i++) {
		theText = theText.replace(subPatterns[i].pat, subPatterns[i].rep);
	}
	//console.log(theText);
	return theText;
}

function customMsgCountGet(theTextarea) {
	var theText = customMsgText(theTextarea);
	theText = customMsgSubVarLengths(theText);
	var charCount = theText.length;
	$j('#theTextPreview').html(theText);
	return charCount;
}

function customMsgCount(theTextarea) {
	var charCount = customMsgCountGet(theTextarea);
	
	var theSpan = document.getElementById(theTextarea.id + 'Count');
	if (theSpan) {
		theSpan.innerHTML=charCount + "/" + customMsgMax;

		if (charCount > customMsgMax) {
			theSpan.style.color = "red";
		}
		else {
			theSpan.style.color = "green";
		}	
	}
}

function jumpTo(lnk) {
	document.getElementsByName(lnk)[0].scrollIntoView();
	document.getElementById('header').scrollIntoView();
	return false;
}
///////////////////////////////////////////////////////////////////////////////

function submitForm(theAction) {
	// all other actions require that at least one checkbox be checked
	var checkSelected = false;
	var checkArray = document.contactForm.contact;
	if (checkArray.length) {
		// there are multiple checkboxes
		for (i = 0;  i < checkArray.length;  i++) {
			if (checkArray[i].checked)
			checkSelected = true;
		}
	}
	else {
		// there is only one
		if (checkArray.checked)
		checkSelected = true;	
	}
	if (!checkSelected) {
		alert("You must select at least one contact to " + theAction + ".");
		return (false);
	}
	if (theAction == "delete") {
		var doit=confirm("Do you really want to delete contact(s)?");
		if (doit== false) {
			return (false);
		}
	}
	document.contactForm.theAction.value = theAction;
	document.contactForm.submitted = true;
	document.contactForm.submit();
}

// check or uncheck all checkboxes in a group on a form
function checkUncheckAll(me, field)
{
	if (field.length) {
		for (i = 0; i < field.length; i++)
			field[i].checked = me.checked ;
	}
	else {
		// only one checkbox
		field.checked = me.checked ;
	}
}


///////////////////////////////////////////////////////////////////////////////
// Code to resize contact table automatically, and to scroll contact table to
// correct position
function tableResize(offsetArray) {
	var tableId;
	for (tableId in offsetArray) {
		if(document.getElementById(tableId)) {
			var a = $j(window).height() - offsetArray[tableId];
			if (a < 360) { a = 360; }
			var newHeight1 = a;
			var newHeight2 = a - 22;
			var selector1 = '#' + tableId;
			var selector2 = '#' + tableId + 'Table';
			var selector3 = '#' + tableId + 'TableBody';
			$j(selector1).height(newHeight1);
			$j(selector2).height(newHeight1);
			$j(selector3).height(newHeight2);
		}
	}
}

function tableScroll() {
var theScroll = document.getElementById("scrollValue");
if(theScroll) {
	var scrollVal = theScroll.innerHTML;
	var theTable = document.getElementById("contactsTableBody");
	if(theTable) {
		theTable.scrollTop = scrollVal;
	}
}
}

if(window.tableOffset!=undefined) {
$j(document).ready(function(){
	tableResize(tableOffset);
	tableScroll();
 });

var resizeTimer = null;
$j(window).bind('resize', function() {
    if (resizeTimer) clearTimeout(resizeTimer);
    resizeTimer = setTimeout('tableResize(tableOffset)', 100);
});
}


///////////////////////////////////////////////////////////////////////////////


function ClearContent(d) {
if(d.length < 1) { return; }
document.getElementById(d).innerHTML="";
}
function HideContent(d) {
if(d.length < 1) { return; }
document.getElementById(d).style.display = "none";
}
function ShowContent(d) {
if(d.length < 1) { return; }
document.getElementById(d).style.display = "block";
}
function ReverseContentDisplay(d) {
if(d.length < 1) { return; }
if(document.getElementById(d).style.display == "none") { document.getElementById(d).style.display = "block"; }
else { document.getElementById(d).style.display = "none"; }
}

///////////////////////////////////////////////////////////////////////////////
// supply with country code and mobile number,
// get back a cleaned up mobile number plus whether it is ok or not
// TODO - more countries
function cleanMobile(countrycode, mobile) {

	// remove () - space etc
	mobile = mobile.replace(/[ \(\)\.\-]/g, "");
	// remove leading plus if it exists
	mobile = mobile.replace(/^\+/, "");

	var ok = false;
	if (countrycode == 1) {
		// US mobiles are always 10 digits
		if (mobile.length == 11) mobile = mobile.replace(/^1/, "");
		if (mobile.length == 10) ok = true;
	} else if (countrycode == 44) {
		// UK mobiles are always 10 digits
		if (mobile.length == 11) mobile = mobile.replace(/^0/, "");
		if (mobile.length == 12) mobile = mobile.replace(/^44/, "");
		if (mobile.length == 13) mobile = mobile.replace(/^440/, "");
		if (mobile.length == 10) ok = true;
	} else if (mobile.length > 6) {
		ok = true;
	}
	
	mobile = countrycode + mobile;
	return {'mobile':mobile, 'ok':ok};
}
///////////////////////////////////////////////////////////////////////////////
function do_select(theNum) {

for (i = 1;  i < 6;  i++)
{
	var theTab = document.getElementById("tab_"+i);
	if(theTab) {
		if (i == theNum) {
			theTab.className = "tabbed_pane_tab selected_tab";
			document.getElementById("box_"+i).style.display = "block";
		}
		else {
			theTab.className = "tabbed_pane_tab";
			document.getElementById("box_"+i).style.display = "none";
		}
	}
}

}

function setPref(prefName, prefVal) {
	$j.post(baseUrl+'setpref', { name: prefName, value: prefVal }, function(data) {
		if (data.error) jsonError(data);
    }, "json" );

}

///////////////////////////////////////////////////////////////////////////////
// filters a table
// thanks to http://www.vonloesch.de/node/23?filt=col

function filter (term, _id, cellNr){
	var suche = term.value.toLowerCase();
	var table = document.getElementById(_id);
	var ele;
	for (var r = 1; r < table.rows.length; r++){
		ele = table.rows[r].cells[cellNr].innerHTML.replace(/<[^>]+>/g,"");
		if (ele.toLowerCase().indexOf(suche)>=0 )
			table.rows[r].style.display = '';
		else table.rows[r].style.display = 'none';
	}
}

function filter2 (phrase, _id, tImg){
	var words = phrase.value.toLowerCase().split(" ");
	var table = document.getElementById(_id);
	var ele;
	for (var r = 1; r < table.rows.length; r++){
		if (table.rows[r].className == 'alwaysDisplay') {
			continue;
		}
		ele = table.rows[r].innerHTML.replace(/<[^>]+>/g,"");
	        var displayStyle = 'none';
	        for (var i = 0; i < words.length; i++) {
		    if (ele.toLowerCase().indexOf(words[i])>=0)
			displayStyle = '';
		    else {
			displayStyle = 'none';
			break;
		    }
	        }
		table.rows[r].style.display = displayStyle;
	}
	
	var tImage = document.getElementById(tImg);
	if (tImage) {
		if (phrase.value) {
			tImage.style.display = '';
		} else {
			tImage.style.display = 'none';		
		}
	}
}

function clearfilter (tInp, _id, tImage) {
	tImage.style.display = 'none';
	var tInput = document.getElementById(tInp);
	tInput.value = '';
	filter2(tInput, _id, "");
}

////////////////////////////////////////////////////////////////////////////
// code for searching for and displaying a list of accounts
var acctTimeout;
var acctLastSearch;
function acctKey(acctfield) {
	if (acctTimeout) clearTimeout(acctTimeout);

	var acct = acctfield.value;
	var tClear = $j(acctfield).attr('rel');
	if (acct.length) {
		$j('#'+tClear).show();
	} else {
		$j('#'+tClear).hide();
	}

	if (acctLastSearch == acct) return false;
	acctLastSearch = acct;
	acctTimeout = setTimeout(function() {searchAccount(acct);}, 500);
}

function searchAccount(acct) {
	if (acct.length < 3) {
		$j('#userlistwrapper').html('');
		$j('#userinfowrapper').html('');
		$j('#debitwrapper').hide();
		return false;
	}
	
	$j.getJSON(baseUrl+'admin/user_with_contact/'+acct, function(data) {
		if (data.error) jsonError(data);
		Jemplate.process('userlist.tt2', data, '#userlistwrapper');
	});
}

function clearsearch (tImage) {
	tImage.style.display = 'none';
	var tInp = $j(tImage).attr('rel');
	var tInput = document.getElementById(tInp);
	tInput.value = '';
}

////////////////////////////////////////////////////////////////////////////
function setcodedefaultdata(data) {
	data.maxfilesize = maxfileupload; // see ocodes.js and ocodes.yml config
	data.msgmax = customMsgMax;
	data.maxvoucher = maxvoucher;
	data.vouchersubstitution = vouchersubstitution;
}

function add_customcode(voucher) { 
	var data = new Object;
	setcodedefaultdata(data);
	var code = new Object;
	if (voucher == 1) {
		code.type = 12;
	}
	else {
		code.type = 4;
	}
	data.code = code;
	Jemplate.process('bizcode.tt2', data, '#codeShadow');
		customMsgCount(document.getElementById('custommessage'));
	$j("#codeShadow").fadeIn('slow');
	setupevents();
	disablefields("readonly");
	$j("#codefile").attr("disabled","disabled");
} 

function add_code(voucher) { 
	$j.post(baseUrl+'rest/code/-1', { random: 1, voucher: voucher }, function(data) {
		if (data.error) jsonError(data);
		setcodedefaultdata(data);
		//console.log(data);
		Jemplate.process('bizcode.tt2', data, '#codeShadow');
		customMsgCount(document.getElementById('custommessage'));
		$j("#codeShadow").fadeIn('slow');
		setupevents();
		
    }, "json" );
} 

function closePopup() { 
	//HideContent('contactShadow');
	if (editedField != null) {
		//alert("Saving field:" + editedField.name);
		changefield(editedField);
	}
	// wait up to 10s for save to complete
	if (saving > 0 && saving < 200) {
		//console.log("saving: " + saving);
		saving++;
		setTimeout("closePopup();", 50);
		return;
	}
	// check custom message length, warn if too long or empty
	var cmsgfield = document.getElementById('custommessage');
	if (cmsgfield) {
		var theVal = customMsgTextStart(cmsgfield);
		if (theVal == '') {
			alert("This code does not contain any information to send to your customers!\n\nIf you want to send a message, enter the SMS text and the optional URL that you would like sent to your customers, then click on the DONE button.\n\n");
			return;
		}
		// check for bad variable names
		var theMsg = customMsgSubVarLengths(theVal).replace(/[0-9\.]+ *%/g, '');
		var badvars = theMsg.match('%.*%');
		if (badvars) {
			var varconfirm=confirm("Are you sure you want to save - it looks like you may have a bad variable header name in this code?\n\nIs this text correct: " + badvars);	
			if (varconfirm == false) return (false);
		}
		var charCount = customMsgCountGet(cmsgfield);
		if (charCount > customMsgMax) {
			alert("Sorry, your SMS message is too long and will be clipped when sent. Please edit it down to " + customMsgMax + " characters.");
			return;
		}
	}
	//console.log("saving: " + saving);
	$j("#codeShadow").fadeOut('slow');
	ClearContent('codeLayer');
	window.location = window.location;
}

function cancelPopup() { 
	$j("#codeShadow").fadeOut('slow');
	ClearContent('codeLayer');
	window.location = window.location;
}

function view_code(id) { 
	$j.getJSON(baseUrl+'rest/code/'+id, function(data) {
		if (data.error) jsonError(data);
		setcodedefaultdata(data);
		Jemplate.process('bizcode.tt2', data, '#codeShadow');		
		customMsgCount(document.getElementById('custommessage'));
		$j("#codeShadow").fadeIn('slow');	
		setupevents();
		
    }, "json" );
} 

function bizcode_delete(id) { 
	var doit=confirm("Do you really want to delete this code?");
	if (doit== false) {
		return (false);
	}
	$j.delete_(baseUrl+'rest/code/'+id, function(data) {
		if (data.error) jsonError(data);
		$j("#codeShadow").fadeOut('slow');
		ClearContent('codeLayer');
		window.location = baseUrl + 'business/admin';
		
    }, "json" );
} 

function bizcode_custom() {
	var resDiv = document.getElementById("result_custom");
	resDiv.innerHTML = '&nbsp;';
	var theInput = document.getElementById("bizcode");
	var theCode = theInput.value;
	var origCode = document.getElementById("cardName").innerHTML;
	
	if (theCode == origCode) {
		alert("You haven't changed the code!");
		return false;
	}
	
	// checkcode : check for allowed characters etc
	var codeOK = checkcode(theCode);
	if (! codeOK) return false;
    
    if (theInput.name == 'code_code_') {
    	// this is a new code
		$j.post(baseUrl+'rest/code/-1', { code: theCode }, function(data) {
			if (data.error) {
				if (data.errortxt) alert(data.errortxt);
				if (data.errcode == 10002) {
					resDiv.innerHTML = '<span class="error">' + data.error + '</span>';
					return(false);
				}
				if (data.errcode == 10001) {
					// forward to login screen
					window.location = '/login';
					return(false);
				}
			}	
			data.maxfilesize = maxfileupload; // see ocodes.js and ocodes.yml config
			data.msgmax = customMsgMax;
			data.codemessage = 'Success, your new custom code is ready for editing.';
			Jemplate.process('bizcode_custom.tt2', data, '#codeShadow');
			customMsgCount(document.getElementById('custommessage'));
			setupevents();
		}, "json" );
	}
	else {
		// editing an existing code
		var codeid = theInput.name.replace(/.*_/,"");
		$j.put(baseUrl+'rest/code/'+codeid, { code: theCode }, function(data) {
			if (data.error) {
				if (data.errcode == 10002) {
					resDiv.innerHTML = '<span class="error">' + data.error + '</span>';
					return(false);
				}
				alert(data.errortxt);
				if (data.errcode == 10001) {
					// forward to login screen
					window.location = '/login';
					return(false);
				}
			}	
			data.maxfilesize = maxfileupload; // see ocodes.js and ocodes.yml config
			data.msgmax = customMsgMax;
			data.codemessage = 'Success, your custom code is changed and ready for editing.';
			Jemplate.process('bizcode_custom.tt2', data, '#codeShadow');
			setupevents();
		}, "json" );		
	}
} 


// todo - this is cut and pasted from above, could be made generic instead
function submitCodeForm(theAction) {
	// all other actions require that at least one checkbox be checked
	var checkSelected = false;
	var checkArray = document.codeForm.code;
	if (checkArray.length) {
		// there are multiple checkboxes
		for (i = 0;  i < checkArray.length;  i++) {
			if (checkArray[i].checked)
			checkSelected = true;
		}
	}
	else {
		// there is only one
		if (checkArray.checked)
		checkSelected = true;	
	}
	if (!checkSelected) {
		alert("You must select at least one code to " + theAction + ".");
		return (false);
	}
	if (theAction == "delete") {
		var doit=confirm("Do you really want to delete code(s)?");
		if (doit== false) {
			return (false);
		}
	}
	else if (theAction == "view") {
		//view_code(id);
		return (false);
	}
	else {
		alert("Sorry, this action is not enabled yet.");
		return (false);
	}
	document.codeForm.theAction.value = theAction;
	document.codeForm.submitted = true;
	document.codeForm.submit();
}

function startUpload(theForm, fileInput, fileDisp, toDisable){
	var theInput = document.getElementById(fileInput);
	if (theInput.value) {
		var tButton = document.getElementById(toDisable);
		tButton.className = "button_link WhiteOnGrey";
		tButton.disabled = true;
		
		var elem = document.getElementById(fileDisp);
		elem.innerHTML = '<img src="' + baseUrl + 'static/images/remembermilk_orange.gif" />';
				
		theForm.submitted = true;
		theForm.submit();
	}
	else {
		alert('You must choose a file first.');
	}
}

function stopUpload(message){
	document.getElementById('codefilename').innerHTML = message;
	var tButton = document.getElementById('customsubmit');
	tButton.className = "button_link WhiteOnGreen";
	tButton.disabled = false;
	return true;   
}

function codeRemoveFile(id) {
	$j.post(baseUrl+'business/fileremove', { codeid: id }, function(data) {
    }, "json" );	
	setTimeout("view_code("+id+");", 500);
}

function callPublish(msg, attachment, action_link) {
	FB.ensureInit(function () {
		FB.Connect.streamPublish(msg, attachment, action_link, null, 'Post to my wall:');
	});
}

function pubToFB(msg, file, url) {
	var attachment;
	var action_link;

	if (url && url != "") {
		action_link = [{ "text": "Go to link",
						"href": url
						}];
		msg = msg + String.fromCharCode(13) + url;
	}
	if (file && file != "") {
		var fileurl = baseUrl;
		fileurl = fileurl.replace(/\/$/, "") + file;
		attachment = {'media': [{'type':'image',
								'src': fileurl,
								'href': fileurl
								}]
							};
		//msg = msg + String.fromCharCode(13) + fileurl;
	}
	
	callPublish(msg, attachment, action_link);
}

function pubToFBbyID(id) {

	$j.getJSON(baseUrl+'rest/codefull/'+id, function(data) {
		if (data.error) jsonError(data);

		var attachment;
		var action_link = '';
		var code = data.code;
		var msg = code.message;
		
		if (code.url && code.url != "") {
			attachment = {	'name':			code.urlname,
							'href':			shortUrl + code.code,
							'caption':		shortUrl + code.code,
							'description':	code.urldesc
							};
			//msg = msg + String.fromCharCode(13) + code.url;
		}
		if (code.urlpath && code.urlpath != "") {
			var fileurl = baseUrl;
			fileurl = fileurl.replace(/\/$/, "") + code.urlpath;
			attachment['media'] = [{'type':'image',
									'src': fileurl,
									'href': fileurl
									}];
							
			//msg = msg + String.fromCharCode(13) + fileurl;
		}
		
		callPublish(msg, attachment, action_link);
		
	});

}

////////////////////////////////////////////////////////////////////////////
function displaymovie(whichmovie, whichdiv, titlediv) {
	var success = showmovie(whichmovie, whichdiv, titlediv);
	if (success) { $j("#moviecontainer").show(); }
	return success;
}

function closemovie(whichdiv) {
    //showmovie('stopmovie', whichdiv);
    var theSpan = document.getElementById(whichdiv);
	if (theSpan) {
		theSpan.innerHTML=' ';
	}
	$j("#moviecontainer").fadeOut('slow');
}

function showmovie(whichmovie, whichdiv, titlediv) {    
	
	var mWidth = 560;
	var mHeight = 325;
	var scURL = 'http://content.screencast.com/users/daveocodes/folders/Camtasia/media/';
	var defaultID = '2c04e724-ec4a-4476-9c55-6840b01e0b91';
	var mID;
	var mName;
    var tHTML;
	var mTitle;
	
	switch(whichmovie)
	{
	case 'intro':
	  mID = '2c04e724-ec4a-4476-9c55-6840b01e0b91';
	  mName = 'O-CODES%20Intro.mp4';
	  mTitle = 'O-CODES Introduction';
	  break;
	case 'editcard':
	  mID = '7bcb166d-7d84-4cb4-b026-ea482697a619';
	  mName = 'O-CODES%20Edit%20Your%20Card.mp4';
	  mTitle = 'O-CODES Edit Your Card';
	  break;
	case 'password':
	  mID = '9514af55-e7df-4054-817c-38acce719922';
	  mName = 'O-CODES%20Change%20Password.mp4';
	  mTitle = 'O-CODES Change Password';
	  break;
	case 'getcode':
	  mID = 'd52dc99c-6f74-4f91-a8ea-d1fd6bef6ad3';
	  mName = 'O-CODES%20Get%20A%20Code.mp4';
	  mTitle = 'O-CODES Get a Code';
	  break;
	case 'addcontact':
	  mID = '38b14af8-5d5b-454c-b649-fe57984d1cfd';
	  mName = 'O-CODES%20Add_Delete%20Contacts.mp4';
	  mTitle = 'O-CODES Add and Delete Contacts';
	  break;
	case 'navcontact':
	  mID = 'bd616fdf-dc64-43f8-95af-5b76b274092f';
	  mName = 'O-CODES%20Navigate%20Contacts.mp4';
	  mTitle = 'O-CODES Navigate Contacts';
	  break;
	case 'contact':
	  mID = 'b9962f90-45b5-490b-8dbc-b313955c8f90';
	  mName = 'O-CODES%20for%20sharing%20Contact%20Info.mp4';
	  mTitle = 'O-CODES for Sharing Contact Information';
	  break;
	case 'ads':
	  mID = 'a08edc07-d354-4c5b-b670-e46398628cb1';
	  mName = 'O-CODES%20in%20Advertising.mp4';
	  mTitle = 'O-CODES in Advertising';
	  break;
	case 'tv':
	  mID = 'ed24fcdd-3689-4e2c-aaab-67c959e8b636';
	  mName = 'O-CODES%20in%20TV.mp4';
	  mTitle = 'O-CODES in TV';
	  break;
	case 'property':
	  mID = 'c02e0fd0-5cf7-401f-93ea-6ec3aa0de77f';
	  mName = 'O-CODES%20in%20Real%20Estate.mp4';	  
	  mTitle = 'O-CODES in Real Estate';
	  break;
	case 'articles':
	  mID = 'ce99a661-d5cf-4735-8ed5-ff3ca58bab8d';
	  mName = 'O-Codes%20Interactive%20Magazines.mp4';	  
	  mTitle = 'O-CODES in Magazines and Newspapers';
	  break;
	case 'coupons':
	  mID = '5c3afd93-fb1f-4e49-8dca-40a926dec7b3';
	  mName = 'O-CODES%20in%20Coupons.mp4';
	  mTitle = 'O-CODES in Coupons';
	  break;
	case 'movies':
	  mID = 'd1243e84-d495-4228-944c-276ff573be28';
	  mName = 'O-CODES%20in%20Movie%20Promotion.mp4';
	  mTitle = 'O-CODES in Movie Promotion';
	  break;
	case 'recipes':
	  mID = '94358752-f163-4c03-9775-88c589a41ead';
	  mName = 'O-CODES%20used%20with%20Recipes.mp4';
	  mTitle = 'O-CODES and Recipes';
	  break;
	case 'museums':
	  mID = '7a1d128e-0695-44a9-a377-da0d1477dfbd';
	  mName = 'O-CODES%20in%20Museums.mp4';
	  mTitle = 'O-CODES in Museums';
	  break;
	case 'zoos':
	  mID = '1b51af6a-1ead-46f4-9c52-2b93384d01e3';
	  mName = 'O-CODES%20in%20Zoos%20and%20Parks.mp4';
	  mTitle = 'O-CODES in Zoos and Parks';
	  break;
	case 'catalogs':
	  mID = '3a69e4ba-5df2-4a3b-aafa-b11344741989';
	  mName = 'O-CODES%20in%20Catalogs.mp4';
	  mTitle = 'O-CODES in Catalogs';
	  break;
	case 'presentations':
	  mID = 'eb78c4d7-d3f6-4841-a99b-722de8bcc1a3';
	  mName = 'O-CODES%20in%20Presentations.mp4';
	  mTitle = 'O-CODES in Presentations';
	  break;
	case 'stopmovie':
	  mID = '';
	  mName = '';
	  break;
	default:
	  mID = '';
	  mName = '';
	}
	
	if (mID == '' && whichmovie != 'stopmovie') {
		alert('Sorry, this movie is not ready yet - please check back soon to view it!');
		return false;
	}
	
	if (mTitle && titlediv) {
	    var theDiv = document.getElementById(titlediv);
		if (theDiv) {
			theDiv.innerHTML=mTitle;
		}
	}
	
    if (DetectFlashVer(8, 0)){
		tHTML = '<object id="scPlayer" width="' + mWidth + '" height="' + mHeight + '"> <param name="movie" value="' + scURL + defaultID + '/mp4h264player.swf"></param> <param name="quality" value="high"></param> <param name="wmode" value="opaque"></param> <param name="bgcolor" value="#000000"></param> <param name="flashVars" value="thumb=' + scURL + mID + '/FirstFrame.jpg&containerwidth=' + mWidth + '&containerheight=' + mHeight + '&content=' + scURL + mID + '/' + mName + '"></param> <param name="allowFullScreen" value="true"></param> <param name="scale" value="showall"></param> <param name="allowScriptAccess" value="always"></param> <param name="base" value="' + scURL + mID + '/"></param> <embed src="' + scURL + defaultID + '/mp4h264player.swf" quality="high" bgcolor="#000000" width="' + mWidth + '" height="' + mHeight + '" type="application/x-shockwave-flash" allowScriptAccess="always" flashVars="thumb=' + scURL + mID + '/FirstFrame.jpg&containerwidth=' + mWidth + '&containerheight=' + mHeight + '&content=' + scURL + mID + '/' + mName + '" allowFullScreen="true" base="' + scURL + mID + '/" scale="showall"></embed> </object>';
	}
	else {
		tHTML = '<video width="' + mWidth + '" height="' + mHeight + '" poster="' + scURL + mID + '/FirstFrame.jpg" controls>';
		tHTML = tHTML + '<source src="' + scURL + mID + '/' + mName + '" type="video/mp4">';
		tHTML = tHTML + '<div style="margin:10px;" class="orange"><p>You need Adobe Flash installed and JavaScript enabled to view this movie.</p><a href="http://get.adobe.com/flashplayer/">Download Flash Player from Adobe</a></div>';
		tHTML = tHTML + '</video>';
	}
    var theSpan = document.getElementById(whichdiv);
	if (theSpan) {
		theSpan.innerHTML=tHTML;
		var myVideo = document.getElementsByTagName('video')[0];
		if (myVideo) {
			// and handler to display Flash download message if the <video> tag fails to play
			myVideo.addEventListener('error',errorFallback,true);
		}
	}
	    
    return true;
}

function errorFallback(evt) {
	//alert("fallback");
	var tHTML = '<div style="margin:10px;" class="orange"><p>You need Adobe Flash installed and JavaScript enabled to view this movie.</p><a href="http://get.adobe.com/flashplayer/">Download Flash Player from Adobe</a></div>';
	this.parentNode.innerHTML=tHTML;
}

// <span class="shortcode" onclick="displaydialog();">[% c.config.SMS.ourshortcode %]</span>
function displaydialog(whichmovie, whichdiv) {
	var data;
	Jemplate.process('hoverpopup_fr.tt2', data, '#dialogpopup');
	$j("#dialogcontainer").show( function() {
        // Animation complete
    });
}

function closedialog(whichmovie, whichdiv) {
    var theSpan = document.getElementById(whichdiv);
	if (theSpan) {
		theSpan.innerHTML=' ';
	}
	$j("#dialogcontainer").fadeOut('slow');
}

///////////////////////////////////////////////////////////////////////////////
function showhover(hoverpopup, e) {
	hp = document.getElementById(hoverpopup);
	
	cursor = getPosition(e);
	hp.style.top = cursor.y + 5 + "px";
	hp.style.left = cursor.x + 5 + "px";
	
	// Set popup to visible
	hp.style.visibility = "visible";
}

function hidehover(hoverpopup) {
	hp = document.getElementById(hoverpopup);
	hp.style.visibility = "hidden";
}

function getPosition(e) {
    e = e || window.event;
    var cursor = {x:0, y:0};
    if (e.pageX || e.pageY) {
        cursor.x = e.pageX;
        cursor.y = e.pageY;
    } 
    else {
        var de = document.documentElement;
        var b = document.body;
        cursor.x = e.clientX + 
            (de.scrollLeft || b.scrollLeft) - (de.clientLeft || 0);
        cursor.y = e.clientY + 
            (de.scrollTop || b.scrollTop) - (de.clientTop || 0);
    }
    return cursor;
}
function mouseX(evt) {
if (evt.pageX) return evt.pageX;
else if (evt.clientX)
   return evt.clientX + (document.documentElement.scrollLeft ?
   document.documentElement.scrollLeft :
   document.body.scrollLeft);
else return null;
}
function mouseY(evt) {
if (evt.pageY) return evt.pageY;
else if (evt.clientY)
   return evt.clientY + (document.documentElement.scrollTop ?
   document.documentElement.scrollTop :
   document.body.scrollTop);
else return null;
}

///////////////////////////////////////////////////////////////////////////////
// todo - this is cut and pasted from above, could be made generic instead
function add_report() {
	alert("Sorry, this action is not enabled yet.");
	return (false);
}

function submitReportForm(theAction) {
	// all other actions require that at least one checkbox be checked
	var checkSelected = false;
	var checkArray = document.reportForm.code;
	if (! checkArray) {
		return (false);
	}
	if (checkArray.length) {
		// there are multiple checkboxes
		for (i = 0;  i < checkArray.length;  i++) {
			if (checkArray[i].checked)
			checkSelected = true;
		}
	}
	else {
		// there is only one
		if (checkArray.checked)
		checkSelected = true;	
	}
	if (!checkSelected) {
		alert("You must select at least one report to " + theAction + ".");
		return (false);
	}
	/*
	if (theAction == "delete") {
		var doit=confirm("Do you really want to report code(s)?");
		if (doit== false) {
			return (false);
		}
	}
	else if (theAction == "view") {
		//view_code(id);
		return (false);
	}
	else {
	*/
		alert("Sorry, this action is not enabled yet.");
		return (false);
	//}
	document.codeForm.theAction.value = theAction;
	document.codeForm.submitted = true;
	document.codeForm.submit();
}

function report_code(id, page) {
	if (! page) {
		page = 1;
	}
	$j.getJSON(baseUrl+'business/codereport/'+id+'?json=1&page='+page, function(data) {
		if (data.error) jsonError(data);
		data.funcname = 'report_code';
		data.funcparams = id;
		Jemplate.process('codereport.tt2', data, '#codeShadow');
		
		// format the date fields
		formatDates("td.jsdate2");

		//$j("#codeShadow").width('700px');	
		$j("#codeShadow").fadeIn('slow');	
		
    }, "json" );
} 

function close_report_code() { 
	$j("#codeShadow").fadeOut('slow');
	ClearContent('codeLayer');
}

function optin(control, type, email) {
	if (control.checked) {
		if (type == 'email') {
			if (email) {
				changefield(control);
			}
			else {
				alert('You do not currently have an email address associated with your account. Please enter one in your contact card on the Home page before opting in to offers by email.');
				control.checked = false;
				return false;
			}
		}
		else {
			var answer = confirm('Please make sure you can accept MMS, and be aware that this may incur extra charges on your phone bill?')
			if (answer){
				changefield(control);
			}
			else{
				control.checked = false;
				return false;
			}
	
		}
	}
	else {
		changefield(control);	
	}
}

function offerSelect(all) {

    var theSpan = document.getElementById('offercount');
	if (! theSpan) {
		return;
	}
	
	var idArray = $j('.offchk:checked').map(function () {
		return $j(this).val();
	});
	
	var idList = $j.makeArray(idArray).join(',');
	//alert(all + " : " + idList);
	
	if (idList == '') {
		theSpan.innerHTML = '0';
		return;
	}
	
	if (all == 'all') {
		idList = 'all';
	}
	
	$j.getJSON(baseUrl+'offers/offer_select?idList='+idList, function(data) {
		if (data.error) jsonError(data);
		theSpan.innerHTML = data.offercount;		
    }, "json" );

	return;
}

function offerCreate(type, group, checkBoxClass) {
	var idArray = getSelected(checkBoxClass, 'many', group);
	if (! idArray) return false;
	var idList = $j.makeArray(idArray).join(',');	

	var all = 0;
	var allArray = $j('.' + checkBoxClass).map(function () {
		return $j(this).val();
	});
	var allList = $j.makeArray(allArray).join(',');	
	if (idList == allList) {
		all = 1;
	}
	
	if (type == "mobile") {
		$j.post(baseUrl+'rest/smsoffer/-1', { 'idlist': idList, 'all': all, 'code': group }, function(data) {
			if (data.error) jsonError(data);
			data.smsoffer.sendathour = '12';
			data.smsoffer.is_new = '1';
			var templateName;
			//if (group == 'group') {
			//	templateName = 'sms_alert.tt2';
			//} else {
				templateName = 'sms_offer.tt2';
			//}
			Jemplate.process(templateName, data, '#codeShadow');
			customMsgCount(document.getElementById('custommessage'));
			var d=new Date();
			$j('#alerttz').html( d.getTimezoneName() );
			$j("#codeShadow").fadeIn('slow');
			setupevents();
			$j('#sendatDate').datepicker({ minDate: new Date(), dateFormat: gDateformat.replace('yyyy', 'yy'), onSelect: function(dateText, inst) { updateSendat(); } });
			
			// "headers":{"1":["first name",6],"4":["time",5],"0":["id",1],"3":["date",10],"2":["last name",5],"5":["location",8]}
			//subPatterns = new Object;			
			//for (var header in data.smsoffer.headers) {
			//	for(var prop in header) {
			//		var tArray = header.prop;
			//		subPatterns.tArray[0] = tArray[1];
			//	}
			//}
		
		}, "json" );
		
	}
	else if (type == "email") {
		alert("Sorry, this action is not enabled yet.");
		return (false);
	}
}

function offerCreateSingle(type, group) {	
	if (type == "mobile") {
		$j.post(baseUrl+'rest/smsoffer/-1', { 'idlist': 0, 'all': 0, 'code': group }, function(data) {
			if (data.error) jsonError(data);
			data.smsoffer.sendathour = '12';
			data.smsoffer.is_new = '1';
			Jemplate.process('sms_offer_single.tt2', data, '#codeShadow');
			customMsgCount(document.getElementById('custommessage'));
			var d=new Date();
			$j('#alerttz').html( d.getTimezoneName() );
			$j("#codeShadow").fadeIn('slow');
			setupevents();
			$j('#sendatDate').datepicker({ minDate: new Date(), dateFormat: gDateformat.replace('yyyy', 'yy'), onSelect: function(dateText, inst) { updateSendat(); } });		
		}, "json" );
		
	}
	else if (type == "email") {
		alert("Sorry, this action is not enabled yet.");
		return (false);
	}
}

function smsofferView(id) {
	$j.getJSON(baseUrl+'rest/smsoffer/'+id, function(data) {
		if (data.error) jsonError(data);
		
		if (data.smsoffer.sendat) {
			theDate = o2s.parseDate(data.smsoffer.sendat, 'yyyy-mm-dd HH:ii:ss');
			theDate = correctOffset(theDate, 0);
			data.smsoffer.sendat = o2s.format(theDate, 'yyyy-mm-dd HH:ii:ss');
			data.smsoffer.sendathour = data.smsoffer.sendat.replace(/.* ([0-9]*):.*/gi, "$1");
		}
		
		var tJemplate = 'sms_offer.tt2';
		if (data.smsoffer.phonegroup == 2) tJemplate = 'sms_offer_single.tt2';
		Jemplate.process(tJemplate, data, '#codeShadow');
		customMsgCount(document.getElementById('custommessage'));
		$j("#codeShadow").fadeIn('slow');
		setupevents();

		if(data.smsoffer.is_editable) {
			$j('#sendatDate').dateFormat(gDateformat);
			$j('#sendatDate').datepicker({ minDate: new Date(), dateFormat: gDateformat.replace('yyyy', 'yy'), onSelect: function(dateText, inst) { updateSendat(); } });
		}
		else {
			$j('#sendatDate').dateFormat(gDateformat + ' h:ii:ss a');
			disablefields("disabled");		
		}
	}, "json" );
}

function smsofferSave(id, theRadioId, theMsgId, offerOrAlert) {
	// first check for blank msg, refuse save if so
	var cmsgfield = document.getElementById(theMsgId);
	var theMsg = customMsgTextStart(cmsgfield);
	if (theMsg == '') {
		alert("This " + offerOrAlert + " does not contain any information to send to your customers!\n\nIf you want to send a message, enter the SMS text and the optional URL that you would like sent to your customers, then click on the DONE button.\n\nTip: Make sure that what you send is something valuable for your customers, otherwise a large number of them may opt out of your " + offerOrAlert + "s list!");
		return (false);
	}
	// check for bad variable names
	theMsg = customMsgSubVarLengths(theMsg).replace(/[0-9\.]+ *%/g, '');
	var badvars = theMsg.match('%.*%');
	if (badvars) {
		var varconfirm=confirm("Are you sure you want to save - it looks like you may have a bad variable header name in this " + offerOrAlert + "?\n\nIs this text correct: " + badvars);	
		if (varconfirm == false) return (false);
	}
	
	// check custom message length, warn if too long
	var charCount = customMsgCountGet(cmsgfield);
	if (charCount > customMsgMax) {
		alert("Sorry, your SMS message is too long (" + charCount + " characters) and will be clipped when sent. Please edit it down to " + customMsgMax + " characters.");
		return (false);
	}

	var theRadio = document.getElementById(theRadioId);
	var doit;
	var sendit = 1;
	if (theRadio.checked) {
		doit=confirm("Do you want to save and send this " + offerOrAlert + " now?");
		sendit = 2;
	}
	else {
		var tDate = updateSendat();
		if (! tDate) {
			alert("Please fill in the date and time for this " + offerOrAlert + ".");
			return false;
		}
		doit=confirm("Do you want to save and send this " + offerOrAlert + " later?");	
	}
	if (doit == false) return (false);
	
	$j.put(baseUrl+'rest/smsoffer/'+id, { sent: sendit }, function(data) {
		if (data.error) jsonError(data);
		$j("#codeShadow").fadeOut('slow');
		ClearContent('codeLayer');
		window.location = window.location;
		
    }, "json" );
}

function smsofferDelete(id, cancelOrDelete, offerOrAlert) { 
	var doit=confirm("Do you really want to " + cancelOrDelete + " this " + offerOrAlert + "?");
	if (doit== false) {
		return (false);
	}
	$j.delete_(baseUrl+'rest/smsoffer/'+id, function(data) {
		if (data.error) jsonError(data);
		$j("#codeShadow").fadeOut('slow');
		ClearContent('codeLayer');
		window.location = window.location;
		
    }, "json" );
}

function smsofferDeleteGroup(checkBoxClass, offerOrAlert) {
	var idArray = getSelected(checkBoxClass, "many", offerOrAlert);
	if (! idArray) return false;
	
	var msg = "Do you really want to delete ";
	if (idArray.length == 1) {
		msg = msg + "this " + offerOrAlert + "?";
	}
	else {
		msg = msg + "these " + offerOrAlert + "s?";
	}		
	var doit=confirm(msg);
	if (doit== false) {
		return (false);
	}

	var idList = $j.makeArray(idArray).join(',');
	$j.delete_(baseUrl+'rest/smsoffer/'+idList, function(data) {
		if (data.error) jsonError(data);
		$j("#codeShadow").fadeOut('slow');
		ClearContent('codeLayer');
		window.location = window.location;
		
    }, "json" );
}

function updateSendat() {
	var dateField = document.getElementById('sendatDate');
	if (! dateField) return;

	saving = 1;
	var tDate = dateField.value;
	var tTime;
	
	var timeField = document.getElementById('sendatTime');
	if(timeField) {
		tTime = timeField.value;
		// try to parse date
		var theDate = o2s.parseDate(tDate + ' ' + tTime, gDateformat + ' H:ii:ss');
	}
	else {
		var hourField = document.getElementById('sendatHour');
		var minField = document.getElementById('sendatMin');
		var amField = document.getElementById('sendatAm');
		var tzField = document.getElementById('sendatTZ');
		
		if ((! hourField) || (! minField) || (! amField) || (! hourField.value) || (! minField.value)) {
			return;
		}
		
		tTime = hourField.value + ':' + minField.value + ':00 ' + amField.value;
		// try to parse date
		var theDate = o2s.parseDate(tDate + ' ' + tTime, gDateformat + ' h:ii:ss a');
	}

	//alert(tDate + ' ' + tTime);

	if (theDate == null) {
		alert("Sorry, I couldn't understand that date and time, please try again.");
		return false;
	}
	theDate = correctOffset(theDate, 1);
	tDate = o2s.format(theDate, 'yyyy-mm-dd HH:ii:ss');
	
	$j.put( baseUrl+'rest/field/'+dateField.name+'_', { name: dateField.name, val: tDate }, function(data){
		if (data.error) jsonError(data);
		$j("#autosave").fadeOut('slow');
		saving = 0;		
	}, "json" );
	
	return tDate;
}

function insertvar(theSpan) {
	var tTxt = $j(theSpan).html();
	var fieldID = $j(theSpan).attr('rel');
	var tField = document.getElementById(fieldID);
	insertAtCursor(tField, tTxt);
	customMsgCount(tField);
	changefield(tField);
}

function insertAtCursor(myField, myValue) {
	//IE support
	if (document.selection) {
		myField.focus();
		sel = document.selection.createRange();
		sel.text = myValue;
	}
	//MOZILLA/NETSCAPE support
	else if (myField.selectionStart || myField.selectionStart == '0') {
		var startPos = myField.selectionStart;
		var endPos = myField.selectionEnd;
		myField.value = myField.value.substring(0, startPos)
		+ myValue
		+ myField.value.substring(endPos, myField.value.length);
	} else {
		myField.value += myValue;
	}
}

Date.prototype.stdTimezoneOffset = function() {
	var jan = new Date(this.getFullYear(), 0, 1);
	var jul = new Date(this.getFullYear(), 6, 1);
	return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
}

Date.prototype.dst = function() {
	if ( this.getTimezoneOffset() < this.stdTimezoneOffset() ) return 1;
	return 0;
}

Date.prototype.getTimezoneName = function() {
	var gmtHours = -this.getTimezoneOffset()/60;
	var dst = this.dst();
	// US
	if (gmtHours == -10 && dst == 0) return "Hawaiian";
	if ((gmtHours == -8 && dst == 0) || (gmtHours == -7 && dst == 1)) return "Pacific";
	if ((gmtHours == -7 && dst == 0) || (gmtHours == -6 && dst == 1)) return "Mountain";
	if ((gmtHours == -6 && dst == 0) || (gmtHours == -5 && dst == 1)) return "Central";
	if ((gmtHours == -5 && dst == 0) || (gmtHours == -4 && dst == 1)) return "Eastern";
	
	// UK
	if (gmtHours == 0 && dst == 0) return "GMT";
	if (gmtHours == 1 && dst == 1) return "BST";
	
	// Other
	return "GMT " + gmtHours;
}

function correctOffset(theDate, direction) {
	var d=new Date();
	var gmtMins = d.getTimezoneOffset();
	if (direction) {
		return o2s.dateAdd("i", gmtMins + gServerOffset, theDate);
	}
	else {
		return o2s.dateAdd("i", -gmtMins - gServerOffset, theDate);
	}
}

// format the date fields and make them display in local timezone
function formatDates(theSelector) {
	var d=new Date();
	var gmtMins = -d.getTimezoneOffset() - gServerOffset;		
	var tStr;
	var newdate;
	
	$j(theSelector).each( function() {
		tStr = $j(this).html();
		if(tStr) {
		newdate = o2s.dateAdd("i", gmtMins, tStr);
		tStr = o2s.format(newdate, gDateTimeformat);
		$j(this).html(tStr);
		}
	});
}

// format the date fields and make them display in local timezone, no time (date only)
function formatDatesOnly(theSelector) {
	var d=new Date();
	var gmtMins = -d.getTimezoneOffset() - gServerOffset;		
	var tStr;
	var newdate;
	
	$j(theSelector).each( function() {
		tStr = $j(this).html();
		if(tStr) {
		newdate = o2s.dateAdd("i", gmtMins, tStr);
		tStr = o2s.format(newdate, gDateformat);
		$j(this).html(tStr);
		}
	});
}

// format a number as a currency amount
function formatCurrency(num) {
	num = num.toString().replace(/\$|\,/g,'');
	if (isNaN(num)) num = "0";
	sign = (num == (num = Math.abs(num)));
	num = Math.floor(num*100+0.50000000001);
	cents = num%100;
	num = Math.floor(num/100).toString();
	if (cents<10) cents = "0" + cents;
	num = thousandSep(num);
	return (((sign)?'':'-') + '$' + num + '.' + cents);
}

function thousandSep(num) {
	num = num.toString();
	for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
		num = num.substring(0,num.length-(4*i+3))+','+num.substring(num.length-(4*i+3));
	return num;
}

///////////////////////////////////////////////////////////////////////////////
// phone list stuff
function offerGroupSelect(all) {

    var theSpan = document.getElementById('offergroupcount');
	if (! theSpan) {
		return;
	}
	
	var idArray = $j('.offgroupchk:checked').map(function () {
		return $j(this).val();
	});
	
	var idList = $j.makeArray(idArray).join(',');
	//alert(all + " : " + idList);
	
	if (idList == '') {
		theSpan.innerHTML = '0';
		return;
	}
	
	if (all == 'all') {
		idList = 'all';
	}
	
	//$j.getJSON(baseUrl+'offers/offer_select?idList='+idList, function(data) {
	//	if (data.error) jsonError(data);
	//	theSpan.innerHTML = data.offercount;		
    //}, "json" );

	return;
}

function offerImportGroup() {
	var data = new Object;
	data.maxfilesize = maxfileupload; // see ocodes.js and ocodes.yml config
	Jemplate.process('phonegroup_import.tt2', data, '#codeShadow');
	$j("#codeShadow").fadeIn('slow');

	// place a mask but let selected elements show through (expose)
	// TODO doesn't work - maybe a a z-index problem?
	//$j("#codeShadow").expose();

}

function offerEditGroupButton(checkBoxClass) {
	var idArray = getSelected(checkBoxClass, "one", "group");
	if (! idArray) return false;
	offerEditGroup(idArray[0]);	
}

function offerEditGroup(groupid) {
	$j.getJSON(baseUrl+'rest/phonegroup/'+groupid, function(data) {
		if (data.error) jsonError(data);
		data.maxfilesize = maxfileupload; // see ocodes.js and ocodes.yml config
		Jemplate.process('phonegroup_import.tt2', data, '#codeShadow');
		$j("#codeShadow").fadeIn('slow');
	}, "json");
}

function offerExportGroup(checkBoxClass) {
	var idArray = getSelected(checkBoxClass, "many", "group");
	if (! idArray) return false;
	var idList = $j.makeArray(idArray).join(',');
	window.location = baseUrl+'offers/export/'+idList;
}

function offerDeleteGroup(checkBoxClass) {
	var idArray = getSelected(checkBoxClass, "many", "group");
	if (! idArray) return false;
	
	var msg = "Do you really want to delete ";
	if (idArray.length == 1) {
		msg = msg + "this phone group?";
	}
	else {
		msg = msg + "these phone groups?";
	}		
	var doit=confirm(msg);
	if (doit== false) {
		return (false);
	}

	var idList = $j.makeArray(idArray).join(',');	
	$j.delete_(baseUrl+'rest/phonegroup/'+idList, function(data) {
		if (data.error) jsonError(data);
		window.location = window.location;		
    }, "json" );
}

// get a list of checkboxes which are selected
function getSelected(checkBoxClass, howMany, thingName) {
	var selector = '.' + checkBoxClass + ':checked';
	var idArray = $j(selector).map(function () {
		return $j(this).val();
	});
	
	// always want at least one selected - so error if none
	if (idArray.length == 0) {
		if (howMany == "one") {
			alert("Please choose one " + thingName + '!');
		} 
		else {
			alert("Please choose at least one " + thingName + '!');
		} 
		return false;
	}
	
	// if we want one, error if many
	if (howMany == "one" && idArray.length > 1) {
		alert("Please choose one " + thingName + " - you have " + idArray.length + " selected.");
		return false;
	} 

	return idArray;
}

///////////////////////////////////////////////////////////////////////////////
// Concierge stuff

var cT;
var cL;

// refresh the table
function conciergeList(page, saveScroll) {
	if (! page) {
		page = 1;
	}
	$j.getJSON(baseUrl+'concierge?json=1&page='+page, function(data) {
		if (data.error) jsonError(data);
		
		// restart the count down
		if (cL) clearTimeout(cL);
		cL = setTimeout('conciergeList('+page+', 1);', 30000);

		// attempt to keep the table more or less static in view, by
		// keeping us the same scroll distance from the BOTTOM of the table.
		// that way if new stuff comes to the top, it won't push the table down.
		// doesn't work so well if people below where we are viewing text again,
		// as they will then jump to the top. also, if a person you are interacting
		// with texts, they will also jump to the top.
		var scrollBot = -1;
		if (saveScroll) {
			var scrollWhich = 'div';
			var theTable = document.getElementById("contactsTableBody");
			var theDiv = document.getElementById("contacts");
			if (theDiv.scrollTop < 5 && theTable.scrollTop < 5) {
				scrollBot = -1;
			} else if (theDiv.scrollTop >= 5) {
				scrollBot = theDiv.scrollHeight - theDiv.scrollTop;
			} else {
				scrollBot = theTable.scrollHeight - theTable.scrollTop;
				scrollWhich = 'table';
			}
			//alert(scrollVal);
		}
		
		Jemplate.process('concierge_table.tt2', data, '#conciergeWrapper');
		tableResize(tableOffset);
		var theTable = document.getElementById("contactsTableBody");
		var theDiv = document.getElementById("contacts");
		if (scrollBot > -1) {
			if (scrollWhich == 'table') {
				theTable.scrollTop = theTable.scrollHeight - scrollBot;
			} else {
				theDiv.scrollTop = theDiv.scrollHeight - scrollBot;
			}
		}
		
		// format the date fields
		formatDates("td.jsdate");
    }, "json" );
}

// display the IM window
function conciergeIM(id, phone, refresh) {
	$j.getJSON(baseUrl+'concierge/history/'+id+'/'+phone+'/'+refresh, function(data) {
		if (data.error) jsonError(data);
		
		if (refresh) {
			$j('#refreshicon').html('<img src="' + baseUrl + 'static/images/remembermilk_orange.gif" />');
			Jemplate.process('concierge_im_msgs.tt2', data, '#msglist');
			setTimeout('$j("#refreshicon").html("")', 1000);
		} else {
			$j("#codeShadow").fadeIn('slow');
			Jemplate.process('concierge_im.tt2', data, '#codeShadow');
		}
		
		// format the date fields
		formatDates("div.jsdate");
		
		// add event to count chars in msg field
		$j("#custommessage").keyup( function (event) {
			keyupfield(this, event.keyCode);
		});
		
		// refresh every 30s
		function timeoutFunc() {
			conciergeIM(id, phone, 1);
		}
		if (cT) clearTimeout(cT);
		cT = setTimeout(timeoutFunc, 30000);
    }, "json" );
}

// close the IM window
function conciergeCancel(msg) {
	if (msg && msg.length > 0) {
		var doit=confirm("Do you really want to close without sending?");
		if (doit== false) {
			return (false);
		}
	}
	clearTimeout(cT);
	$j("#codeShadow").fadeOut('slow');
	//conciergeList();
}

// send an SMS
function conciergeSendSMS(id, number, msg) {
	if (msg.length == 0) {
		alert("You must enter a message to send!");
		return false;
	}
	
	$j("#sendsms").attr("disabled","disabled");
	$j("#addnote").attr("disabled","disabled");

	$j.post(baseUrl+'concierge/send/', { content: msg, phone: number }, function(data) {
		if (data.error) {
			jsonError(data);
			$j("#sendsms").attr("disabled","");
			$j("#addnote").attr("disabled","");
		}
		else {
			//$j("#codeShadow").fadeOut('slow');
			//window.location = window.location;
			conciergeIM(id, number, 0);
		}
    }, "json" );

}

// add a note
function conciergeAddNote(id, number, msg) {
	if (msg.length == 0) {
		alert("You must enter a note to save!");
		return false;
	}

	$j("#sendsms").attr("disabled","disabled");
	$j("#addnote").attr("disabled","disabled");

	$j.post(baseUrl+'concierge/note/', { content: msg, phone: number }, function(data) {
		if (data.error) {
			jsonError(data);
		}
		else {
			//$j("#codeShadow").fadeOut('slow');
			//window.location = window.location;
			conciergeIM(id, number, 0);
		}
    }, "json" );
}

///////////////////////////////////////////////////////////////////////////////
function selectText(element) {
    var text = document.getElementById(element);
    if ($j.browser.msie) {
        var range = document.body.createTextRange();
        range.moveToElementText(text);
        range.select();
    } else if ($j.browser.mozilla || $j.browser.opera) {
        var selection = window.getSelection();
        var range = document.createRange();
        range.selectNodeContents(text);
        selection.removeAllRanges();
        selection.addRange(range);
    } else if ($j.browser.safari) {
        var selection = window.getSelection();
        selection.setBaseAndExtent(text, 0, text, 1);
    }
}


///////////////////////////////////////////////////////////////////////////////
// handle errors, especially not-logged in response to JSON request
function jsonError(data) {
	alert(data.errortxt);
	if (data.errcode == 10001) {
		// forward to login screen
		window.location = '/login';
		return(false);
	}
}


///////////////////////////////////////////////////////////////////////////////
// form handling functions, to replace those in forms.js
// used to add default text, and filter it out when form is submitted
function formDefaultInit() {
    var formInputs = $j('input.cleardefault');
    formInputs.each(function() {
    	if ($j(this).val() == '') $j(this).val( $j(this).attr('defaulttext') );
		formAddEvent(this, 'focus', formDefaultClear, false);
		formAddEvent(this, 'blur', formDefaultReplace, false);
    });
}

function formAddEvent(element, eventType, lamdaFunction, useCapture) {
    if (element.addEventListener) {
        element.addEventListener(eventType, lamdaFunction, useCapture);
        return true;
    } else if (element.attachEvent) {
        var r = element.attachEvent('on' + eventType, lamdaFunction);
        return r;
    } else {
        return false;
    }
}

function formDefaultClear(e) {
    var target = window.event ? window.event.srcElement : e ? e.target : null;
    if (!target) return;
    
    target.style.color='black';
    if (target.value == $j(target).attr('defaulttext')) {
        target.value = '';
    }
}

function formDefaultReplace(e) {
    var target = window.event ? window.event.srcElement : e ? e.target : null;
    if (!target) return;
    
    if (target.value == '' && $j(target).attr('defaulttext')) {
        target.value = $j(target).attr('defaulttext');
        target.style.color='lightgrey';
    }
}

function formDefaultFilter() {
    var formInputs = $j('input.cleardefault');
    formInputs.each(function() {
    	if ($j(this).val() == $j(this).attr('defaulttext')) $j(this).val('');
    });
}


