/// <reference path="jquery.js" />
/*
 ww.jQuery.js  
 West Wind jQuery plug-ins and utilities

 Copyright (c) 2008 Rick Strahl, West Wind Technologies 
 www.west-wind.com

 Licensed under MIT License
 http://en.wikipedia.org/wiki/MIT_License

 Version 0.90.672 - 12/01/08
*/
this.HttpClient = function(opt) {
    var _I = this;

    this.completed = null;
    this.errorHandler = null;
    this.errorMessage = "";
    this.async = true;
    this.evalResult = false;
    this.isMsAjaxJson = false;
    this.contentType = "application/x-www-form-urlencoded";
    this.method = "GET";
    this.timeout = 20000;
    this.headers = {};

    $.extend(_I, opt);

    this.appendHeader = function(header, value) {
        _I.headers[header] = value;
    }
    this.send = function(url, postData, completed, errorHandler) {
        completed = completed || _I.completed;
        errorHandler = errorHandler || _I.errorHandler;

        $.ajax(
           { url: url,
               data: postData,
               type: (postData ? "POST" : _I.method),
               processData: false,  // always process on our own!
               contentType: _I.contentType,
               timeout: _I.timeout,
               dataType: "text",
               global: false,
               async: _I.async,
               beforeSend: function(xhr) {
                   for (var header in _I.headers) xhr.setRequestHeader(header, _I.headers[header]);
               },
               success: function(result, status) {
                   var errorException = null;

                   if (_I.evalResult) {
                       try {
                           result = JSON.parse(result);
                           if (result != null) {
                               if (result.d && result.d.__type)
                                   result = result.d;
                               else if (_I.isMsAjaxJson) {
                                   // Wrapped message: return first property
                                   for (var property in result) {
                                       result = result[property];
                                       break;
                                   }
                               }
                           }
                       }
                       catch (e) { errorException = new CallbackException(e); }
                   }
                   if (errorException) {
                       if (errorHandler)
                           errorHandler(errorException, _I);
                       return;
                   }
                   if (result && (result.isCallbackError || result.iscallbackerror)) {
                       if (errorHandler)
                           errorHandler(result, _I);
                   }
                   if (completed)
                       completed(result, _I);
               },
               error: function(xhr, status) {
                   var res = xhr.responseText;
                   var err = null;                   
                   if (res && res.charAt(0) == '{')
                       var err = JSON.parse(res);
                   if (!err) {
                       if (xhr.status != 200)
                           err = new CallbackException(xhr.status + " " + xhr.statusText);
                       else
                           err = new CallbackException("Unknown Error Response");
                       err.detail = res;
                   }
                   else
                       err = new CallbackException(err); // force error to common format

                   if (errorHandler)
                       errorHandler(err, _I, xhr);
               }
           });
    }
    this.returnError = function(message) {
        var error = new CallbackException(message);
        if (_I.errorHandler)
            _I.errorHandler(error, _I);
    }
}

this.CallbackException = function(message, detail) {
    this.isCallbackError = true;
    if (typeof (message) == "object") {
        if (message.message)
            this.message = message.message;
        else if (message.Message)
            this.message = message.Message;
    }
    else
        this.message = message;

    if (detail)
        this.detail = detail;
    else
        this.detail = null;
}



this.ServiceProxy = function(serviceUrl) {
    /// <summary>
    /// Generic Service Proxy class that can be used to 
    /// call JSON Services generically using jQuery
    /// </summary>
    /// <param name="serviceUrl" type="string">The Url of the service ready to accept the method name</param>
    /// <example>
    /// var proxy = new ServiceProxy("JsonStockService.svc/");
    /// proxy.invoke("GetStockQuote",{symbol:"msft"},function(quote) { alert(result.LastPrice); },onPageError);
    ///</example>        
    var _I = this;
    this.serviceUrl = serviceUrl;

    // Call a wrapped object
    this.invoke = function(method, params, callback, errorCallback, isBare) {
        /// <summary>
        /// Calls a WCF/ASMX service and returns the result.
        /// </summary>    
        /// <param name="method" type="string">The method of the service to call</param>
        /// <param name="params" type="object">An object that represents the parameters to pass {symbol:"msft",years:2}       
        /// <param name="callback" type="function">Function called on success. Receives a single parameter of the parsed result value</parm>
        /// <param name="errorCallback" type="function">Function called on failure. Receives a single error object with Message and StackDetail</parm>
        /// <param name="isBar" type="boolean">Set to true if response is not a WCF/ASMX style wrapped object</parm>

        // Convert input data into JSON using internal code
        var json = JSON.serialize(params);

        // The service endpoint URL MyService.svc/       
        var url = _I.serviceUrl + method;

        var http = new HttpClient(
        { contentType: "application/json",
          evalResult: true,
          isMsAjaxJson: !isBare
        });
        http.send(url, json, callback, errorCallback);
    }
}


