/* ## global.js - contains global functions and constants ## */

/* ## global constants ## */

// key codes
var KEY_RETURN = 13;

// custom attributes
var SAVE_FIELD_KEY = 'sfk';

/* ## global functions ## */


/* url funcs */

function isUsingProxy(){
    return null != PROXY_RELATIVE_URL && PROXY_RELATIVE_URL != '';
};


// string formatting
function doStringFormat(format, args){
    // props: http://frogsbrain.wordpress.com/2007/04/;28/javascript-stringformat-method/
    var pattern = /\{\d+\}/g;
    return format.replace(pattern, function(capture){ return args[capture.match(/\d+/)]; });
};

// reload the page with the specified country and subregion
function reLoadCountry(countryID, subRegionID)
{
    var key = ['cid', 'srid'];
    var value = [countryID, subRegionID];
    reLoadPage(key, value);
};

// reload the page with the specified key / value appended or replaced on qs
// nb - key and value can be arrays
function reLoadPage(key, value)
{
    var url = document.location.href;
    
    if(isArray(key) && isArray(value))
    {
         for (var i = 0; i < key.length; i++)
         {
            url = appendQuerystring(url, key[i], value[i]);
         }
    }   
    else
    {
        url = appendQuerystring(url, key, value);
    };
    
    document.location.href = url;
};

// append / replace the current querystring key / value pair on the url
function appendQuerystring(url, key, value){
    var result = url;
    var val = key + '=' + value;
    
    var pattern = key + '=[^&]*';
    
    var re = new RegExp(pattern, 'g');
    var match = re.exec(url);
    
    if(null != match){
        result = url.replace(re, val);
    }else{
        var separator = url.indexOf('?') == -1 ? '?' : '&';
        result = url + separator + val;
    };
    
    return result;
    
};

function isArray(obj)
{
    return obj.constructor.toString().indexOf("Array") != -1;
};

/// Get the integer value from the specified control id. Default = 0
//  + ctrl (string) - the client id of the control containing quantity value
function getInt(ctrl)
{
    var result = getControlValue(ctrl);
    
    if(isNaN(result))
    {
        result = 0;
    };

    return result;
};

/// disable the specified button
function disableButton(btn) {
    
    btn.className = btn.className.indexOf('_disabled') == -1
                        ? btn.className + '_disabled'
                        : btn.className;
                        
    btn.onclick = function(){return false;};
    btn.enabled = false;
    btn.disabled = "disabled";
    btn.title = '';
    btn.href = '';
    
};

/// roundTo2Decimals on the given value
function roundTo2Decimals(value) {
    if(isNaN(value)) return value;
    
    result = Math.round(value * 100) / 100;
	
	return result;
};

/// ensure 2 trailing decimals on the given value
function ensure2TrailingDecimals(value) {
    var result = roundTo2Decimals(value);
    
	var re1 = new RegExp("\\.\\d{1}$");
	var re2 = new RegExp("\\.\\d{2}$");
	
	if(null != re1.exec(result)){
	    result += '0';
	}else if(null == re2.exec(result)){
	    result += '.00';
	};
	
	return result;
	
};


/// get the element with specified id
function getElement(id)
{
    return $('#' + id);
};

/// get the value of the input select with specified id
function getSelectValue(ctrlID){
    var ctrl = document.getElementById(ctrlID);
    
    // TODO - jquery way?
    if(ctrl != null && ctrl.options && ctrl.options.length > 0)
    {
        return ctrl.options[ctrl.selectedIndex].value;
    }
    else
    {
        return '';
    };
};

// set the value of the control with specified id
function setControlValue(ctrlID, value){
    $('#' + ctrlID).attr("value", value);
};

/// get the value of the control. default empty string
/// + controlID (string)
function getControlValue(controlID){
    var result = $('#' + controlID).attr("value");
    return isDefined(typeof(result)) ? result : '';
};


