if (typeof KMC === 'undefined') KMC={};
(function () {

    Function.prototype.createDelegate = function(obj, args, appendArgs){
        var method = this;
        return function() {
            var callArgs = args || arguments;
            if(appendArgs === true){
                callArgs = Array.prototype.slice.call(arguments, 0);
                callArgs = callArgs.concat(args);
            }else if(typeof appendArgs == "number"){
                callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
                var applyArgs = [appendArgs, 0].concat(args); // create method call params
                Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
            }
            return method.apply(obj || window, callArgs);
        };
    };

    // This id innerHTML plus itself
    jQuery.fn.outerHTML = function (s) {
        return (s) ? $(this).before(s).remove() : jQuery("<p>").append($(this).eq(0).clone()).html();
    };

    //This function prepends zeros to any number to a desired length
    var zero_pad = function (num, digits) {
        num = '' + num; // make sure number is a string.
        while (num.length < digits) {
            num = '0' + num;
        }
        return num;
    };
    var weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
    var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
    
    Date.prototype.printDay = function () {
        return weekdays[this.getDay()];
    };

    Date.prototype.clone = function () {
        return new Date(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes());
    };

    Date.prototype.printDate = function () {
        var day = this.getDate();
        if (day == 1 || day == 21 || day == 31) {
            return day + "st";
        }
        else if (day == 2 || day == 22) {
            return day + "nd";
        }
        else if (day == 3 || day == 23) {
            return day + "rd";
        }
        else {
            return day + "th";
        }
    };
    
        // if the 2nd date is later, the return value will be negative.
    Date.prototype.daysBetween = function(other_date){
        //Set 1 day in milliseconds
        var one_day=1000*60*60*24;
        //Calculate difference btw the two dates, and convert to days
        return Math.ceil((this.getTime()-other_date.getTime())/(one_day));
    };
    
    //returns true if this.date is on a later date then other_date and returns true
    Date.prototype.laterDay = function(other_date) {
        if (this.getFullYear() > other_date.getFullYear()) { return true }
        else if (this.getFullYear() == other_date.getFullYear()) {
            if (this.getMonth() > other_date.getMonth()) { return true }
            else if (this.getMonth() == other_date.getMonth()) {
                return this.getDate() > other_date.getDate();
            }
        }
        return false;
    };
    //Returns true if this.date is the same date as other_date
    Date.prototype.sameDay = function(other_date) {
        return this.getFullYear() === other_date.getFullYear()
            && this.getMonth() === other_date.getMonth()
            && this.getDate() === other_date.getDate();
    };
    
    //Returns true if this.date is earlier then other_date
    Date.prototype.earlierDay = function(other_date) {
        return !this.laterDay(other_date) && !this.sameDay(other_date);
    };
     
    // Within a given month, does a shift occur on this date.
    Date.prototype.showShift = function (shift) {
        return !this.earlierDay(shift.start_date)
                && shift.start_date.getDay() === this.getDay()
                && (shift.end_date === "None" || !this.laterDay(shift.end_date) )
    
    };
    Date.prototype.inputTime = function (name) {
        return "<span class='time-input'><input name='" + name + "_hours' type='text' value='" + zero_pad(this.getHours(), 2) + "'/>:" + "<input name='" + name + "_minutes' type='text' value='" + zero_pad(this.getMinutes(), 2) + "'/></span>";
    };
    Date.prototype.inputDate = function (name) {
        var html = "<span class='date-input'>" + "<select name='" + name + "_month' > ";
        for (var mk in months) {
            html += '<option ' + (mk == this.getMonth() ? 'selected = "selected" ' : '') + 'value = "' + mk + '">' + months[mk] + '</option>';
        }
        html += '</select>';
        html += "<input name='" + name + "_day' type='text' value='" + zero_pad(this.getDate(), 2) + "'/>, " + "<input name='" + name + "_year' type='text' value='" + zero_pad(this.getFullYear(), 2) + "'/>" + "</span>";
        return html;
    };
    Date.prototype.printTime = function () {
        return zero_pad(this.getHours(), 2) + ":" + zero_pad(this.getMinutes(), 2);
    };
    Date.prototype.printTimeShort = function () {
        // never print 0:XX, we want 12:XX
        return (this.getHours()%12 || 12) + ":" + zero_pad(this.getMinutes(), 2);
    };
    Date.prototype.printMonth = function () {
        return months[this.getMonth()];
    };

    
    Date.prototype.print = function () {
        return this.printDay() + ", " + this.printMonth() + " " + this.printDate();
    };

    Date.prototype.si_format = function (opts) {
        opts = opts || {};
        return this.getFullYear() 
            + "-" + zero_pad(this.getMonth() + 1, 2) 
            + "-" + zero_pad(this.getDate(), 2)  
            + (opts.hours !== false ? " " + zero_pad(this.getHours(), 2) + ":"  : '')
            + (opts.minutes !== false ? zero_pad(this.getMinutes(), 2) : '')
            + (opts.seconds !== false ? ":" + zero_pad(this.getSeconds(), 2) : '');
    };

    KMC.UTIL = {
        popup: function (string) {
            $.jGrowl(string, { life: 2000 });
        },
        parse_json: function (rsp) {
            return eval('('+rsp+')');
        },
        input_date_or_null: function (date, exists) {
            if (date == 'None') {
                return 'weekly ' + (exists ? '' : ' <small><a href="#" class="date_type_toggle">(change)</a></small>');
            } else {
                return date.inputDate('end') + (exists ? '' : '<small><a href="#" class="date_type_toggle">(weekly)</a></small>');
            }
        },
        parse_si_date: function(str) {
            var parts = str.match(/(\d\d\d\d)\-(\d\d)\-(\d\d)/);
            if (parts) return new Date(parts[1],parts[2]*1 - 1,parts[3]);
        },
        mod: function (x, y) {
            return ((x % y) + y) % y;
        },

        weekdays: weekdays,
        zero_pad: zero_pad,
        form_value: function (field_name, value) {
            return $('form *[name="' + field_name + '"]').val(value);
        },
        clone: function (obj) {
            if (obj == null || typeof(obj) != 'object') return obj;
            var temp = new obj.constructor(); // changed (TWiCE) {Copied off Internets - //moot// ftw!}
            for (var key in obj)
            temp[key] = clone(obj[key]);
            return temp;
        },

        // Return sorted list of keys
        // @param obj - composite object to sort.
        // @param sort_by - attribute of objects to sort by.
        // @param serializer - key of object method to use for pre-sort serialization.
        sorted_keys: function (obj, sort_by, serializer) {
            var lookup = {},
                sorted = [],
                out = [],
                hash;
            for (var key in obj) {
                    if (serializer) {
                        var hash = obj[key][sort_by][serializer]();
                    }
                    else { // default serializer is the toString method.
                        var hash = obj[key][sort_by] + ''
                    }
                    if (typeof lookup[hash] == 'undefined') {
                        lookup[hash] = [];
                    }
                    lookup[hash].push(key);
                }
            for (hash in lookup) {
                    sorted.push(hash);
                }

            sorted.sort();
            for (var i = 0; i < sorted.length; i++) {
                    for (var j = 0; j < lookup[sorted[i]].length; j++) {
                        out.push(lookup[sorted[i]][j]);
                    }
                }
            return out;
        },

        first_item: function (obj) {
            for (k in obj) {
                return obj[k]
            };
        }
    };


})();

