var datePattern = /^\d{4}-\d{1,2}-\d{1,2}$/; //http://www.the-art-of-web.com/javascript/validate-date/
var docItem = null;

function ignoreEnterOnField(fieldId)
{
	//ignore this function if the enter key is pressed in the textarea field for typing:
	var ae = document.activeElement;
	var ta = document.getElementById(fieldId);
	return (ae == ta)
}

function prependZeros(cnt, val)
{
	"use strict";
	var len = val.toString().length; //e.g. count = 3, number = 10
	var d = cnt - len; //e.g. 3 - 2, d = 1
	var x, r = val;
	for (x = 1; x <= d; x++) {r = '0'+r;}
	return r;
}

function handleEnter(inField, e)
{
	"use strict";
	if (e !== undefined)
	{
		if (parseInt(e.which) === 13) 
		{ 
			//enter pressed 
			if (document.getElementById('btnOk')!==null) {document.getElementById('btnOk').click();}
		}	
	}
}

$(document).keypress(function(e){handleEnter(null, e)});

function isValidEmail(email) 
{ 
    var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
}

const numberWithCommas = (x) => 
{
  var parts = x.toString().split(".");
  parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  return parts.join(".");
}

function pad(num, size) 
{
    var s = num+"";
    while (s.length < size) s = "0" + s;
    return s;
}

const numberAsCurrency = (x) =>
{
	var val = Math.round(Number(x) * 100) / 100;
	var parts = val.toString().split(".");
	if (parts.length > 1)
	{
		var dec = parts[1].length < 2 ? parts[1]+'0' : parts[1];
	}
	return 'R'+parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + (parts[1] ? "." + dec : "");
}

function showHint(id){document.getElementById('hint_'+id).style.visibility = 'visible';}
function hideHint(id)
{
	"use strict";
	var fld = document.getElementById(id);
	var obj = document.getElementById("hint_"+id);
	var ph = (fld) ? fld.getAttribute('placeholder') : '';
	obj.style.visibility = 'visible';
	obj.innerHTML = ph;
	obj.classList.remove('error');
	obj.classList.remove('success');	
}

function isNumber(n){return !isNaN(parseFloat(n)) && isFinite(n);}
function isWholeNumber(n){return n%1==0;}

function isValidPhoneNumber(value){return (/^\d{7,}$/).test(value.replace(/[\s()+\-\.]|ext/gi, ''));}

function toTitleCase(str){return str.replace(/\w*\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});}

function scrollIntoViewIfNeeded(target) 
{
	"use strict";
	if (target !== null)
	{
		var rect = target.getBoundingClientRect();
		if (rect.bottom > window.innerHeight) {
			target.scrollIntoView(false);
		}
		if (rect.top < 0) {
			target.scrollIntoView();
		}
	}
}

function handleError(id, errorMessage)
{
	/*
	var err;
	//document.getElementById(id).focus();
	eval('document.getElementById("row_' + id + '").style.display = "table-row"');
	eval('document.getElementById("error_' + id + '").innerHTML = "' + errorMessage + '"');
	*/
	obj = document.getElementById("hint_"+id);
	if (obj !== null)
	{
		//obj.className = "error";
		obj.classList.remove('success');
		obj.classList.add('error');		
		obj.style.display = "visible";
		//glyphicon-warning-sign
		obj.innerHTML = '<i class="fa fa-exclamation-triangle" aria-hidden="true"></i>&nbsp;'+errorMessage;
		showHint(id);	
		scrollIntoViewIfNeeded(document.getElementById(id));
	} else alert(errorMessage);
	/*
	eval('document.getElementById("hint_' + id + '").className = "error"');
	eval('document.getElementById("hint_' + id + '").innerHTML = "' + errorMessage + '"');*/	
}

function handleSuccess(id, successMessage)
{
	/*
	var err;
	//document.getElementById(id).focus();
	eval('document.getElementById("row_' + id + '").style.display = "table-row"');
	eval('document.getElementById("error_' + id + '").innerHTML = "' + errorMessage + '"');
	*/
	obj = document.getElementById("hint_"+id);
	if (obj!=null)
	{
		obj.classList.remove('error');
		obj.classList.add('success');
		//obj.className = "success";
		obj.style.display = "visible";
		//glyphicon-warning-sign
		obj.innerHTML = '<i class="fa fa-check" aria-hidden="true"></i>&nbsp;'+successMessage;
		showHint(id);	
	} else alert(successMessage);
	/*
	eval('document.getElementById("hint_' + id + '").className = "error"');
	eval('document.getElementById("hint_' + id + '").innerHTML = "' + errorMessage + '"');*/	
}

function clearError(id)
{
	"use strict";
	var obj = document.getElementById("hint_"+id);
	if (obj !== null)
	{
		obj.classList.remove('success');
		obj.classList.remove('error');
		/*
		Use the placeholder attribute to restore the description of the hint. In some cases (like with the select tag)
		a placeholder attribute is not used, but we add it anyway to be able to get the hint:
		*/
		var phObj = document.getElementById(id);
		var ph = phObj === null ? '' : document.getElementById(id).getAttribute('placeholder');
		obj.innerHTML = '<i class="fa fa-check" aria-hidden="true"></i>&nbsp;'+ph;
	}
}

//** export table ** //
function exportQuery(title, sql)
{
	"use strict";
	var aflaai;
	var queryName = prompt("Please enter a name for this report", title);
	aflaai= window.open("../list/export.php?" + queryName + "+"+sql, "export" , "location=0, menubar=0, scrollbars=0, status=0, titlebar=0, toolbar=0, directories=0, resizable=1, width=200, height=240, top=50, left=250");
	aflaai.resizeTo(1, 1);
	aflaai.moveTo(1, 1);
	aflaai.onblur = function() {aflaai.close();};
	alert('The data was successfully downloaded.');
}

