(function () {
    var Routine;
    if (!Routine) {
        Routine = this.Routine = {};
    }

    var $ = this.jQuery;
    Routine.VERSION = "1.0.0.1";

    Routine.CallType = {
        Create: "POST",
        Update: "PUT",
        Delete: "DELETE",
        Read: "GET"
    };

    Routine.DataType = {
        Json: "JSON",
        QueryString: "QueryString"
    }

    //handles data
    //sample usage:
    //var model = Routine.Model.extend({
    //		name: "name",
    // 		age: 55
    //});	
    Routine.Model = function (obj) {
        this.Object = obj;

        this.get = function (field) {
            return this.Object[field];
        }

        this.set = function (field, value) {
            this.Object[field] = value;
        }

        this.pluck = function () {
            return this.Object;
        }

        this.show = function () {
            return JSON.stringify(this.Object);
        }

        this.savePersist = function (key, value) {
            if (this.supportsLocalStorage()) {
                localStorage[key] = (typeof value == 'object') ? JSON.stringify(value) : value;
            }
            else {
                throw new Error("Storage not supported in browser");
            }
        }

        this.retrievePersist = function (key) {
            try {
                return JSON.parse(localStorage[key]);
            }
            catch (e) {
                return localStorage[key];
            }
        }

        this.supportsLocalStorage = function () {
            try {
                return 'localStorage' in window && window['localStorage'] !== null;
            }
            catch (e) {
                return false;
            }
        }
    }

    //handles ajax calls
    //required: dataType, method, model, url
    //sample usage:	
    //var remote = Routine.Remote.extend({
    //		method: Routine.CallType.Read,
    // 		model: "opt=myparam",
    // 		url: "myurl.aspx",
    // 		success: function(data){
    //    		console.log(data);
    // 		},
    // 		error: function(x, t, e){ 
    //    		console.log("error");
    // 		}
    //});
    Routine.Remote = function (obj) {
        if (obj != undefined && obj != null) {
            var type = obj.method;
            var contentType = (obj.dataType == Routine.DataType.Json) ? "application/json" : "";
            var param = (obj.method == Routine.CallType.Create ||
				obj.method == Routine.CallType.Update) ? JSON.stringify(obj.model) : obj.model;			

            var params = {
                url: obj.url,
                type: type,
                data: param,
                async: true,
                success: obj.success,
                error: obj.error
            }
            
            if(obj.timeout > 0){
				window.setTimeout(function(){ $.ajax(params); }, obj.timeout);
			}
			else{
				$.ajax(params);
			}
        }
    }

    //handles list
    //sample usage:
    //var list = Routine.List.extend({});
    //list.add(model1);
    //list.add(model2);
    //console.log(list.each());
    //list1.remove(model1);
    Routine.List = function () {
        this.ObjectList = [];

        this.add = function (param) {
            this.ObjectList.push(param);
        }

        this.remove = function (param) {
            for (var i = 0; i < this.ObjectList.length; i++) {
                if (this.compare(this.ObjectList[i], param)) {
                    this.ObjectList.splice(i, 1);
                }
            }
        }

        this.contains = function (param) {
            var output = false;
            for (var i = 0; i < this.ObjectList.length; i++) {
                if (typeof this.ObjectList[i] != 'object') {
                    if (this.ObjectList[i] == param) {
                        output = true;
                    }
                }
                else {
                    if (this.compare(this.ObjectList[i], param)) {
                        output = true;
                    }
                }
            }

            return output;
        }

        this.each = function () {
            return JSON.stringify(this.ObjectList);
        }

        this.pluck = function (param) {
            return this.ObjectList[param];
        }

        this.count = function () {
            return this.ObjectList.length;
        }

        this.fetch = function () {
            return this.ObjectList;
        }

        this.compare = function (obj1, obj2) {
            for (var i in obj1) {
                if (obj1.hasOwnProperty(i)) {
                    if (!obj2.hasOwnProperty(i)) {
                        return false;
                    }
                    if (obj1[i] != obj2[i]) {
                        return false;
                    }
                }
            }

            for (var i in obj2) {
                if (obj2.hasOwnProperty(i)) {
                    if (!obj1.hasOwnProperty(i)) {
                        return false;
                    }
                    if (obj1[i] != obj2[i]) {
                        return false;
                    }
                }
            }

            return true;
        }
    }

    var modelExtend = function (prototypeProperty, classProperty) {
        var child = inherits(this, prototypeProperty, classProperty);
        var instance = new child();

        Routine.Model.call(instance, prototypeProperty);

        return instance;
    }

    var listExtend = function (prototypeProperty, classProperty) {
        var child = inherits(this, prototypeProperty, classProperty);
        var instance = new child();

        return instance;
    }

    var remoteExtend = function (prototypeProperty, classProperty) {
        var child = inherits(this, prototypeProperty, classProperty);
        var instance = new child();

        Routine.Remote.call(instance, prototypeProperty);

        return instance;
    }

    modelExtend.prototype = new Routine.Model();
    listExtend.prototype = new Routine.List();
    remoteExtend.prototype = new Routine.Remote();
	
    inherits = function (childConstructor, parentConstructor) {
        function tempConstructor() { };

        tempConstructor.prototype = parentConstructor.prototype;
        childConstructor.superClass_ = parentConstructor.prototype;
        childConstructor.prototype = new tempConstructor();
        childConstructor.prototype.constructor = childConstructor;

        return childConstructor;
    }

    Routine.Model.extend = modelExtend;
    Routine.List.extend = listExtend;
    Routine.Remote.extend = remoteExtend;	

	//---- external functions ----
    var getUrl = function (object) {
        if (!(object && object.url)) {
            throw new Error("url must be specified");
        }
        else {
            return object.url;
        }
    }

    var escapeHTML = function (string) {
        return string.replace(/&(?!\w+;)/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
    }

	//handles String.format action similar with c# String.format
    if(!String.prototype.format) {
        String.prototype.format = _StringFormatInline;		
    }	

    if(!String.format) {
        String.format = _StringFormatStatic;		
    }	

    function _StringFormatInline() {
        var txt = this;
        for (var i = 0; i < arguments.length; i++) {
            var exp = new RegExp('\\{' + (i) + '\\}', 'gm');
            txt = txt.replace(exp, arguments[i]);
        }
        return txt;
    }

    function _StringFormatStatic() {
        for (var i = 1; i < arguments.length; i++) {
            var exp = new RegExp('\\{' + (i - 1) + '\\}', 'gm');
            arguments[0] = arguments[0].replace(exp, arguments[i]);
        }
        return arguments[0];
    }
	
	if(!String.prototype.queryString){
		String.prototype.queryString = _GetUrlParam;
	}
	
	if(!String.queryString){
		String.queryString = _GetUrlParam;
	}
	
	function _GetUrlParam() {		
		var name = arguments[0];
		name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
		var regexS = "[\\?&]" + name + "=([^&#]*)";
		var regex = new RegExp(regexS);
		var results = regex.exec(window.location.href);
		if (results == null)
			return "";
		else
			return results[1];		
	}
}).call(this);
