/**
 * @author Andrew Masri */



//var jsDebug = true;

///////////////////// In-place ajax input text editor (single-line) //////////////////////////////////////////////////////////

//convert any element into an in-place editor (using 'input' form field)
function editText(id) {
	//if id is an element object convert it to an id attribute
	if (typeof id == 'object') {
		var source = jQuery(id);
		id = source.attr('id');
	} else {
		var source = jQuery('#'+id);
	}

	//wrap the source element in a div and then hide it (this enables us to retain the 'display' style of the source element)
	source.wrap('<span class="editorWrapper"></span>');
	source.wrap('<div class="editorWrapper" style="display:none"></div>');
	
	//append editable input element after the hidden div
	source.parent().parent().append('<input id="edit-'+id+'" type="text"/>');
	
	var editor = jQuery('#edit-'+id);
	
	//setup the input element's attributes
	editor.addClass(source.attr('class')+' '+source[0].nodeName.toLowerCase()+' '+'inPlaceEditor');

	//initial value of input element
 	var initialValue = source.html();
	initialValue = initialValue.replace(/&amp;/g, '&');
	initialValue = initialValue.split('<')[0];	//remove any html tags (eg. Draft blog marker) 
	initialValue = jQuery.trim(initialValue);
	switch (initialValue.toLowerCase()) {
		case 'edit':
		case 'click to edit':
		case 'none':
		case 'empty':
		case '___':
		case '---':
		case '':
			editor.val('');	//these values mean that there is no value yet
			break;
		default:
			editor.val(initialValue);	//convert '&' html entity to text 
	}
	editor.data('initialValue', editor.val());	//record the initial value - later we'll use this to determine whether the text is modified
log('edit', id+' : '+initialValue);

	//copy the style settings from the source element to the input element 
	editor.css('backgroundColor', 'transparent');
	editor.css('color', source.css('color'));
	editor.css('textAlign', source.css('textAlign'));
	editor.css('fontSize', source.css('fontSize'));
	if (!jQuery.browser.webkit) { editor.css('border', '3px solid #679ed9'); }
	editor.css('margin-top', source.css('margin-top'));
	editor.css('margin-left', source.css('margin-left'));
	editor.css('margin-right', source.css('margin-right'));
	editor.css('margin-bottom', source.css('margin-bottom'));
	editor.css('font-weight', source.css('font-weight'));
	editor.css('display', source.css('display'));
	editor.attr('size', (editor.val().length < 7) ? 7 :  editor.val().length); 	//size of input field in chars


	//setup the input element's event handlers
	editor.bind('blur', function() {
log('lostFocus', id);
 		saveEditor('edit-'+id);
 		quitEditor('edit-'+id);
	});
	editor.focus();
	editor.select();

	//handle return/esc/tab keystrokes 
	editor.keydown(function(event) {
	  	detectKey(event, 'edit-'+id);
	});
}







///////////////////// In-place ajax textarea editor (multi-line) //////////////////////////////////////////////////////////