//** export table ** //
function exportDataTable(table)
{
  aflaai= window.open("../list/export.php?" + table, "export" , "location=0, menubar=0, scrollbars=0, status=0, titlebar=0, toolbar=0, directories=0, resizable=1, width=200, height=240, top=50, left=250");
  aflaai.resizeTo(1, 1);
  aflaai.moveTo(1, 1);
  aflaai.onblur = function() {aflaai.close();};
  alert('The data was successfully downloaded.');
}

//** upload File ** //
function fileUpload(field, displayField, fileType, multi)
{
	"use strict";
	var upload= window.open(baseRootURL+"upload/upload.php?" + field + "+" + displayField + "+" + fileType + "+" + multi, "upload" , "location=0, menubar=0, scrollbars=0, status=0, titlebar=0, toolbar=0, directories=0, resizable=1, width=800, height=600, top=50, left=250");
	if (upload) 
	{
		upload.resizeTo(800, 800);
		upload.moveTo(350, 75);
	}
}

function getFileExtension1(filename) 
{
  return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename)[0] : undefined;
}

function prepImages(imageField, images, labelField)
{
	//Let's first remove any images already in the list. what we upload now overwrites what's there;	
	var startAtZero = document.getElementsByClassName('imageUploaded') == null;
	var deleteExisting = true;
	var elm=[], obj, lbl, canDelete = true;
	var tst = document.getElementsByName(imageField);
	var imgField = document.getElementsByName(imageField)[0];
	var flext;
	if (window.opener === null)
	{
		if (imgField === null)
		{
			lbl = {};
			lbl.value = '0';
			deleteExisting = false;
			obj = document.createElement("div"); //container for the images.
		}
		else		
		{
			if (document.getElementById('imgDiv0')===null)
			{
				obj = imgField.parentNode;
				elm = document.getElementsByName(imageField);
				lbl = document.getElementById(labelField);
			}
			else
			{
				obj = document.getElementById('imgDiv0').parentNode;
				elm = document.getElementsByClassName('imageUploaded');
				lbl = document.getElementById(labelField);
			}
		}
	}
	else
	{
		var doc = opener.document !== null ? opener.document : window.opener.document;
		var imgf = doc.getElementById(imageField);
		if (imgf === null)
		{
			//this is where images should be appended rather than be replaced!
			deleteExisting = false;
			obj = doc.getElementById('imgDiv0').parentNode;
			elm = doc.getElementsByClassName('imageUploaded');
			lbl = doc.getElementById(labelField);			
		}
		else
		{
			obj = doc.getElementById(imageField).parentNode;
			elm = doc.getElementsByName(imageField);
			lbl = doc.getElementById(labelField);
		}
	}

	var l = 0;
	if (deleteExisting)
	{
		var idx;
		var strt = startAtZero?0:1;
		while(elm.length >= strt)
		{		
			idx = (elm.length - 1);
			elm[idx].parentNode.removeChild(elm[idx]);
			//elm = window.opener.document.getElementsByName(imageField);
		}
	} 
	else l = elm.length; //since we're appending images, start the index after the existing pics.
	
	//now add the images
	var imgDiv, orderDiv, closeDiv, imgNode;
	//img.src = value[0];
	var sz = images.length;
	lbl.value = (sz+l)+' files uploaded.';
	for (var x=0; x<sz; x++)
	{
		flext = getFileExtension1(images[x]);
		imgDiv=document.createElement("div");
		imgDiv.setAttribute('name', 	'imgContainer[]');
		imgDiv.setAttribute('id', 		'imgDiv'+(x+l));
		imgDiv.setAttribute('class',	'col-md-2 imageUploaded ');
		imgDiv.setAttribute('sable-doc',images[x]);
		
		switch(flext)
		{
			case('jpg'):
			case('heif'):
			case('webp'):
			case('png'):
			case('gif'):
			case('jpeg'):
			{
				imgDiv.setAttribute('style', 'background-image:url(\''+images[x]+'\');');
				break;
			}

			//other
			default:
			{
				imgDiv.setAttribute('style', 'background-image:url(\'/media/images/filetypes/'+flext+'.png\');');
			}
		}
		
		//imgDiv.setAttribute('innerHTML',	flext);
		obj.appendChild(imgDiv);	
		
		/*
		imgNode = document.createElement("img");
		imgNode.setAttribute('height',	'100%');
		imgNode.setAttribute('width', 	'100%');		
		imgNode.setAttribute('name', 	imageField);
		imgNode.setAttribute('id', 		'imgNode'+(x+l));
		imgNode.setAttribute('src', 	images[x]); //NOTE --> NOT (x+l)!!
		imgDiv.appendChild(imgNode);
		*/

		closeDiv=document.createElement("div");
		closeDiv.setAttribute('class', 		'imageCloseDiv');	
		closeDiv.setAttribute('name', 		'closeDiv'+(x+l));
		closeDiv.setAttribute('id', 		'closeDiv'+(x+l));
		closeDiv.setAttribute('onclick',	'removeImageElement(this.parentNode, imgDiv'+(x+l)+', "'+labelField+'")');
		closeDiv.innerHTML = '<h3><i class="fa fa-times-circle"></i></h3>';
		imgDiv.appendChild(closeDiv);		

		orderDiv=document.createElement("div");
		orderDiv.setAttribute('class', 		'imageOrderDiv');	
		orderDiv.setAttribute('name', 		'orderDiv'+(x+l));
		orderDiv.setAttribute('id', 		'orderDiv'+(x+l));
		orderDiv.setAttribute('onclick',	'checkItemOrder('+(x+l)+')');
		orderDiv.innerHTML = '<h3>'+(((x+l)+1)*1)+'</h3>';
		imgDiv.appendChild(orderDiv);						
	}

	if (document.getElementById(imageField)!==null) 
	{
		var img = document.getElementById(imageField);
		img.parentNode.removeChild(img);
	}
}

