(function ($) {
    $.fn.ellipsis = function () {
        return $(this).each(function () {
            var el = $(this);
            var resetDescription = function (height, originalText) {
                el.html(originalText);
                el.animate({ "height": height }, "normal", null, function () {
                    el.ellipsis();
                });
            }

            if (el.css("overflow") == "hidden") {

                var originalText = el.html();
                var availWidth = el.width();
                var availHeight = el.height();

                var t = $(this.cloneNode(true))
                    .hide()
                    .css({
                        'position': 'absolute',
                        'overflow': 'visible',
                        'max-width': 'none',
                        'max-height': 'none'
                    });
                t.css("height", "auto").width(availWidth);
                el.after(t);

                var fullHeight = t.height();

                var avail = availHeight;
                var test = t.height();
                var foundMin = false, foundMax = false;
                if (test > avail) {
                    //Binary search style trimming of the temp element to find its optimal size
                    var min = 0;
                    var max = originalText.length;
                    while (min <= max) {
                        var trimLocation = (min + max) / 2;
                        var text = originalText.substr(0, trimLocation);
                        t.html(text + "&hellip;");

                        test = t.height();
                        if (test > avail) {
                            if (foundMax)
                                foundMin = true;

                            max = trimLocation - 1;
                            if (min > max) {
                                //If we would be ending decrement the min and regenerate the text so we don't end with a
                                //slightly larger text than there is space for
                                trimLocation = (max + max - 2) / 2;
                                text = originalText.substr(0, trimLocation);
                                t.html(text + "&hellip;");
                                break;
                            }
                        }
                        else if (test < avail) {
                            min = trimLocation + 1;
                        }
                        else {
                            if (foundMin && foundMax && ((max - min) / max < .2))
                                break;
                            foundMax = true;
                            min = trimLocation + 1;
                        }
                    }
                }

                el.html(t.html());
                t.remove();

                var replaceTags = new RegExp(/<\/?[^>]+>/gi);
                el.attr("title", originalText.replace(replaceTags, ''));
            }

        });
    };
})(jQuery);
