var JSON = JSON || {};

// implement JSON.stringify serialization  
JSON.stringify = JSON.stringify || function (obj) {  
    var t = typeof (obj);  
    if (t != "object" || obj === null) {  
        // simple data type  
        if (t == "string") obj = '"'+obj+'"';  
        return String(obj);  
    } else {  
        // recurse array or object  
        var n, v, json = [], arr = (obj && obj.constructor == Array);  
        for (n in obj) {  
            v = obj[n]; t = typeof(v);  
            if (t == "string") v = '"'+v+'"';  
            else if (t == "object" && v !== null) v = JSON.stringify(v);  
            json.push((arr ? "" : '"' + n + '":') + String(v));  
        }  
        return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");  
    }  
};  


function URLDecode(value) {
    return decodeURIComponent(value);
};

function URLEncode(value) {
    return encodeURIComponent(value);
};
        
var noop = function () {};

var arrayMerge = function (/* arrays */) {
    var newArr = [];
    for (var i=0; i<arguments.length; i++) {
        var tmpArr = arguments[i];
        for (var j=0;j<tmpArr.length;j++) {
        newArr[newArr.length] = tmpArr[j];
        }
    }
    return newArr;
};


//ATTENTION: identical parameters are overwritten
var objectMerge = function (/* objects */) {
    var newObj = {};
    for (var i=0; i<arguments.length; i++) {
        var tmpObj = arguments[i];
        for (var j in tmpObj) {
            newObj[j] = tmpObj[j];
        }
    }
    return newObj;
};

var partial = function (/** func, [param[, param [,...]]]*/) {
    var func = arguments[0];
    var tmpArr = [];
    for (var i=1; i<arguments.length;i++) {
        tmpArr[tmpArr.length] = arguments[i];
    }
    return function () { return func.apply(this,arrayMerge(tmpArr,arguments)); };
};

var base64decode = function (str) {
    var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
    var invalid = {
        strlen: (str.length % 4 != 0),
        chars:  new RegExp('[^' + chars + ']').test(str),
        equals: ((/=/).test(str) && ((/=[^=]/).test(str) || (/={3}/).test(str)))
    };
    if (invalid.strlen || invalid.chars || invalid.equals)
        throw new Error('Invalid base64 data');
    var decoded = [];
    var c = 0;
    while (c < str.length) {
        var i0 = chars.indexOf(str.charAt(c++));
        var i1 = chars.indexOf(str.charAt(c++));
        var i2 = chars.indexOf(str.charAt(c++));
        var i3 = chars.indexOf(str.charAt(c++));
        var buf = (i0 << 18) + (i1 << 12) + ((i2 & 63) << 6) + (i3 & 63);
        var b0 = (buf & (255 << 16)) >> 16;
        var b1 = (i2 == 64) ? -1 : (buf & (255 << 8)) >> 8;
        var b2 = (i3 == 64) ? -1 : (buf & 255);
        decoded[decoded.length] = String.fromCharCode(b0);
        if (b1 >= 0) decoded[decoded.length] = String.fromCharCode(b1);
        if (b2 >= 0) decoded[decoded.length] = String.fromCharCode(b2);
    }
    return decoded.join('');
};


/*
    jquery uuid-generator from http://plugins.jquery.com/files/jquery.uuid.js.txt
*/
/*
Usage 1: define the default prefix by using an object with the property prefix as a parameter which contains a string value; {prefix: 'id'}
Usage 2: call the function jQuery.uuid() with a string parameter p to be used as a prefix to generate a random uuid;
Usage 3: call the function jQuery.uuid() with no parameters to generate a uuid with the default prefix; defaul prefix: '' (empty string)
*/

/*
Generate fragment of random numbers
*/
(function($){
    
    if($.maria === undefined){
        
        $.maria = {};
        
    }
    
    $.maria._uuid_default_prefix = '';
    $.maria._uuidlet = function () {
        return(((1+Math.random())*0x10000)|0).toString(16).substring(1);
    };
    /*
    Generates random uuid
    */
    $.maria.uuid = function (p) {
        if (typeof(p) == 'object' && typeof(p.prefix) == 'string') {
            $.maria._uuid_default_prefix = p.prefix;
        } else {
            p = p || $.maria._uuid_default_prefix || '';
            return( p + $.maria._uuidlet() + $.maria._uuidlet() + "-" + $.maria._uuidlet() + "-" + $.maria._uuidlet() + "-" + $.maria._uuidlet() + "-" + $.maria._uuidlet() + $.maria._uuidlet() + $.maria._uuidlet());
        };
    };
    
})(jQuery);


// ===================
// = Debug Functions =
// ===================
window.log = function () {
    if (typeof(console) !== "undefined") {
        Function.prototype.apply.apply(console.log, [console, arguments]);
    }
};

window.debug = function () {
    if (typeof(console) !== "undefined") {
        Function.prototype.apply.apply(console.debug, [console, arguments]);
    }
};

window.warn = function () {
    if (typeof(console) !== "undefined") {
        Function.prototype.apply.apply(console.warn, [console, arguments]);
    }
};

window.error = function () {
    if (typeof(console) !== "undefined") {
        Function.prototype.apply.apply(console.error, [console, arguments]);
    }
};

window.assert = function () {
    if (typeof(console) !== "undefined") {
        Function.prototype.apply.apply(console.assert, [console, arguments]);
    }
};


// Fallback to save IE & FF from breaking, cause they dont define a console object
(function($){

	if(window.console == null) {
		window.console = {
			log: $.noop,
			debug: $.noop,
			assert: $.noop,
			warn: $.noop,
			error: $.noop
		};
	}

})(jQuery);