// replace the matched element with the specified HTML or DOM elements
// + id - the matched element
// + value - the HTML or DOM elements to replace
function replaceValue(id, value){
    $('#' + id).replaceWith(value)
};

// set the matched inner HTML of the matched element with the specified HTML or DOM elements
// + id - the matched element
// + value - the HTML or DOM elements to set
function setHTML(id, value){
    $('#' + id).html(value)
};


// returns jQuery.find() on all checkboxes contained in the matched element
// + id - the matched element
function getAllCheckboxes(id){
    return $('#' + id).find("input[type='checkbox']")
};

// register a .slideToggle call on the specified trigger and element
// + triggerID - id of the the trigger
// + elementID - id of the the element to toggle
function registerSlider(triggerID, elementID){
    return $("#" + triggerID).click(function () {
        $("#" + elementID).slideToggle("fast");
    });
};




/// generic function for handling all JSON responses
/// + jsonData - json data object (MangoLab.MangoBasket.Web.Json.Data.JsonData)
/// + userMessageControlID - id of html element to display a user message
function canHandleJSON(jsonData, userMessageControlID){

    var result = !jsonData.IsError;
    
    if(jsonData.IsError && IS_DEBUG && jsonData.UserMessage.trim() != ''){
        alert(jsonData.UserMessage);
    };
    
    if(null != jsonData.AuthCookieName) setCookie(jsonData.AuthCookieName, jsonData.AuthCookieValue);
    
    if(null != jsonData.RedirectUrl && !(jsonData.IsSiteClosedForMaintenance && $('#vwLogin').length > 0)){
    
        if(typeof(userMessageControlID) != 'undefined')
            displayUserMessage(userMessageControlID, 'Please wait....', false);

        document.location.href = jsonData.RedirectUrl;
        result = false;

    };
    
    return result;

};

/// display a messge in the control with specified id
/// + id (string) - id element of element
/// + msg (string) - the message to display
/// + fade (bool) - whether to fade the element (default true)
/// + cssClass (string)
function displayUserMessage(id, msg, fade, cssClass){
    if(false == fade){
        $('#' + id).html(msg);
    }else{
        // default behaviour
        var lbl = $('#' + id);
        cssClass = typeof(cssClass) != 'undefined' 
                    ? cssClass 
                    : lbl.attr("class");
        lbl.hide().attr("class", cssClass).fadeIn().html(msg);
    };
};


// open a window at the specified url, width, height, top and left
function openWindow(url, width, height, top, left){
    var features = 'scrollbars=1,modal=no,directories=0,menubar=0,titlebar=0,toolbar=0,top=' + top + ',left=' + left + ',width=' + width + ',height=' + height;
    return window.open(url, '', features);
};

// open an image popup at the specified url, width and height
function openImagePopup(url, width, height){
    return openWindow(url, width, height, 100, 100);
};

// return a key code from a key press event - default null
function getKey(e)
{
	var key = null;
	
	if(e && e.which)
		key = e.which;
		
	else if (isDefined(typeof(event)))
		key = event.keyCode;
		
	return key;
};

// return only numeric key presses
function onKeyPressNumericOnly(e)
{
	var key = getKey(e);
	var result = true;
	
	if(key != 0 && key != 8) // delete, back, ins etc.
	{
		
		var val = String.fromCharCode(key);
		result = val >= 0 && val <= 9;
	};
	
	return result;  
};

// return only if the control value is a decimal after the key event (to 2 places)
function onKeyPressDecimalOnly(e, ctrl)
{
	var key = getKey(e);
	var result = true;
	
	
	if(key != 0 && key != 8) // delete, back, ins etc.
	{
		var val = ctrl.value + String.fromCharCode(key);
		result = isDecimal(val);
	};
	
	return result;
};

// returns a value indicating whether the type is defined
//  + t - object type
function isDefined(t){
    return t != 'undefined';
};

// returns a value indicating whether the val is a decimal (to 2 places)
function isDecimal(val){
    var re = new RegExp("^\\d*(\\.\\d{0,2})?$");
	return null != re.exec(val);
};