//Copyright (c) 2005 JSON.org
//Modifications for MS AJAX by Rick Strahl
//Added dates in object parser,} and ] encoding, MS Date Support
this.JSON = {
    copyright: '(c)2005 JSON.org',
    license: 'http://www.crockford.com/JSON/license.html',
    serialize: function(v) {
        var a = [];
        //	Emit a string.
        function e(s) {
            a[a.length] = s;
        }

        // Convert a value.
        function g(x) {
            var b, c, i, l, v;

            switch (typeof x) {
                case 'string':

                    e('"');
                    if (/["\\\x00-\x1f\x7d\x5d]/.test(x)) {
                        l = x.length;
                        for (i = 0; i < l; i += 1) {
                            c = x.charAt(i);
                            if (c >= ' ' && c != '}' && c != ']') {
                                if (c == '\\' || c == '"')
                                    e('\\');
                                e(c);
                            } else {
                                switch (c) {
                                    case '\b':
                                        e('\\b');
                                        break;
                                    case '\f':
                                        e('\\f');
                                        break;
                                    case '\n':
                                        e('\\n');
                                        break;
                                    case '\r':
                                        e('\\r');
                                        break;
                                    case '\t':
                                        e('\\t');
                                        break;
                                    case '}':
                                        e('\\u007D');
                                        break;
                                    case ']':
                                        e('\\u005D');
                                        break;
                                    default:
                                        c = c.charCodeAt();
                                        e('\\u00' +
		Math.floor(c / 16).toString(16) +
		(c % 16).toString(16));
                                }
                            }
                        }
                    } else {
                        e(x);
                    }
                    e('"');
                    return;
                case 'number':
                    e(isFinite(x) ? x : 'null');
                    return;
                case 'object':
                    if (x) {
                        // RAS: Added Date Parsing
                        if (x.toUTCString)
                            return e('\"\\/Date(' + x.getTime() + ')\\/\"'); // MS Ajax style

                        if (x instanceof Array) {
                            e('[');
                            l = a.length;
                            for (i = 0; i < x.length; i += 1) {
                                v = x[i];
                                if (typeof v != _ud &&
		typeof v != 'function') {
                                    if (b) {
                                        e(',');
                                    }
                                    g(v);
                                    b = true;
                                }
                            }
                            e(']');
                            return;
                        } else if (typeof x.valueOf == 'function') {
                            e('{');
                            l = a.length;
                            for (i in x) {
                                v = x[i];
                                if (typeof v != _ud &&
		typeof v != 'function' &&
		(!v || typeof v != 'object' ||
		typeof v.valueOf == 'function')) {
                                    if (b) {
                                        e(',');
                                    }
                                    g(i);
                                    e(':');
                                    g(v);
                                    b = true;
                                }
                            }
                            return e('}');
                        }
                    }
                    e('null');
                    return;
                case 'boolean':
                    e(x);
                    return;
                default:
                    e('null');
                    return;
            }
        }
        g(v);
        return a.join('');
    },
    // *** RAS Update: RegEx handler for dates ISO and MS AJAX style
    regExDate: function(str, p1, p2, offset, s) {
        str = str.substring(1).replace('"', '');
        var date = str;
        //MS Ajax date
        var regEx = /\/Date(.*)\//;
        if (regEx.test(str)) {
            str = str.match(/Date\((.*?)\)/)[1];
            date = "new Date(" + parseInt(str) + ")";
        }
        else { // ISO Date 2007-12-31T23:59:59Z                                     
            var matches = str.split(/[-,:,T,Z]/);
            matches[1] = (parseInt(matches[1], 0) - 1).toString();
            date = "new Date(Date.UTC(" + matches.join(",") + "))";
        }
        return date;
    },
    parse: function(text, noCheck) {

        if (!noCheck && !(!(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
 text.replace(/"(\\.|[^"\\])*"/g, '')))))
            throw new Error("Invalid characters in JSON parse string.");

        // *** RAS Update:  Fix up Dates: ISO and MS AJAX format support
        var regEx = /(\"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}.*?\")|(\"\\*\/Date\(.*?\)\\*\/")/g;
        //var regEx = /(\"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}.*?\")|(\"\\\/Date\(.*?\)\\\/")/g;
        text = text.replace(regEx, this.regExDate);

        return eval('(' + text + ')');
    },
    parseSafe: function(text) {
        try { return this.parse(text); } catch (e) { return null; }
    }
}

/// <script type="text/html" id="script">
/// <div> 
///   <#= content #>
///   <# for(var i=0; i < names.length; i++) { #>
///   Name: <#= names[i] #> <br/>
///   <# } #>
/// </div>
/// </script>
///
/// var tmpl = $("#itemtemplate").html();
/// var data = { content: "This is some textual content",
///              names: ["rick", "markus"]
/// };
/// $(document.body).html(parseTemplate(tmpl, data));
/// based on John Resig's Micro Templating engine
var _tmplCache = {}
this.parseTemplate = function(str, data) {
    /// <summary>
    /// Client side template parser that uses &lt;#= #&gt; and &lt;# code #&gt; expressions.
    /// and # # code blocks for template expansion.
    /// </summary>    
    /// <param name="str" type="string">The text of the template to expand</param>    
    /// <param name="data" type="var">
    /// Any data that is to be merged. Pass an object and
    /// that object's properties are visible as variables.
    /// </param>    
    /// <returns type="string" />  
    var err = "";
    try {
        var func = _tmplCache[str];
        if (!func) {
            var strFunc =
            "var p=[],print=function(){p.push.apply(p,arguments);};" +
                        "with(obj){p.push('" +
            str.replace(/[\r\t\n]/g, " ")
               .replace(/'(?=[^#]*#>)/g, "\t")
               .split("'").join("\\'")
               .split("\t").join("'")
               .replace(/<#=(.+?)#>/g, "',$1,'")
               .split("<#").join("');")
               .split("#>").join("p.push('")
               + "');}return p.join('');";

            func = new Function("obj", strFunc);
            _tmplCache[str] = func;
        }
        return func(data);
    } catch (e) { err = e.message; }
    return "< # ERROR: " + err.htmlEncode() + " # >";
}



String.prototype.htmlEncode = function() {
    var div = document.createElement('div');
    if (typeof (div.textContent) == 'string')
        div.textContent = this.toString();
    else
        div.innerText = this.toString();
    return div.innerHTML;
}
String.prototype.trimEnd = function(c) {
    return this.replace(/\s+$/, '');
}
String.prototype.trimStart = function(c) {
    return this.replace(/^\s+/, '');
}
String.repeat = function(chr, count) {
    var str = "";
    for (var x = 0; x < count; x++) { str += chr };
    return str;
}
String.prototype.padL = function(width, pad) {
    if (!width || width < 1)
        return this;

    if (!pad) pad = " ";
    var length = width - this.length
    if (length < 1) return this.substr(0, width);

    return (String.repeat(pad, length) + this).substr(0, width);
}
String.prototype.padR = function(width, pad) {
    if (!width || width < 1)
        return this;

    if (!pad) pad = " ";
    var length = width - this.length
    if (length < 1) this.substr(0, width);

    return (this + String.repeat(pad, length)).substr(0, width);
}
String.startsWith = function(str) {
    if (!str) return false;
    return this.substr(0, str.length) == str;
}
String.format = function(frmt, args) {
    for (var x = 0; x < arguments.length; x++) {
        frmt = frmt.replace("{" + x + "}", arguments[x + 1]);
    }
    return frmt;
}
String.prototype.format = function() {
    var a = [this];
    $.merge(a, arguments);
    return String.format.apply(this, a);
}
String.prototype.isNumber = function() {   

    if (this.length == 0) return false;
    if ("0123456789".indexOf(this.substr(0,1)) > -1)
        return true;
    return false;
}
var _monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
Date.prototype.formatDate = function(format) {
    var date = this;
    if (!format)
        format = "MM/dd/yyyy";

    var month = date.getMonth();
    var year = date.getFullYear();

    if (format.indexOf("yyyy") > -1)
        format = format.replace("yyyy", year.toString());
    else if (format.indexOf("yy") > -1)
        format = format.replace("yy", year.toString().substr(2, 2));

    format = format.replace("dd", date.getDate().toString().padL(2, "0"));

    var hours = date.getHours();
    if (format.indexOf("t") > -1) {
        if (hours > 11)
            format = format.replace("t", "pm")
        else
            format = format.replace("t", "am")
    }
    if (format.indexOf("HH") > -1)
        format = format.replace("HH", hours.toString().padL(2, "0"));
    if (format.indexOf("hh") > -1) {
        if (hours > 12) hours -= 12;
        if (hours == 0) hours = 12;
        format = format.replace("hh", hours.toString().padL(2, "0"));
    }
    if (format.indexOf("mm") > -1)
        format = format.replace("mm", date.getMinutes().toString().padL(2, "0"));
    if (format.indexOf("ss") > -1)
        format = format.replace("ss", date.getSeconds().toString().padL(2, "0"));

    if (format.indexOf("MMMM") > -1)
        format = format.replace("MMMM", _monthNames[month]);
    else if (format.indexOf("MMM") > -1)
        format = format.replace("MMM", _monthNames[month].substr(0, 3));
    else
        format = format.replace("MM", month.toString().padL(2, "0"));

    return format;
}
Number.prototype.formatNumber = function(format, option) {
    var num = this;
    var fmt = Number.getNumberFormat();
    if (format == "c") {
        num = Math.round(num * 100) / 100;
        option = option || "$";
        num = num.toLocaleString();
        var s = num.split(".");
        var p = s.length > 1 ? s[1] : '';
        return option + s[0] + fmt.d + p.padR(2, '0');
    }
    if (format.substr(0, 1) == "n") {
        if (format.length == 1)
            return num.toLocaleString()
        var dec = format.substr(1);
        dec = parseInt(dec);
        if (typeof (dec) != "number")
            return num.toLocaleString();
        num = num.toFixed(dec);
        var x = num.split(fmt.d);
        var x1 = x[0];
        var x2 = x.length > 1 ? fmt.d + x[1] : '';
        var rgx = /(\d+)(\d{3})/;
        while (rgx.test(x1))
            x1 = x1.replace(rgx, '$1' + fmt.c + '$2');
        return x1 + x2
    }
    if (format.substr(0, 1) == "f") {
        if (format.length == 1)
            return num.toString();
        var dec = format.substr(1);
        dec = parseFloat(dec);
        if (typeof (dec) != "number")
            return num.toString();
        return num.toFixed(dec);
    }
    return num.toString();
}
Number.getNumberFormat = function(cur) {
    var t = 1000.1.toLocaleString();
    var r = {};        
    r.d = t.substr(5,1);     
    if (r.d.isNumber())
       r.d = t.substr(4,1);           
    r.c = t.substr(1, 1);    
    if (r.c.isNumber())
        r.c = ",";        
    r.s = cur || "$";
    return r;
}
registerNamespace = function(ns) {
    var pts = ns.split('.');
    var stk = window;
    var nsp = "";
    for (var i = 0; i < pts.length; i++) {
        var pt = pts[i];
        if (stk[pt])
            stk = stk[pt];
        else
            stk = stk[pt] = {};
    }
}
$.fn.serializeNoViewState = function() {
    return this.find("input,textarea,select,hidden").not("#__VIEWSTATE,#__EVENTVALIDATION").serialize();
}
$.fn.makeAbsolute = function(rebase) {
    /// <summary>
    /// Makes an element absolute
    /// </summary>    
    /// <param name="rebase" type="boolean">forces element onto the body tag. Note: might effect rendering or references</param>    
    /// </param>    
    /// <returns type="jQuery" /> 
    return this.each(function() {
        var el = $(this);
        var pos = el.position();
        el.css({ position: "absolute",
            marginLeft: 0, marginTop: 0,
            top: pos.top, left: pos.left
        });        
        if (rebase)
            el.remove().appendTo("body");
    });
}
var _ud = "undefined";

//})(jQuery);