function prepDocs(documentField, files, labelField)
{
	"use strict";
	var doc = window.opener===null?document:window.opener.document;
	//properties
	//console.log('files = '+files);
	this.fileCount = files.length;
	this.colWidth = 6;
	this.balanceWidth = 6;
	this.containerName = labelField+'_container';
	this.readonly = false;
	
	//methods
	this.setReadonly = function(readonly)
	{
		this.readonly = readonly;
	}
	
	this.showData = function()
	{
		//wDebug(doc);
		doc.getElementById(labelField).innerHTML = this.fileCount+' files uploaded.';
		//console.log(this.fileCount+' files uploaded. -->'+labelField);
		var html = '';
		for(var i=0; i < this.fileCount; i++){html += this.buildElement(i);}
		doc.getElementById(this.containerName).innerHTML = html;
	}
	
	this.buildElement = function(index)
	{
		//build the HTML:
		var url = files[index];
		var shortname = url.substring(url.lastIndexOf('/')+1);
		var style = this.readonly ? ' style=background:#eee;"" ' : '';
		var html = '';
//		html  = '   <p></p>';
//		html += '    <div class="container">';
		html += '      <div class="row forms-grids">';
		html += '    		<div class="col-md-'+this.colWidth+' forms-grid">';
		html += '        		<div class="list-item">';
		html += '          			<div class="list-item-main"'+style+'>';
		html += ' 						<a href="'+files[index]+'" download target="_blank" title="'+files[index]+'" id="uploaded_doc_'+index+'">';
		html += '						<i class="fa fa-download" aria-hidden="true"></i>&nbsp;'+shortname+'</a>';
		
		if (!this.readonly)
		{
		html += '      					<div class="list-item-action" name="uploaded_file" id="uploaded_file_'+index+'" title="'+files[index]+'">';

		html += '        					<i onClick="removeFileElement(\''+index+'\',\''+documentField+'\',\''+labelField+'\')" class="fa fa-times pointer" style="color:#d10a11" aria-hidden="true" ';
		html += '							title="Remove '+files[index]+'"></i>';
		
		html += '        				</div>';
		}
		html += '        			</div>';
		html += '        		</div>';
		
		html += '        		<div class="col-md-'+this.balanceWidth+' forms-grid">';	
		html += '        		</div>';
		
		html += '        	</div>';
		html += '      </div>';
//		html += '    </div>';
		html += '    <p></p>';
		return html;
	};
}
function insertUploadFileName(labelField, value, fileField, fileType)
{
	"use strict";
	if (Array.isArray(value))
	{
		/**
		 	FileTypes here must correspond with upload_val.php:
			1-9 = images
				-- 1 = /images/
				-- 2 == /images/stock/
				-- 3 == /images/profile/
				-- 4 == /images/gallery/
				-- 5 == /images/blog/
				-- 6 == /images/filetypes/
			10-19 = videos
			20-29 = downloads
			30-39 = audio
		**/
		switch(parseInt(fileType))
		{
			case  1:
			case  2:
			case  3:
			case  4:
			case  5:
			case  6:
			case  7: {prepImages(fileField, value, labelField); break;}
			case 20:
			{
				var tst = new prepDocs(fileField, value, labelField);
				tst.showData();
				break;
			}
			default: {break;}
		}
	}
	else
	{
		switch(parseInt(fileType))
		{
			case  1:
			case  2:
			case  3:
			case  4:
			case  5:
			case  6:
			case  7: 
			{
				if (window.opener.document.getElementById(labelField) !== null)
				{window.opener.document.getElementById(labelField).value = value;}
				
				if (window.opener.document.getElementById(fileField) !== null)
				{window.opener.document.getElementById(fileField).src = value;}	
				break;				
			}
			case 20:
			{
				if (window.opener.document.getElementById(labelField) !== null)
				{window.opener.document.getElementById(labelField).value = value;}
				
				if (window.opener.document.getElementById(fileField) !== null)
				{window.opener.document.getElementById(fileField).innerHTML = value;}	
				break;
			}
			default: {break;}
		}
	
	}
	window.close();
}

