/**
 * @author s.sokolenko
 */

Element.addMethods({
    sortBySelector: function(element, selector, sortAsc)
    {
        element = $(element);
        var restoreElement = element.detachFromDOM();

        var options = Object.extend({
                node: "LI"
        }, arguments[3] || {});

        var items = $A(element.select(options.node).sort(function(left, right) {
            if (!Object.isArray(selector)) {
                selector = [selector];
            }

            /* Init cache for text selectors */
            if(Object.isUndefined($(left)._ctext)) {
                $(left)._ctext = new Hash();
            }
            if(Object.isUndefined($(right)._ctext)) {
                $(right)._ctext = new Hash();
            }

            var leftVal = '';
            var rightVal = '';
            var a = 0;
            var b = 0;
            // Iterate through columns to collect their values for further comparison
            // Itaration is performed until collected values are not equal
            selector.each(function(s, i) {
                if (Object.isUndefined($(left)._ctext.get(s))) {
                    $(left)._ctext.set(s, $($(left).select(s)[0]).getText());
                }
                if (Object.isUndefined($(right)._ctext.get(s))) {
                    $(right)._ctext.set(s, $($(right).select(s)[0]).getText());
                }

                leftVal += $(left)._ctext.get(s);
                rightVal += $(right)._ctext.get(s);
                // Try to compare first column values as floats
                if (i == 0) {
                    a = parseFloat(leftVal);
                    b = parseFloat(rightVal);
                    if (!isNaN(a) && !isNaN(b)) {
                        if (a != b) {
                            leftVal = a;
                            rightVal = b;
                            throw $break; // equivalent to using break in a vanilla loop
                        }
                    }
                }

                if (leftVal.toUpperCase() != rightVal.toUpperCase()) throw $break;
            });

            if (typeof(leftVal) == 'string' && typeof(rightVal) == 'string') {
                if (leftVal.toUpperCase() != rightVal.toUpperCase()) {
                    // Compare the case of values if they are equal
                    // otherwise make caseless comparison
                    leftVal = leftVal.toUpperCase();
                    rightVal = rightVal.toUpperCase();
                }
            }

            if (!isNaN(a) && !isNaN(b) && !sortAsc && a == b) {
                return leftVal < rightVal ? 1 : leftVal > rightVal ? -1 : 0;
            }

            return leftVal < rightVal ? -1 : leftVal > rightVal ? 1 : 0;
        }));

        if (!sortAsc) {
            items.reverse();
        }

        element.empty();
        items.each(function(li) {
            element.appendChild(li);
        });

        restoreElement();

        return element;
    },

    getText: function(element) {
        return (element.innerText || element.textContent).toString().strip();
    },

    /**
     * Remove an element and provide a function that inserts it into its original position
     * @return {Function} A function that inserts the element into its original position
     **/
    detachFromDOM: function(element) {
      var parentNode = element.parentNode;
      var nextSibling = element.nextSibling;
      parentNode.removeChild(element);
      return function() {
        if (nextSibling) {
          parentNode.insertBefore(element, nextSibling);
        } else {
          parentNode.appendChild(element);
        }
      };
    }
});