//convert any element into an in-place editor (using 'textarea' form field)
function editTextArea(id) {

	//if id is an element object convert it to an id attribute
	if (typeof id == 'object') {
		var source = jQuery(id);
		id = source.attr('id');
	} else {
		var source = jQuery('#'+id);
	}
	
	//wrap the source element in a div and then hide it (this enables us to retain the 'display' style of the source element)
	source.wrap('<span class="editorWrapper"></span>');
	source.wrap('<div class="editorWrapper" style="display:none"></div>');
	
	//append editable input element after the hidden div
	source.parent().parent().append('<textarea id="edit-'+id+'"></textarea>');
	
	var editor = jQuery('#edit-'+id);
	
	//setup the input element's attributes
	editor.addClass(source.attr('class')+' '+source[0].nodeName.toLowerCase()+' '+'inPlaceEditor');

	//initial value of input element
	var initialValue = source.html();
	initialValue = initialValue.replace(/<br>|<br \/>|<br\/>/gi, '\r');	//remove html line breaks - \r seems to work in firefox and ie
	initialValue = initialValue.replace(/&amp;/g, '&');	//convert '&' html entity to text
	initialValue = jQuery.trim(initialValue);	//record the initial value - later we'll use this to determine whether the text is modified
	switch (initialValue.toLowerCase()) {
		case 'edit':
		case 'click to edit':
		case 'click here to comment...':
		case 'none':
		case 'empty':
		case '':
			editor.text('');	//these values mean that there is no value yet
			break;
		default:
			editor.text(initialValue);	
	}
	editor.data('initialValue', editor.text());	//record the initial value - later we'll use this to determine whether the text is modified 

	
	//copy the style settings from the source element to the input element 
	editor.css('background-color', source.css('background-color'));
	editor.css('font-family', source.css('font-family'));
	editor.css('font-weight', source.css('font-weight'));
	editor.css('color', source.css('color'));
	editor.css('textAlign', source.css('textAlign'));
	editor.css('line-height', source.css('line-height'));
	if (!jQuery.browser.webkit) { editor.css('border', '3px solid #679ed9'); }
	editor.css('fontSize', source.css('fontSize'));
	editor.css('margin-top', source.css('margin-top'));
	editor.css('margin-left', source.css('margin-left'));
	editor.css('margin-right', source.css('margin-right'));
	editor.css('margin-bottom', source.css('margin-bottom'));
	editor.css('display', 'inline');
	editor.css('width', (source.css('width') == 'undefined') ? '100%' : source.css('width'));
	editor.css('min-height', '44px');


	//set height of textarea based on content
	if (editor.css('height') == 'auto') {
		editor.css('height', '44px');	//force height to be something numeric for auto height to work
	}
	while ((parseInt(editor.css('height').replace(/px|em/i, '')) < editor[0].scrollHeight)) {
		editor.css('height', editor[0].scrollHeight + 20 +'px') //expand textarea to eliminate vertical scrollbar
	}


	//setup the input element's event handlers
	editor.bind('blur', function() {
log('lostFocus', id);
 		saveEditor('edit-'+id);
 		quitEditor('edit-'+id);
	});
	editor.focus();
	editor.select();

	//handle return/esc/tab keystrokes 
	editor.keydown(function(event) {
	  	detectKey(event, 'edit-'+id);
	});
}




function saveEditor(id){
	var editor = jQuery('#'+id);
	if (!editor.length) {
		return;	//the editor has already been destroyed	
	}
	
	var sourceId = id.replace(/edit-/, '');
	var editedValue = jQuery.trim(editor.val());
	
	//retrieve initialValue (differs between browsers due to newline implementations) 
	var initialValue = editor.data('initialValue');
	initialValue = initialValue.replace(/\r\n/gi, '\n'); 
	initialValue = initialValue.replace(/\r/gi, '\n');
	
	if (editedValue != initialValue) {
		initialValue = editedValue; //prevent multiple save requests
		editedValue = editedValue.myEncode();
		Post.Send('id='+sourceId+'&pageId='+pageId+'&value='+editedValue, base_url+'dataserver/ajaxSaveField');
log('saved', id+' --> '+editedValue);
	}
	return;
}		



function quitEditor(id){
	jQuery('#'+id).unbind('keydown');	//stop tracking keyboard shortcuts
		
	var editor = jQuery('#'+id);
	if (editor.length) {
		editor.remove(); //remove the editor
		//remove the hidden div from around the source element in order to reveal the source element
		var sourceId = id.replace(/edit-/, '');
		var source = jQuery('#' + sourceId);
	
		while (source.parent().hasClass('editorWrapper')) {
			source.unwrap(); //remove the hidden div wrapper and span container tags
		}
log('removed', id);
	}
}		