function removeImageElement(obj, imgDiv, labelField)
{
	"use strict";
	if (obj.parentNode.childElementCount > 1)
	{ 
		obj.parentNode.removeChild(obj);
	}
	else
	{
		var div = obj.parentNode.getElementsByName('imgContainer[]');
		div[0].setAttribute('style', 'background-image: url(\''+baseRootURL+'media/images/unknown_image.png\');');
	}
	
	var images = [];
	var elm = document.getElementsByName('imgContainer[]');
	for (var x=0; x<elm.length; x++)
	{		
		images[x] = elm[x].style.backgroundImage.slice(4, -1).replace(/"/g, "");
	}
	prepImages('imgContainer[]', images, labelField);
}

function removeFileElement(index, documentField, labelField)
{	
	"use strict";
	var files = document.getElementsByName('uploaded_file');
	var x, elm, cnt = 0, id, fileArr = [];
	for(x=0; x < files.length; x++)
	{
		if(x!==parseInt(index))
		{
			//console.log('x <> '+index+', so adding it to array.');
			id = 'uploaded_file_'+x;
			elm = document.getElementById(id);
			fileArr[cnt] = elm.title;
			cnt++;
		}
	}
	var tst = new prepDocs(documentField, fileArr, labelField);
	tst.showData();
}

function checkItemOrder(idNo)
{
	/*
	loop through all of the parents elements and check if any of the images have already been marked to change the order.
	If none have been marked, then mark this one. If another has already been marked then we swop the images and restore 
	the markings (colours):
	*/
	var obj = document.getElementById('imgDiv'+idNo); 
	
	if (document.getElementById('orderDiv'+idNo).className==='imageOrderSelectedDiv')
	{
		//since this item is the selected item, the user wants to reset:
		document.getElementById('orderDiv'+idNo).className = 'imageOrderDiv';
	}
	else
	{
		var par = obj.parentNode;
		var itms = par.getElementsByClassName('col-md-2 imageUploaded'); //all the "imgDiv" nodes we added above.
		var selItems;
		var marked = false;
		for (var x=0; x<itms.length; x++)
		{
			selItems = itms[x].getElementsByClassName('imageOrderSelectedDiv');
			if (selItems.length > 0)
			{
				marked = true;
				break;
			}
		}
		if (marked)
		{
			var div2 = document.getElementById('imgDiv'+x) ;
			var img1 = obj.style.backgroundImage;
			var img2 = div2.style.backgroundImage;
			
			obj.style.backgroundImage = img2;
			div2.style.backgroundImage = img1;
			
			document.getElementById('orderDiv'+idNo).className = 'imageOrderDiv';
			document.getElementById('orderDiv'+x).className = 'imageOrderDiv';
		}
		else
		{
			obj.getElementsByClassName('imageOrderDiv')[0].className = 'imageOrderSelectedDiv';
		}
	}
}

function loadPage(url, data){callModule(url, data);}

function getAjaxOptions(sourceFieldId, dataFieldId, phpFileName, defaultValue="")
{
	try	
	{
		var data = {};
		data.input_id      = document.getElementById(sourceFieldId).value;
		data.field_id      = dataFieldId;
		data.default_value = defaultValue;
		callModule("lib/"+phpFileName, data);
	}
	catch (e) {console.log(e.message);}	
}

//getAjaxData(id, 'selSize', 'getAirconSizes.php');
function getAjaxData(sourceValue, dataFieldId, phpFileName)
{
	"use strict";
	try	
	{
		var data = {};
		data.input_id = sourceValue;
		data.field_id = dataFieldId;
		callModule("lib/"+phpFileName, data);		
	}
	catch (e) {console.log(e.message);}
}

function callModule(url, data, callback) //was being called by getSableData which was deprecated.
{
	"use strict";
	var rnd = Math.floor((Math.random() * 255) + 1); //generate random number from 1 to 255
	var ajaxCall = new ajax("ajaxCall"+rnd, data, url, callback);
}

function getFileData(field, value, displayField)
{
	window.opener.document.getElementById(field).value = value;
	var inData  = {};
	inData.fileName = value;
	if (inData.fileName)
	{		
		var outData = loadPage("../upload/getHTMLContent.php", inData);
		if (outData) 
		{
			str = "var data = "+outData+";";
			if (str) eval(str); else alert('The remote object could not be translated.');
		} else alert('No data was returned from the server.');
		if (window.opener.document.getElementById(displayField)!=null)
			window.opener.document.getElementById(displayField).innerHTML = data.html;
	}
	window.close();
}

function viewSelection(sid, field, hidden, srch, module, condition)
{
	distributor= window.open("../"+module+"/list.php?"+ sid + "+" + field + "+" + hidden + "+" + srch + "+" + condition, "distributor", "location=0, menubar=0, scrollbars=0, status=0, titlebar=0, toolbar=0, directories=0, resizable=1, width=200, height=240, top=50, left=250");
	distributor.resizeTo(450, 600);
	distributor.moveTo(250, 50);
}

function insertSelectionCode(code, desc, field, hidden)
{
  window.close();
  window.opener.document.getElementById(field).value = desc;
  window.opener.document.getElementById(hidden).value = code;
}

function refineSelectionList(dataFieldId, sourceFieldId, phpFileName)
{
	"use strict";
	try
	{
		document.getElementById(dataFieldId).innerHTML = "<option>Loading...</option>";
		var data = {};
		data.input_id = document.getElementById(sourceFieldId).value;
		data.field_id = dataFieldId;
		callModule("lib/"+phpFileName, data);
	}
	catch (e) {console.log(e.message);}
}

//** calendar ** //
function viewcalendar(dateField)
{
  kalendarik = window.open("../lib/calendar.php?field="+dateField, "kalendarik" , "location=0, menubar=0, scrollbars=0, status=0, titlebar=0, toolbar=0, directories=0, resizable=0, width=200, height=265, top=50, left=265");
  kalendarik.resizeTo(300, 380);
  kalendarik.moveTo(250, 50);
}

function insertdate(d, dateField)
{
  window.close();
  window.opener.document.getElementById(dateField).value = d;
}

function validURL(url)
{
	var myRegExp =/^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i;
	return myRegExp.test(url);
}

function validateDate(dateField, fieldDesc)
{	
	if(!fieldDesc) throw ('missing field description.');
	var date = document.getElementById(dateField).value;	
	if (date != '' && !date.match(datePattern))
	{
		errors = true;
		handleError(dateField, "Please select a valid "+fieldDesc+" date.");
	}
	else 
	{		
		var dateElems = date.split("-");
		if (!isNumber(dateElems[0]) || !isNumber(dateElems[1]) || !isNumber(dateElems[2]) || 
		    (dateElems[0] < 2000)   || (dateElems[0] > 2100)   || (dateElems[1] < 1)      || (dateElems[1] > 12) || 
			(dateElems[2] < 1)      || (dateElems[2] > 31))
		{
			errors = true;
			handleError(dateField, "This is not a valid date for "+fieldDesc+".");
		}
		else clearError(dateField); 
	}
	return date;
}

function viewImage(imagePath)
{
	var img = new Image();
	img.src = imagePath;
	
	prent= window.open(imagePath, "prent" , "location=0, menubar=0, scrollbars=0, status=0, titlebar=0, toolbar=0, directories=0, resizable=1, width=250, height=250, top=50, left=50");
	
	prent.oncontextmenu = function(event) 
	{
		event.preventDefault();
		event.stopPropagation();
		//alert('Right click functionality has been disabled.');
		return false;
		
	};	
	prent.resizeTo(img.width, img.height);
	//prent.moveTo(0, 0);
}

function validateRequiredNumber(fieldID, errorMessages)
{
	var fieldValue = document.getElementById(fieldID).value;
	var ph = document.getElementById(fieldID).getAttribute('placeholder');
	
	if (!Array.isArray(errorMessages))
	{
		errorMessages = [];
		errorMessages[0] = "Please provide a valid numerical value.";
		errorMessages[1] = "Please enter a numeric value.";
		errorMessages[2] = "Please enter a value greater than zero.";
	}
	
	if (!fieldValue)
	{
		errors = true;
		errorMessage = (errorMessages[0])?errorMessages[0]:"A value is required for "+ph+".";
		handleError(fieldID, errorMessage);
	}
	else 
	{
		if ((!isNumber(fieldValue)))
		{
			errors = true;
			errorMessage = (errorMessages[1])?errorMessages[1]:"Please enter a numeric value "+ph+".";
			handleError(fieldID, errorMessage);
		}
		else 
		{
			fieldValue = (fieldValue * 1);
			if (fieldValue <= 0)
			{
				errors = true;
				errorMessage = (errorMessages[2])?errorMessages[2]:"Please enter a value greater than zero for "+ph+".";
				handleError(fieldID, errorMessage);				
			}
			else clearError(fieldID);
		}
	}
	return fieldValue;
}

function validateNumericField(fieldID, errorMessage)
{
	var val = document.getElementById(fieldID).value ? document.getElementById(fieldID).value : 0;
	var fieldValue = parseFloat(val);
	if (fieldValue) 
	{
		if ((!isNumber(fieldValue)))
		{
			errors = true;
			errorMessage = (errorMessage == "")?"Please enter a numeric value only.":errorMessage;
			handleError(fieldID, errorMessage);
		}
		else 
		{
			//fieldValue = (fieldValue * 1);
			if (fieldValue <= 0)
			{
				errors = true;
				errorMessage = (errorMessage == "")?"Please enter a value greater than zero.":errorMessage;
				handleError(fieldID, errorMessage);
			}
			else clearError(fieldID);
		}
	}
	return fieldValue;
}

function validateText(fieldID)
{
	var fieldValue = document.getElementById(fieldID).value;
	return fieldValue;
}

function validateRequiredText(fieldID, errorMessage)
{
	var fieldValue = document.getElementById(fieldID).value;
	if (fieldValue == "")
	{
		errors = true;
		errorMessage = (errorMessage == "")?"A value is required for this field.":errorMessage;
		handleError(fieldID, errorMessage);
	}
	else clearError(fieldID);
	return fieldValue;
}

function validateRequiredSelection(fieldID, errorMessage)
{
	var selectField = document.getElementById(fieldID);
	var index = parseInt(selectField.options.selectedIndex);
	if (index === -1)
	{
		errors = true;
		errorMessage = (errorMessage === "")?"Please make a selection.":errorMessage;
		handleError(fieldID, errorMessage);		
	}
	else
	{
		var fieldValue = selectField.options[index].value;
		if (!fieldValue)
		{
			errors = true;
			errorMessage = "No options are available.";
			handleError(fieldID, errorMessage);
		}
		else
		{
			if (fieldValue === "0")
			{
				errors = true;
				errorMessage = (errorMessage === "")?"Please make a selection.":errorMessage;
				handleError(fieldID, errorMessage);
			} else clearError(fieldID);
		}
	}
	return fieldValue;
}

function validateRequiredCheckbox(fieldID, errorMessage)
{
	var checkField = document.getElementById(fieldID);
	var fieldValue = checkField.checked;
	if(!fieldValue)
	{
		errors = true;
		errorMessage = !errorMessage?"Your confirmation is required.":errorMessage;
		handleError(fieldID, errorMessage);
	}
	else clearError(fieldID);
	return fieldValue;
}

function validateSelection(fieldID, errorMessage)
{
	var selectField = document.getElementById(fieldID);
	var ops = selectField.options[selectField.options.selectedIndex];
	var fieldValue = ops !== undefined ? ops.value : 0;
	/*
	if (!fieldValue)
	{
		errors = true;
		errorMessage = errorMessage ? errorMessage : "No options are available.";
		handleError(fieldID, errorMessage);
	}
	else clearError(fieldID);
	*/
	clearError(fieldID);
	return fieldValue;
}

function validateEmail(fieldID, errorMessage)
{
	var fieldValue = document.getElementById(fieldID).value;
	if (fieldValue !== "")
	{
		if (!isValidEmail(fieldValue))
		{
			errors = true;
			var em = (errorMessage) ? errorMessage : "Email address does not seem to be valid.";
			handleError(fieldID, em);
		} else clearError(fieldID);
	}
	else clearError(fieldID);
	return fieldValue;	
}

function validateRequiredEmail(fieldID, errorMessage)
{
	document.getElementById(fieldID).value = document.getElementById(fieldID).value.toLowerCase();
	var fieldValue = document.getElementById(fieldID).value;
	if (fieldValue == "")
	{
		errors = true;
		var em = (errorMessage === "") ? "A value is required for this field." : errorMessage;
		handleError(fieldID, errorMessage);
	}
	else 
	{
		fieldValue = validateEmail(fieldID, errorMessage);
	}
	return fieldValue;
}

function validateConfirmationEmail(fieldID, confirmId, errorMessage)
{
	document.getElementById(fieldID).value = document.getElementById(fieldID).value.toLowerCase();
	document.getElementById(confirmId).value = document.getElementById(confirmId).value.toLowerCase();
	var fieldValue = document.getElementById(fieldID).value;
	
	if (fieldValue == "")
	{
		errors = true;
		errorMessage = (errorMessage == "")?"Please confirm the email address.":errorMessage;
		handleError(fieldID, errorMessage);
	}
	else 
	{
		if (isValidEmail(fieldValue))
		{
			var origValue = document.getElementById(confirmId).value;
			if (fieldValue == origValue)
			{
				clearError(fieldID);
			}
			else
			{
				errors = true;
				errorMessage = "The email addresses do not match.";
				handleError(fieldID, errorMessage);					
			}
		}
		else
		{
			errors = true;
			errorMessage = "Not a valid email address.";
			handleError(fieldID, errorMessage);			
		}
	}
	return fieldValue;
}

function validateSliderValue(fieldID, min, max)
{
	var field = document.getElementById(fieldID);
	var fieldValue;
	var valMax = max; //field.getAttribute("max");
	var valMin = min; //field.getAttribute("min");
	
	if (field != null)
	{
		fieldValue = field.value; 
		if (fieldValue > valMax) 
		{
			errors = true;
			handleError(fieldID, "Value cannot be greater than "+valMax+".");			
		}
		if (fieldValue < valMin) 
		{
			errors = true;
			handleError(fieldID, "Value cannot be less than "+valMin+".");			
		}		
	}
	return fieldValue;	
}

function validatePhoneNumber(fieldID, errorMessage, required)
{
	var fieldValue = document.getElementById(fieldID).value;
	if (fieldValue == "")
	{
		if(required)
		{
			errors = true;
			errorMessage = (errorMessage == "") ? "Phone number required." : errorMessage;
			handleError(fieldID, errorMessage);		
		} 
		else clearError(fieldID);
	}
	else
	{
		if ((!isValidPhoneNumber(fieldValue)))
		{
			errors = true;
			handleError(fieldID, errorMessage);
		}
		else clearError(fieldID);
	}
	return fieldValue;
}

function validateRSAIDNo(fieldID, errorMessage, required)
{
	var fieldValue = document.getElementById(fieldID).value;
	if (!fieldValue)
	{
		if (required)
		{
			errors = true;
			errorMessage = (errorMessage == "")?"Please enter an ID number.":errorMessage;
			handleError(fieldID, errorMessage);		
		}
		else clearError(fieldID);
	}
	else
	{
		if ((!isNumber(fieldValue)) || (fieldValue.length != 13))
		{
			errors = true;
			//handleError(fieldID, "The ID number should consist of 13 numeric digits without spaces.");
			handleError(fieldID, "Not a valid ID number.");
		}
		else clearError(fieldID);
	}
	return fieldValue;
}

function validatePassportNo(fieldID, errorMessage, required)
{
	var fieldValue = document.getElementById(fieldID).value;
	if (!fieldValue)
	{
		if (required)
		{
			errors = true;
			errorMessage = (errorMessage == "")?"Please enter a passport number.":errorMessage;
			handleError(fieldID, errorMessage);		
		}
		else clearError(fieldID);
	}
	else
	{
		var myRegExp =/^[A-PR-WY][1-9]\d\s?\d{4}[1-9]$/ig;		
		if (!myRegExp.test(fieldValue))
		{
			errors = true;
			handleError(fieldID, "Invalid passport number.");	
		}
		else clearError(fieldID);
	}
	return fieldValue;
}

function validatePassword(fieldID, confirmId, required)
{
	var pwdField = document.getElementById(fieldID);
	var fieldValue; 
	if (pwdField != null)
	{
		fieldValue = pwdField.value;
		if (fieldValue != "") 
		{
			if (fieldValue.length < 8)
			{
				errors = true;
				handleError(fieldID, "Your password length should be at least 8 characters long.");	
			}
			else
			{
				if (fieldValue != document.getElementById(confirmId).value)
				{
					errors = true;
					handleError(confirmId, "Your passwords do not match.");
					clearError(fieldID);
				}
				else 
				{	
					clearError(fieldID);
					clearError(confirmId);
				}
			}
		}
		else
		{
			if(required===true)
			{
				errors = true;
				handleError(fieldID, "Password is required.");
			}
			else 
			{	
				clearError(fieldID);
				clearError(confirmId);
			}
		}
	}
	else fieldValue = "";
	return fieldValue;
}

function validateImage(fieldID, defaultImage)
{
	var fieldValue;
	if (document.getElementById(fieldID) != null)
	{
		fieldValue = document.getElementById(fieldID).value; 
		if (fieldValue == "") fieldValue = defaultImage;
	}
	else fieldValue = defaultImage;	
	return fieldValue;
}

function validateImageMulti(labelFieldId, arrayFieldId, defaultImage)
{
	var labelField  = document.getElementById(labelFieldId);
	var arrayFields = document.getElementsByName(arrayFieldId);
	if (arrayFields.length <= 0)
	{
		errors = true;
		handleError(labelFieldId, "Please select images to upload.");	
	}
	else 
	{		
		imgArray = new Array();
		for(var i=0; i<arrayFields.length; i++) 
		{
			if (arrayFields[i].src != 'undefined') imgArray[i] = arrayFields[i].src;
		}
		clearError(labelFieldId);
		return imgArray;
	}
}

function validateTextArea(fieldID, errorMessage, required)
{
	var fieldValue = document.getElementById(fieldID).value;
	if (required)
	{
		if(fieldValue==="")
		{
			errors = true;
			errorMessage = (errorMessage === "")?"Please enter some detail.":errorMessage;
			handleError(fieldID, errorMessage);
		}
		else clearError(fieldID);
	}
	else clearError(fieldID);
//	return encodeURIComponent(fieldValue);
	return fieldValue;
}

function validateRadioGroup(groupName, hintFieldId, errorMessage="")
{
	//checks that at least one of the radio's are selected:
	var err = errorMessage===""?'Please select one of the options.':errorMessage;
	var rads = document.getElementsByName(groupName);
	var i;
	var set = false;
	for(i=0; i<rads.length; i++)
	{
		set = rads[i].checked;
		if (set) break;	
	}
	if (set)
	{
		clearError(hintFieldId); 
	}
	else
	{
		handleError(hintFieldId, err)
	}
	return set;
}

function validateNicEditTextArea(fieldID, errorMessage, required)
{
	var fieldValue = nicEditors.findEditor(fieldID).getContent();	
	if(required)
	{
		if(fieldValue==="<br>")
		{
			errors = true;
			errorMessage = (errorMessage === "")?"Please enter some detail.":errorMessage;
			handleError(fieldID, errorMessage);
		}
		else clearError(fieldID);
	}
	else clearError(fieldID);
//	return encodeURIComponent(fieldValue);
	return fieldValue;
}

function trim(str)
{
  var newstr;
  newstr = str.replace(/^\s*/, "").replace(/\s*$/, "");
  for (var x=0; x < 10; x++)  newstr = newstr.replace(/\s{2,}/, " ");
  return newstr;
} 

function correctName(str)
{
	str = trim(str);
    return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
}

function addSelectionList(senderElement, elementName, containerId)
{
	this.items = new Array();
	this.handle = 0;
	this.colWidth = 12;
	this.balanceWidth = 1;
	this.prependedText = '';
	this.appendedText = '';
	this.displayText = ''; //what the user actually sees in the list item
	this.tag = '';
	this.itmIdx = -1; //if your <select> options has a "Select..." to indicate the user must select. Sometimes this is 0, so it can be changed if necessary, otherwise addItem will add the "select..." to the list.
	this.readonly = false;
	
	this.prependText 	= function(text){this.prependedText = text;}
	this.appendText 	= function(text){this.appendedText = text;}
	this.setTag 		= function(text){this.tag = text;}
	this.setItmIdx 		= function(idx) {this.itmIdx = idx;}
	this.setDisplayText = function(text){this.displayText = text;}
	this.setReadOnly 	= function(readonly){this.readonly = readonly;}
	
	this.setColWidth = function(width)
	{
		this.colWidth = width;
		this.balanceWidth = 12 - this.colWidth;
	}

	this.buildElement = function()
	{
		"use strict";
		var readonlyClass = this.readonly ? 'readonly' : '';
		var dtxt = (this.displayText)?this.displayText:this.items[this.handle].text;
		//build the HTML:
//		var html = '<p></p>';
		var html = '<p></p>';

		html += '        	<div class="col-md-'+this.colWidth+' forms-grid" style="margin-top:10px;">';
		html += '          		<div class="list-item-main '+readonlyClass+'">';
		html += '					<i class="fa fa-check-square-o" aria-hidden="true"></i>&nbsp;'+dtxt;
		
		if (!this.readonly)
		{
			html += '      				<div class="list-item-action">';
			html += '        				<i onClick="'+senderElement+'.removeItem(\''+this.handle+'\')" class="fa fa-times-circle pointer" style="color:#d10a11" aria-hidden="true" ';
			html += '							title="Remove '+dtxt+'"></i>';
			html += '        			</div>';	
		}
		
		html += '        		</div>';
		html += '        	</div>';

//		html += '    </div>';
		html += '    <p></p>';
		return html;
	}
	
	this.createItem = function(incrementHandle)
	{
		//now add the element
		var newDiv = document.createElement('div');
		newDiv.setAttribute('id', elementName+'Element'+this.handle);
		newDiv.innerHTML = this.buildElement();
		if (document.getElementById(containerId)!==null)
		{
			document.getElementById(containerId).appendChild(newDiv);	
		}
		else
		{
			if (window.opener.document.getElementById(containerId)!==null)
			{
				window.opener.document.getElementById(containerId).appendChild(newDiv);	
			}
		}
		//increment the handle counter
		this.handle = (incrementHandle)?this.handle += 1:this.handle;	
	}
	
	this.addBasicItem = function(value, caption)
	{
		var goOn = true;
		for(var itm in this.items)
		{
			if(caption===this.items[itm].text) 
			{
				goOn = false;
				break;
			}
		}
		
		if(goOn)
		{
			this.items[this.handle] = {};
			this.items[this.handle].value = value;
			this.items[this.handle].text  = this.prependedText + caption + this.appendedText; //goes to $_POST and id should be encoded
			this.items[this.handle].tag   = this.tag; //any additional info required. Could even be a struct, array, etc.
			this.items[this.handle].displayText = this.displayText;
			this.items[this.handle].readonly 	= this.readonly;			
			this.createItem(true);
		};// else alert('"'+obj.options[obj.selectedIndex].text+'" has already been added.');
	}
	
	this.addItem = function(selectElement)
	{
		if (selectElement.selectedIndex > this.itmIdx)
		{
			var goOn = true;
			for(var itm in this.items)
			{
				if(selectElement.value===this.items[itm].value) 
				{
					goOn = false;
					break;
				}
			}
			
			if(goOn)
			{
				this.items[this.handle] = {};
				this.items[this.handle].value = selectElement.value;
				this.items[this.handle].text  = this.prependedText + selectElement.options[selectElement.selectedIndex].text + this.appendedText; //goes to $_POST and id should be encoded
				this.items[this.handle].tag 		= this.tag; //any additional info required. Could even be a struct, array, etc.
				this.items[this.handle].displayText = this.displayText;
				this.items[this.handle].readonly 	= this.readonly;
				this.createItem(true);
			};// else alert('"'+obj.options[obj.selectedIndex].text+'" has already been added.');
		}
	}
	
	this.removeItem = function(removeHandle)
	{
		var x;
		var tmp = [];
		tmp = this.items;
		this.removeAll(); //remove the list to start over.
		delete tmp[removeHandle]; //delete the relevant array entry
		
		var itmHandle = 0;
		this.handle = 0; //reset the counter.
		this.items = []; //clear the array to start again:
		for (itm in tmp) //tmp is the key!
		{
			this.items[this.handle] = {};
			this.items[this.handle].value		= tmp[itm].value;	
			this.items[this.handle].text		= tmp[itm].text;
			this.items[this.handle].tag			= tmp[itm].tag;
			this.items[this.handle].displayText	= tmp[itm].displayText;	
			this.items[this.handle].readonly	= tmp[itm].readonly;
			
			this.setTag(tmp[itm].tag);
			this.setReadOnly(tmp[itm].readonly);
			this.setDisplayText(tmp[itm].displayText);
			
			this.createItem(false); //restore the child nodes in proper sequence.
			this.handle++;
		}
	}
	
	this.removeAll = function()
	{
		var divItem;
		if (document.getElementById(containerId) !== null)
		{
			divItem = document.getElementById(containerId);
		}
		else
		{
			if (window.opener.document.getElementById(containerId)!==null)
			{
				divItem = window.opener.document.getElementById(containerId);
			} else throw('Invalid field id specified.');		
		}		
		while (divItem.firstChild){divItem.removeChild(divItem.lastChild)} //remove all the dom child nodes
	}
	
	this.validateItems = function(minimum, element, description)
	{
		var mm = parseInt(minimum);
		var cn = parseInt(this.items.length);
		//alert('You have '+cn+' items, but need at least '+mm);
		if (cn < mm)
		{
			errors = true;
			handleError(element, "You need to add at least "+mm+" "+description+".");
		}
	}
	
	this.getItemsAsString = function()
	{
		//what is not not needed to be sent over the network is removed:
		var arr = [];
		var tmp = {};
		for (var x = 0; x < this.items.length; x++)
		{
			tmp			= {};
			tmp.value 	= this.items[x].value;
			tmp.tag		= this.items[x].tag;
			tmp.text	= this.items[x].text;
			arr[x] = tmp;
		}
		return JSON.stringify(arr);
	}
	
	this.getCount = function(){return this.items.length;}
}

function inputRefinement(inputFieldId, outputFieldId, phpFileName)
{	
	try
	{
		this.data = {};
		this.refineInput = function(callback)
		{
			document.getElementById(outputFieldId).innerHTML = "<option>Loading...</option>";
			this.data.input_id = document.getElementById(inputFieldId).value;
			this.data.field_id = outputFieldId;
			callModule("lib/"+phpFileName, this.data, callback);
		}
	} catch (e) {console.log(e.message);}
}

function getGenderFromRSAId(id){return ((id[6] * 1) > 4)?true:false;} //returns true if Male, false if Female

function scrollToAnchor(aid)
{
	$("#"+aid)[0].scrollIntoView({
    behavior: "smooth", // or "auto" or "instant"
    block: "start" // or "end"
});
}

function runCallback(function1, function2)
{
 /* 
 Running a callback means that we have 2 functions, the second will wait for the first to be done before executing.	
 This fixes a problem that we are often faced with trying to make two consecutive Ajax calls one after the other. Because
 we make the Ajax calls asyncronously, making 2 calls causes the process to hang. Callbacks fixes the problem.
 NOTE: this can be changed to work with an array if multiple calls are required.
 
 example on how to use:
 
 function firstFunc(callback)
 {
	 ...do stuff...
	 callback();
 }
 function secondFunc()
 {	
	...do something...
 }
 
 runCallback(firstFunc, secondFunc);
 
 */
 	"use strict";
	function1(function2);
}

function setCookie(cname, cvalue, exdays) 
{
	var d = new Date();
	d.setTime(d.getTime() + (exdays*24*60*60*1000));
	var expires = "expires="+ d.toUTCString();
	document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}

function getCookie(cname) 
{
	var name = cname + "=";
	var decodedCookie = decodeURIComponent(document.cookie);
	var ca = decodedCookie.split(';');
	for (var i = 0; i < ca.length; i++) 
	{
		var c = ca[i];
		while (c.charAt(0) == ' '){c = c.substring(1);}
		if (c.indexOf(name) == 0) {return c.substring(name.length, c.length);}
	}
	return "";
}

function deleteCookie(cname)
{
	setCookie(cname, "", 0);
}

function getOrSetCookie(cname, cvalue)
{
	var cki = getCookie(cname);
	if (cki) 
	{
		return cki; 
	}
	else
	{
		setCookie(cname, cvalue);
		return cvalue;
	}
}