// returns a value indicating whether the val is numeric (no decimals)
function isNumeric(val){
    var re = new RegExp("^\\d*$");
	return null != re.exec(val);
};

// enforce a numeric value on the control
function enforceNumeric(ctrl){

    var val = getSavedFieldValue(ctrl);

    if(isNumeric(ctrl.value.trim())){
        val = ctrl.value.trim();
    };
    
    ctrl.value = val;

    saveFieldValue(ctrl, val);
    
};

// enforce a decimal value on the control
function enforceDecimal(ctrl){

    var val = getSavedFieldValue(ctrl);
    
    if(isDecimal(ctrl.value.trim())){
        val = ctrl.value.trim();
    };
    
    ctrl.value = val;

    saveFieldValue(ctrl, val);
};

/// save the current value of a field in the DOM
function saveFieldValue(ctrl, val){
    ctrl.setAttribute(SAVE_FIELD_KEY, val);
};

/// return a saved field value
function getSavedFieldValue(ctrl){
    return ctrl.getAttribute(SAVE_FIELD_KEY);
};


// return selected text - default empty string
function getSelectedText()
{
    var result = '';
    
    if (typeof(window.getSelection) == 'function'){
        result = window.getSelection();
    }
    else if (typeof(document.getSelection) == 'function'){
        result = document.getSelection();
    }
    else if (typeof(document.selection) == 'function'){
        result = document.selection.createRange().text;
    };
    
    return result;
};


// initiate a prompt with a callback on success (with Yes / No buttons)
// + msg (string) - message as html
// + callbackYes (function) - function to execute on yes
// + callbackNo (function) - function to execute on no (optional)
// + isAutoWidth (bool) - auto-width on containing div? (optional)
// + buttons (jqi buttons) - default to { Yes: true, No: false } (optional)
function doPrompt(msg, callbackYes, callbackNo, isAutoWidth, buttons){
    
    
    isAutoWidth = (typeof(isAutoWidth) == 'undefined') ? false : isAutoWidth;
    var width = isAutoWidth ? "auto" : "330px";
    msg = "<div style=\"width:" + width + ";\">" + msg + "</div>";
    
    if(typeof(buttons) == 'undefined') buttons = { Yes: true, No: false };
    
    $.prompt(msg, { 
		buttons:  buttons,
		callback: function(v,m) {
		    if(v){ 
			    callbackYes();
            } else if(typeof(callbackNo) == 'function') {
                callbackNo(); 
            };
		}
	});
};

function handleError(e, method){
    $().mangoLog("!handleError:" , e);
    $().mangoLog("!handleError:" , method);
    if(true == IS_DEBUG)
        throw('Error in ' + method + ': ' + e);
};



// ## string prototype functions ## //
String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
};
String.prototype.ltrim = function() {
	return this.replace(/^\s+/,"");
};
String.prototype.rtrim = function() {
	return this.replace(/\s+$/,"");
};



/*  "dependency" functions */

// set checkbox checked depending on value
// + controlID (string) - the ID of checkbox / radio
// + value (string) to check against
// + unCheckWhenEmpty (bool) whether to uncheck the control if value empty
function doCheckBoxDependency(controlID, value, unCheckWhenEmpty){
    
    var isEmpty = (value == '');
    var doCheck = unCheckWhenEmpty || (!unCheckWhenEmpty && !isEmpty);
    
    if(true == doCheck){
        var ctrl = $('#' + controlID);
        ctrl.attr("checked", !isEmpty);
    };
};

// set radios checked depending on value
// + control1ID (string) - the ID of radio - on
// + control2ID (string) - the ID of radio - off
// + value (string) to check against
function doRadioDependency(controlOnID, controlOffID, value){
    
   
    var turnOff = value == '' || value == 'undefined';
    
    var ctrlOn = $('#' + controlOnID);
    var ctrlOff = $('#' + controlOffID);
    
    ctrlOn.attr("checked", !turnOff);
    ctrlOff.attr("checked", turnOff);
    
    
};