//called by in-place editors when a key is pressed
function detectKey(event, id) {
	var character = (event.which) ? event.which : event.keyCode;

	var editor = jQuery('#'+id);
	if (!editor.length) {
		return;	//the editor getting the keydown event doesn't exist anymore 
	}

	var elementType = editor[0].nodeName.toLowerCase();
	
	//vertical auto-grow (textarea only)
	if ((elementType == 'textarea') && (parseInt(editor.css('height').replace(/px|em/i, '')) != editor[0].scrollHeight)) {
		editor.css('height', editor[0].scrollHeight + 20 +'px') //expand textarea to eliminate vertical scrollbar
	}

	//horizontal auto-grow (input field only)
	if ((elementType == 'input') && (editor.attr('size') < editor.val().length )) {
		editor.attr('size', editor.val().length); 	//size of input field in chars
	}


	switch (character) {
		case 13:	//RETURN
			//in a textarea field <RETURN> is treated as a line break character rather than a save command
			if (elementType != 'textarea') {
log('keydown', id+' <- RETURN');
				event.preventDefault();
				saveEditor(id);
				quitEditor(id);
			}
			break;
		case 9:		//TAB - used in combination with tabindexes
log('keydown', id+' <- TAB');
			event.preventDefault();			
			saveEditor(id);
			quitEditor(id);
			nextTabIndex(id);
			break;
		case 27:	//ESCAPE (note that Safari does not provide the ESC key and firefox uses char 0 which seem to conflict with the delete key)
log('keydown', id+' <- ESCAPE');
			event.preventDefault();			
			quitEditor(id);	//discard the editor and return to normal display
			break;
		default:
			break;
	}
	return false;
}



//open the next tabIndex field for editing
function nextTabIndex(id) {
	var sourceId = id.replace(/edit-/, '');
	var source = jQuery('#'+sourceId);	//the field that has just been tabbed from 
	var tabIndexes = jQuery('[tabindex]');	//list of all tabIndexes
	var foundThisTabIndex = false;
	
	if ((source.attr('tabindex').indexOf('undefined') == -1) && tabIndexes.length > 1) {
		tabIndexes.each(function() {
			if (foundThisTabIndex && jQuery(this).attr('tabindex').indexOf('undefined') == -1) {
				editText(jQuery(this));
				foundThisTabIndex = false;
				return;
			}

			if (jQuery(this).attr('id') == sourceId) {
				foundThisTabIndex = true;					//we found the field we just tabbed from in the list of tabIndexes - edit the next tabIndex
			}
		});
	} 
}



//////////////////////// Checkbox handler ////////////////////////////////////////////////////////////////////////

//save the checkbox value to the database (the id of the checkbox encodes the database table/id info)
function saveCheckbox(element) {
	var id = element.id;
	var value = (element.checked) ? 1 : 0;
	Post.Send('id='+id+'&pageId='+pageId+'&value='+value, base_url+'dataserver/ajaxSaveField');
	displayResult('#'+id+'-result');
	
	//are there duplicate checkboxes (whose class == this id) - their state must also be changed
	jQuery('.'+id).attr('checked', element.checked);
	 
	//is there a child element that should be revealed hidden based on the checkbox value 
	if (value) {
		jQuery('.childOf-'+id).fadeIn('slow');
	} else { 
		jQuery('.childOf-'+id).fadeOut('slow');	
	}
																						 		
}

//this function shouldn't be necessary because child elements should be hidden in php
//this function hides child elements of any parent elements that are not checked 
jQuery(document).ready(function() {
	jQuery('input:checkbox:not(:checked)').each(function() {
		jQuery('.childOf-'+this.id).css('display', 'none');	
	});
});



//////////////////////// Dropdown handler ////////////////////////////////////////////////////////////////////////

//save the selected value to the database (the id of the checkbox encodes the database table/id info)
function saveDropdown(name) {
	var value = document.getElementsByName(name)[0].value;
	Post.Send('id='+name+'&pageId='+pageId+'&value='+value, base_url+'dataserver/ajaxSaveField');
	displayResult('#'+name+'-result');
}








//////////////////////// content add/remove button handlers ////////////////////////////////////////////////////////////////////////


