/**
 * @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, autocompleteArray) {
	//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);
 		if (typeof autocompleteArray != 'undefined') {
			setTimeout("saveEditor('edit-" + id + "')", 200); //the small delay is necessary to enable the autocomplete selection to take effect
		}
		else {
			saveEditor('edit-' + id);
		}
	});
	editor.focus();
	editor.select();

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

	//attach any autocomplete array data to the editor (using the jQueryUi autocomplete widget)
//alert(typeof autocompleteArray)
	if (typeof autocompleteArray == 'object' && autocompleteArray.length) {
		editor.autocomplete({
			source: autocompleteArray
		});
	}
}







///////////////////// 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);
	});
	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);
	}

	quitEditor(id);
}



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);
			}
			break;
		case 9:		//TAB - used in combination with tabindexes
log('keydown', id+' <- TAB');
			event.preventDefault();
			saveEditor(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 radio button value to the database (the id of the enclosing form encodes the database table/id info)
function saveRadioButton(element) {
	if (typeof pageId == 'undefined') {var pageId=0;}
	element = jQuery(element);
	var value = element.val()
	var id = element.parents('form').attr('id');
	Post.Send('id='+id+'&pageId='+pageId+'&value='+value, base_url+'dataserver/ajaxSaveField');
	displayResult('#'+id+'-result');
}




//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');
	}
}


//saves the user/group/membership setting via ajax
function saveGroupMembership(element) {
	var id = element.id;
	var isMember = (element.checked) ? 1 : 0;
	Post.Send('id='+id+'&isMember='+isMember, base_url+'dataserver/ajaxGroupMembership');
}



//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(element) {
    if (typeof element != 'object') {
        alert('error: saveDropdown(element) not passed an element object');
        return;
    }
    element = jQuery(element);
    var value = element.val().myEncode();
    var id = element.attr('name');

	Post.Send('id='+id+'&pageId='+pageId+'&value='+value, base_url+'dataserver/ajaxSaveField');
	displayResult('#'+id+'-result');
}








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



//the callback function (optional) enables the use of a custom delete function (eg. for the dhtmlx tree delete fn)
function removeContent(id, redirectUrl, callback) {
	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 'contract_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 'ci_groups':
			confirmMessage = 'Are you sure you want to delete the selected Group?';
			break;

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

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


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

	//create the dialog placeholder
	if (jQuery('#confirmDialog').length == 0) {
		jQuery('body').append('<div id="confirmDialog" style="display:none" title="Please Confirm"><p>' + confirmMessage + '</p></div>');
	} else {
		jQuery('#confirmDialog').html('<p>' + confirmMessage + '</p>');
	}

	jQuery("#confirmDialog").dialog({
		resizable: false,
		modal: true,
		buttons: {
			'Confirm': function() {
				jQuery(this).dialog('close');

				//delete row from database (id encodes the table-rowId information)
				if (typeof callback == 'undefined') {
					Post.Send('id=' + id + '&pageId=' + pageId + ((redirectUrl) ? '&redirectUrl=' + redirectUrl : ''), base_url + 'dataserver/ajaxDeleteRow');
				} else {
					if (typeof callback != 'function') {
						alert('System error: the callback function specified is not a function');
					} else {
						callback();
					}
				}
			},
			'Cancel': function() {
				jQuery(this).dialog('close');
			}
		}
	});
}



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


function dispatchNewsletter(){
	jQuery('#ajaxNotifyResult').html('<blink class="error">Processing. Please wait...</blink>');
	jQuery('.preSend').css('display', 'none');
	jQuery('.postSend').css('display', 'inline');

	var notifyGroup = jQuery('[name=notifyGroup]').val();
	var subject = jQuery('#subject').val();

	Post.Send('notifyGroup=' + notifyGroup + '&subject=' + subject, base_url + 'dataserver/ajaxSendNewsletter');
}


function adminPasswordReset(user, title) {
	if (typeof user == 'undefined' || !user.length) {
		alert('System error: the user was not specified');
	}

	if (typeof title == 'undefined') {
		title = 'Confirm Password Reset';
	}

	//create the save dialog placeholder
	if (jQuery('#confirmPasswordResetDialog').length == 0) {
		jQuery('body').append('<div id="confirmPasswordResetDialog" style="display:none" title="' + title + '"><p>Would you like to generate a new password for this user and send them their new login details?</p></div>');
	}

	jQuery("#confirmPasswordResetDialog").dialog({
		resizable: false,
		modal: true,
		buttons: {
			'Confirm': function() {
				jQuery(this).dialog('close');

				Post.Send('user=' + user, base_url + 'login/resetPassword');
			},
			'Cancel': function() {
				jQuery(this).dialog('close');
			}
		}
	});
}




function submitInvoice(id){

	busyStart();

	if (jQuery('#submitInvoice').length == 0) {
		jQuery('body').append('<div id="submitInvoice" title="Confirm Invoice Submittal"></div>');
	}

	//load the specified url content via ajax call into the dialog placeholder
	jQuery('#submitInvoice').load(base_url+'subconsulting/submitInvoice/'+id, function(){
		jQuery("#submitInvoice").dialog({
			resizable: true,
			width: 'auto',
			modal: true,
			buttons: {
				'Submit Invoice': function() {
					jQuery(this).dialog('close');

					//compile a list of selected email recipients
					var recipientIds = '';
					jQuery('input.recipients:checked').each(function() {
					    if (recipientIds.length) {
							recipientIds += ','
						}
						recipientIds += jQuery(this).val();
					});

					var message = encodeURIComponent(jQuery('#submitInvoiceIntro').html()+jQuery('#submitInvoiceNotes').val());
					var subject = jQuery('#submitInvoiceSubject').text();
					Post.Send('id=invoiceSubmitted-'+id+'&value=1&recipientIds='+recipientIds+'&subject='+subject+'&message='+message, base_url+'dataserver/ajaxSaveField');
				},
				'Cancel': function() {
					jQuery(this).dialog('close');
				}
			}
		});

		busyStop();
	});

}






function approveInvoice(id) {
	busyStart();

	if (jQuery('#approveInvoice').length == 0) {
		jQuery('body').append('<div id="approveInvoice" title="Confirm Invoice Approval"></div>');
	}

	//load the specified url content via ajax call into the dialog placeholder
	jQuery('#approveInvoice').load(base_url+'subconsulting/approveInvoice/'+id, function() {
		jQuery("#approveInvoice").dialog({
			resizable: true,
			width: 'auto',
			modal: true,
			buttons: {
				'Approve Invoice': function() {
					jQuery(this).dialog('close');

					//compile a list of selected email recipients
					var recipientIds = '';
					jQuery('input.recipients:checked').each(function() {
					    if (recipientIds.length) {
							recipientIds += ','
						}
						recipientIds += jQuery(this).val();
					});

					var message = encodeURIComponent(jQuery('#approveInvoiceIntro').html()+jQuery('#approveInvoiceNotes').val());
					var subject = jQuery('#approveInvoiceSubject').text();
					Post.Send('id=invoiceApprovedByLeader-'+id+'&value=1&recipientIds='+recipientIds+'&subject='+subject+'&message='+message, base_url+'dataserver/ajaxSaveField');
				},
				'Cancel': function() {
					jQuery(this).dialog('close');
				}
			}
		});

		busyStop();
	});
}





function rejectInvoice(id) {

	busyStart();

	if (jQuery('#rejectInvoice').length == 0) {
		jQuery('body').append('<div id="rejectInvoice" title="Confirm Invoice Rejection"></div>');
	}

	//load the specified url content via ajax call into the dialog placeholder
	jQuery('#rejectInvoice').load(base_url+'subconsulting/rejectInvoice/'+id, function() {
		jQuery("#rejectInvoice").dialog({
			resizable: true,
			width: 'auto',
			modal: true,
			buttons: {
				'Reject Invoice': function() {
					jQuery(this).dialog('close');

					//compile a list of selected email recipients
					var recipientIds = '';
					jQuery('input.recipients:checked').each(function() {
					    if (recipientIds.length) {
							recipientIds += ','
						}
						recipientIds += jQuery(this).val();
					});

					var message = encodeURIComponent(jQuery('#rejectInvoiceIntro').html()+jQuery('#rejectInvoiceReason').val());
					var subject = jQuery('#rejectInvoiceSubject').text();
					Post.Send('id=invoiceRejected-'+id+'&value=1&recipientIds='+recipientIds+'&subject='+subject+'&message='+message, base_url+'dataserver/ajaxSaveField');
				},
				'Cancel': function() {
					jQuery(this).dialog('close');
				}
			}
		});

		busyStop();
	});

}





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


//this function uses the ajaxSaveField server-side function to create a new row - the element id contains the row information
function newRow(element) {
	switch (typeof element) {
		case 'string':
			var id = element;
			break;

		case 'object':
			var id = jQuery(element).attr('id');
			break;

		default:
			alert('a system error occurred');
	}

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


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(project) {
	if (typeof project == 'undefined') {
		Post.Send('id=contract-0', base_url+'dataserver/ajaxSaveField');
	} else {
		Post.Send('id=contractProject-0&value='+project, 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, ' '));
}