// copy values from box1 to box2
// + control1ID (box1ID) - the ID of text box 1
// + control2ID (box2ID) - the ID of text box 2
// + ifBox2NotEmpty (bool) - whether to copy values if box 2 is *not* empty
function doTextBoxDependency(box1ID, box2ID, ifBox2NotEmpty){
    
    var box1 = $('#' + box1ID);
    var box2 = $('#' + box2ID);
    if(true == ifBox2NotEmpty || box2.attr("value").length == 0){
        box2.attr("value", box1.attr("value"));
    };
    
};

// set all checkboxes in control of specified id
// + id (string) - of parent dom
// + checked (bool) - check / uncheck
function checkAll(id, checked)
{
    getAllCheckboxes(id).each(function (i) {
        $(this).attr("checked", checked);
    });
    
};

// html-encode the specified value
function htmlEncode(value){
    return $('<div/>').text(value).html();
};

/// cookie functions ///

/// write the contents of the current quersytring as cookies
/// + keys (array) keys to include. if null or undefined, all keys are included
/// + qs (string) the querystring. optional, defaults to current querystring
function queryStringToCookies(keys, qs){

    var checkKeys = null == keys || typeof(keys) != 'undefined';

    qs = typeof(qs) == 'undefined'
            ? document.location.href.split('?', 2)[1] 
            : qs;
            
    if(typeof(qs) != 'undefined'){
        var values = qs.split('&');
        for(var i in values){
            var spl = values[i].split('=');
            if(spl.length > 1){
                var key = spl[0];
                var val = spl[1];
                if(false == checkKeys || getIndexOf(keys, key) != -1){
                    setCookie(key, val);
                };
            };
        };
    };

};

/// write the contents of the all cookies as a querystring
/// + keys (array) keys to include. if null or undefined, all keys are included
function cookiesToQueryString(keys){
    
    var result = "";
    if(typeof(keys) != 'undefined'){
        var cookies = document.cookie.split(";");
        for(var i in keys){
            result += doStringFormat("{0}={1}{2}", [keys[i], getCookie(keys[i]), i == keys.length-1 ? "" : "&"]);
        };
    }else{
        var re = new RegExp('; ', 'g');
        result = document.cookie.replace(re, "&");
    };
    
    return result;
};

/// get the cookie with specified key
/// TODO - this is horrid 
function getCookie(key){
    var myCookie=document.cookie;
    key = escape(key);
    var cookieValue;
    var start=myCookie.indexOf(" " + key + "=");
    if(start==-1) start=myCookie.indexOf(key + "=");
    if(start==-1) cookieValue=null;
    else{
	    start=myCookie.indexOf("=",start)+1;
	    var end=myCookie.indexOf(";",start);
	    if(end==-1) end=myCookie.length;
	    cookieValue=myCookie.substring(start,end);
    };
    return unescape(cookieValue);
};

/// set a cookie value
function setCookie(key, value, path, lifetime){
	
    if(document.cookie.length<=7300){
	
	    if(typeof path == 'undefined')
		    path = "/";
	
	    if(typeof lifetime == 'undefined')
		    lifetime = 1000;
	
	    var ddate=new Date();
	    ddate.setDate(ddate.getDate()+eval(lifetime));
	    var expires=ddate.toGMTString();
		
	    document.cookie=escape(key)+"="+escape(value)+";expires="+expires+";Path="+path+";";
    };
};



/// #### IE hacks ####

/// returns the index of the specified key in the array
/// default value: -1
function getIndexOf(array, key){
    /// (NB we could extend the Array prototype, but the function then appears in iterations of the array, so use this instead)
    var result = -1;
    if(typeof(array.indexOf) == 'function'){
        result = array.indexOf(key);
    }else{
        for(var i in array){
            if(array[i] == key){
                result = i;
                break;
            };
        };
    };
    return result;
};


