/**
 * Resizable Widget: introspect a widget's supported sizes and handle resize
 * events passed from the sneezeguard to the widget
 * @author Seth Kinast
 *
 * options takes the form of an object with two members:
 * heights: array of height classes supported
 * widths: array of width classes supported
 *
 * If an argument is not given, the current dimension of the widget will be
 * saved and used. Make sure your container has a height!
 *
 * Usage: $(".my-widget").resizableWidget(['width-1','width-2'],
 *                                        ['mini','large']);
 */
(function($) {
    $.fn.resizableWidget = function(widths, heights) {
        var w = widths, h = heights, wh=w.concat(h),
            wSizes = [], hSizes = [],
            wClasses = [], hClasses = [];

        /**
         * Strips all known height/width classes from
         * an element. Useful for removing dimensions
         * before applying new class.
         *
         * me: jQuery object
         */
        function stripCurrentDimensionalClasses(me) {
            for(i in wh) {
                if(wh.hasOwnProperty(i)) {
                    me.removeClass(wh[i]);
                }
            }
        }

        return this.each(function() {
            var i, me = $(this),
                WSMContainer = me.parent(),
                WSMWrapper = WSMContainer.parent(),
                WSMCell = WSMWrapper.parent(),
                WSMCanvas = WSMCell.parent(),
                maxWidth = WSMCanvas.width(),
                maxHeight = parseInt(WSMCanvas.css('max-height'));

            // create a dummy container to use for introspecting height and width
            var dummy = $("<div></div>").attr('class', me.attr('class')).appendTo('body');
            stripCurrentDimensionalClasses(dummy);
            for(i=0;i<w.length;i++) {
                dummy.addClass(w[i]); // Add the class to the cell
                var ow = dummy.outerWidth(); // Find the width and save it
                if(ow <= maxWidth) {
                    wSizes.push(ow); // Only allow widths smaller than my canvas
                    wClasses.push(w[i]);
                }
                dummy.removeClass(w[i]);
            }
            for(i=0;i<h.length;i++) {
                dummy.addClass(h[i]); // Add the class to the cell
                var oh = dummy.outerHeight();  // Find the height and save it
                if(isNaN(maxHeight) || oh <= maxHeight) {
                    hSizes.push(oh); // Only allow heights smaller than max canvas height
                    hClasses.push(h[i]);
                }
                dummy.removeClass(h[i]);
            }
            dummy.remove(); // we attached the element to the DOM so we could measure, so remove it after
            // Set some data attributes to show min/max width/height
            WSMContainer.data('is-resizable',true);
            WSMContainer.data('min-width',Math.min.apply(Math,wSizes));
            WSMContainer.data('max-width',Math.max.apply(Math,wSizes));
            WSMContainer.data('min-height',Math.min.apply(Math,hSizes));
            WSMContainer.data('max-height',Math.max.apply(Math,hSizes));

            WSMContainer.bind('widgetResize', function(e) {
                var currentWidth = WSMContainer.outerWidth();
                var currentHeight = WSMContainer.outerHeight();

                // find the absolute difference between sneeze width and all possible widths
                var offsetWidths = $.map(wSizes, function(n) {
                    return Math.abs(n - e.width);
                });
                // The smallest difference is the best match. Find its index, and then
                // look up the class name (which will have the same index)
                var bestWidthMatch = wClasses[offsetWidths.indexOf(Math.min.apply(Math,offsetWidths))];

                // Now repeat, but for height
                var offsetHeights = $.map(hSizes, function(n) {
                    return Math.abs(n - e.height);
                });
                var bestHeightMatch = hClasses[offsetHeights.indexOf(Math.min.apply(Math,offsetHeights))];

                // Finally, apply the new classes to the widget
                stripCurrentDimensionalClasses(me);
                me.addClass(bestWidthMatch).addClass(bestHeightMatch);
                // Update the cell with the dimension data.
                WSMCell.data('width',bestWidthMatch)
                       .data('height',bestHeightMatch);

                // Masonry is the most expensive step computationally. Only trigger a reload if necessary
                if(currentWidth != WSMContainer.outerWidth() || currentHeight != WSMContainer.outerHeight()) {
                    me.trigger($.Event('widgetSizeChanged'))
                      .trigger($.Event('masonryLayoutChanged'));
                }
            });
            WSMContainer.bind('widgetResizeCompleted', function(e) {
                me.trigger($.Event('masonryLayoutChangeCompleted'));
            });
            
            // If a sneezeguard is already present, we should rebuild it to turn on resize functionality
            if(WSMWrapper.children('.wsm-flexbox-sneezeguard').length) {
                WSMWrapper.sneezeguard();
            }
        });
    };
})(jQuery);

/*
 * Add Array.indexof() support for IE. Oh, IE.
 * See: https://github.com/mootools/mootools-core/blob/master/Source/Types/Array.js
 */
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(item, from){
        var length = this.length >>> 0;
        for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){
            if (this[i] === item) return i;
        }
        return -1;
    }
}