function removeContent(id, redirectUrl) {
	table = id.split("-"); 
	table = table[0];

	switch (table) {
		case 'blogcategories':
			confirmMessage = 'Are you sure you want to delete this Category?  It could result in some blog articles having no category!';
			break;
						
		case 'pages':
			confirmMessage = 'Are you sure you want to delete this page?  You will lose any content on the page!';
			break;

		case 'project':
			confirmMessage = 'Are you sure you want to delete this Project?';
			break;

		case 'contacts':
			confirmMessage = 'Are you sure you want to delete that Contact?';
			break;

		case 'contracts':
			confirmMessage = '<p>Are you sure you want to delete this Agreement?</p><p>Any associated Invoices will also be deleted permanently - including those already submitted for payment!</p>';
			break;

		case 'contract_projects':
			confirmMessage = '<p>Are you sure you want to delete this Project?</p><p>Any associated Agreements and Invoices will also be deleted permanently!</p>';
			break;

		case 'contract_phases':
			confirmMessage = '<p>Are you sure you want to delete this Stage?</p><p>The Stage will also be deleted permanently from any associated invoices - including those already submitted for payment!</p>';
			break;

		case 'invoices':
			confirmMessage = 'Are you sure you want to delete this Invoice?';
			break;

		case 'images':
			confirmMessage = 'Are you sure you want to delete the selected image?';
			break;


		case 'content':
		default:
			confirmMessage = 'Are you sure you want to permanently delete the selected page content?';
	}


	//create the save dialog placeholder
	jQuery('body').append('<div id="confirmDialog" title="Please Confirm"><p>'+confirmMessage+'</p></div>');
	
	jQuery("#confirmDialog").dialog({
		resizable: false,
		modal: true,
		buttons: {
			'Confirm': function() {
				jQuery(this).dialog('close');
				jQuery('#confirmDialog').remove();
				//delete row from database (id encodes the table-rowId information)
				Post.Send('id='+id+'&pageId='+pageId+((redirectUrl) ? '&redirectUrl='+redirectUrl : ''), base_url+'dataserver/ajaxDeleteRow');			
			},
			'Cancel': function() {
				jQuery(this).dialog('close');
				jQuery('#confirmDialog').remove();
			}
		}
	});
}		



function removeComment(id) {
	Post.Send('id='+id+'&pageId='+pageId, base_url+'dataserver/ajaxDeleteRow');
}





function submitInvoice(id, invoiceNumber) {

	jQuery('.invoiceNumberPlaceholder').text(invoiceNumber);	//populate the invoice number field

	jQuery("#submitInvoice").dialog({
		resizable: true,
		width: 'auto',
		modal: true,
		buttons: {
			'Submit Invoice': function() {
				jQuery(this).dialog('close');
				var message = encodeURIComponent(jQuery('#submitInvoiceIntro').html()+jQuery('#submitInvoiceNotes').val());
				var subject = jQuery('#submitInvoiceSubject').text();
				var recipientIds = jQuery('#submitInvoiceRecipientIds').text();
				Post.Send('id=invoiceSubmitted-'+id+'&value=1&recipientIds='+recipientIds+'&subject='+subject+'&message='+message, base_url+'dataserver/ajaxSaveField');
			},
			'Cancel': function() {
				jQuery(this).dialog('close');
			}
		}
	});	
}






function approveInvoice(id, invoiceNumber) {

	jQuery('.invoiceNumberPlaceholder').text(invoiceNumber);	//populate the invoice number field

	jQuery("#approveInvoice").dialog({
		resizable: true,
		width: 'auto',
		modal: true,
		buttons: {
			'Approve Invoice': function() {
				jQuery(this).dialog('close');
				var message = encodeURIComponent(jQuery('#approveInvoiceIntro').html()+jQuery('#approveInvoiceNotes').val());
				var subject = jQuery('#approveInvoiceSubject').text();
				var recipientIds = jQuery('#approveInvoiceRecipientIds').text();
				Post.Send('id=invoiceApprovedByLeader-'+id+'&value=1&recipientIds='+recipientIds+'&subject='+subject+'&message='+message, base_url+'dataserver/ajaxSaveField');
			},
			'Cancel': function() {
				jQuery(this).dialog('close');
			}
		}
	});	
}





