(function($) {
    $.fn.verticalLayoutRects = function(options) {
        var defaults = {
            paddingWidth: 24,
            paddingHeight: 24,
            containerLeft: 0,
            marginTop: 0,
            imageWidth: 150,
            bitPadding: 10,
            containerWidth: null,
            handler: null
        };

        var opts = $.extend(defaults, options);

        var container = this;

        var laneHeight = 0;

        var highestInRow = 0;
        var currentLeft = 0;
        var currentTop = opts.marginTop;
        var canvasWidth = opts.containerWidth;
        var currentRow = new Array();

        // A simple greedy algorithm for placing bits vertically
        function layout(items) {
            if (!opts.containerWidth) {
                canvasWidth = container.width();
            }

            for (var i = 0; i < items.length; ++i) {
                var item = $(items[i]);
                if (opts.handler){
                    var template = opts.handler(item);
                }

                var left = currentLeft + opts.paddingWidth;
                var top = currentTop + opts.paddingHeight;

                var remainingWidth = canvasWidth - currentLeft - opts.paddingWidth;

                var dimensions = getDimensions(item);
                var width = dimensions.width;
                var height = dimensions.height;
                
                if (width < remainingWidth) {
                    currentLeft += width + opts.paddingWidth;
                    currentRow.push(item);
                } else {
                    alignRowElements(currentRow, currentTop, highestInRow);

                    currentTop += (highestInRow + opts.paddingHeight);
                    currentLeft = width + opts.paddingWidth;

                    top = currentTop + opts.paddingHeight;
                    left = opts.paddingWidth;

                    highestInRow = 0;
                    currentRow = [item];
                }

                if (height > highestInRow)
                    highestInRow = height;

                placeItem(item, left, top);
            }
            alignRowElements(currentRow, currentTop, highestInRow);
        }

        function alignRowElements(row, rowTop, maxHeight){
            for (rowIndex in row){
                var rowItem = row[rowIndex];
                var dimensions = getDimensions(rowItem);
                rowItem.css("top", rowTop + ((maxHeight - dimensions.height) / 2) + opts.paddingHeight);
            }
        }

        function placeItem(item, left, top) {
            item.css("position", "absolute");
            item.css("left", left);
            item.css("top", top);
            item.appendTo(container);
        }
        
        function getDimensions(item){
            if (item.hasClass("picture-bit") || item.hasClass("collage-bit")){
                $.metadata.setType("attr", "data");
                bit_data = item.metadata().bit_data;
                item_width = bit_data.original_dims.width;
                item_height = bit_data.original_dims.height;
                aspect_ratio = item_width/item_height;
                return {
                    'height': Math.max(Math.ceil(opts.imageWidth/aspect_ratio)+(opts.bitPadding*2), item.height()),
                    'width': Math.max(opts.imageWidth, item.width())
                };
            } else {
                return {
                    'height': item.height(),
                    'width': item.width()
                };
            }
        }

        function resetCanvas() {
            var keep = $(".keepme", container);
            container.empty();
            container.append(keep);

            laneHeight = 0;

            highestInRow = 0;
            currentLeft = 0;
            currentTop = 0;
        }

        function resizeCanvas() {
            var contentsHeight = currentTop + highestInRow + (opts.paddingHeight * 2);
            container.height(Math.max(contentsHeight, laneHeight));
            container.width(canvasWidth);
        }
        
        return {
            update: function(memories) {
                layout(memories);
                resizeCanvas();
                return this;
            },

            reset: function() {
                resetCanvas();
                return this;
            }
        };
    };
})(jQuery);


