ko.bindingHandlers.sort = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        var asc = false, value = valueAccessor();
        element.style.cursor = 'pointer';
        element.onclick = function () {
            if (ko.utils.unwrapObservable(value.arr) === null || ko.utils.unwrapObservable(value.arr) == 0)
                return false;
            asc = !asc;
            value.arr.sort(function (left, right) {
                var prop1 = ko.utils.unwrapObservable(left[value.prop]),
                    prop2 = ko.utils.unwrapObservable(right[value.prop]);

                if (prop1 && isFunction(prop1.toLowerCase))
                    prop1 = prop1.toLowerCase();

                if (prop2 && isFunction(prop2.toLowerCase))
                    prop2 = prop2.toLowerCase();

                if (prop1 == prop2)
                    return 0;
                if (asc && prop1 < prop2)
                    return -1;
                if (!asc && prop1 > prop2)
                    return -1;
                return 1;
            });

            if (value.icon)
                alterIconClass($(this));

            function alterIconClass(o) {
                clearSortIcon(o);
                getIcon(o).removeClass(asc ? "icon-arrow-down" : "icon-arrow-up").addClass(asc ? "icon-arrow-up" : "icon-arrow-down");
            }

            function getIcon(o) {
                var icon = o.find("i");
                if (icon.length == 0)
                    o.append(icon = $("<i class=\"pull-right\"></i>"));
                return icon;
            }

            function clearSortIcon(o) {
                o.closest("table").find("i").removeClass("icon-arrow-up icon-arrow-down");
            }

            function isFunction(o) {
                return typeof (o) === "function";
            }

            function isUndefined(o) {
                return typeof (o) === "undefined";
            }
        };
    }
};