function rejectInvoice(id, invoiceNumber){
	
	jQuery('.invoiceNumberPlaceholder').text(invoiceNumber);	//populate the invoice number field
	
	jQuery("#rejectInvoice").dialog({
		resizable: true,
		width: 'auto',
		modal: true,
		buttons: {
			'Reject Invoice': function() {
				jQuery(this).dialog('close');
				var message = encodeURIComponent(jQuery('#rejectInvoiceIntro').html()+jQuery('#rejectInvoiceReason').val());
				var subject = jQuery('#rejectInvoiceSubject').text();
				var recipientIds = jQuery('#rejectInvoiceRecipientIds').text();
				Post.Send('id=invoiceSubmitted-'+id+'&value=0&recipientIds='+recipientIds+'&subject='+subject+'&message='+message, base_url+'dataserver/ajaxSaveField');
			},
			'Cancel': function() {
				jQuery(this).dialog('close');
			}
		}
	});	
}


function addContent(pageRef, title, redirectUrl) {
	Post.Send('pageRef='+pageRef+'&title='+title+'&pageId='+pageId+'&redirectUrl='+encodeURIComponent(redirectUrl), base_url+'dataserver/ajaxInsertContent');
}		



function newBlogCategory() {
	Post.Send('id=blogCategory-0&value=New Category', base_url+'dataserver/ajaxSaveField');
}		



function newBlogArticle(redirectUrl) {
	var dataset = 'dataset[parentId]=0&dataset[title]=New%20Blog%20Article&dataset[pageType]=blog&dataset[display]=0';
	Post.Send(dataset+'&redirectUrl='+redirectUrl, base_url+'dataserver/insertPage');
	displayResult('#server-result');
}		



function newProject(redirectUrl) {
	var dataset = 'dataset[parentId]=0&dataset[title]=New%20Project&dataset[pageType]=portfolio&dataset[display]=1';
	Post.Send(dataset+'&redirectUrl='+redirectUrl, base_url+'dataserver/insertPage');
	displayResult('#server-result');
}		

//subcontracting system ajax handlers
function newContract() {
	Post.Send('id=contract-0', base_url+'dataserver/ajaxSaveField');
}		

function newContractProject() {
	Post.Send('id=subcontractingProject-0', base_url+'dataserver/ajaxSaveField');
}


function newInvoice(contractId) {
	Post.Send('id=invoice-0&pageId='+contractId, base_url+'dataserver/ajaxSaveField');
}		

function newContractPhase(contractId) {
	Post.Send('id=contractPhase-0&pageId='+contractId, base_url+'dataserver/ajaxSaveField');
}		

//Confirm dialog popup (for example when user hits the delete button) 
 function confirmation(message, url) {
	if (confirm(message)) {
		window.open(url, '_self');
	}
}



//ajax email message handler
function sendMessage(fromEmail, recipientIds, subject, message, ccMyself, fromName, successMessage) {
	if (fromName == undefined) {fromName='';}
	if (successMessage == undefined) {successMessage='';}
	ccMyself = (ccMyself) ? 1 : 0;
	Post.Send('fromEmail='+fromEmail+'&fromName='+fromName+'&recipientIds='+recipientIds+'&subject='+subject+'&message='+message+'&ccMyself='+ccMyself+'&random='+Math.random()*10000+'&successMessage='+successMessage, base_url+'dataserver/sendEmailMessage');
}



//this function is compatible with php's rawurldecode (use this instead of encodeURIComponent)
String.prototype.myEncode = function() {
	return encodeURIComponent(this);
}

//this function is compatible with php's urlencode (use this instead of decodeURIComponent)
String.prototype.myDecode = function() {
	return decodeURIComponent(this.replace(/\%2526/g, '&').replace(/\%2520/g, ' ').replace(/\%252520/g, ' '));
}


