/*************************************************
**  jQuery Masonry version 1.3.2
**  Copyright David DeSandro, licensed MIT
**  http://desandro.com/resources/jquery-masonry
**************************************************/
; (function ($) {

    /*!
    * smartresize: debounced resize event for jQuery
    * http://github.com/lrbabe/jquery-smartresize
    *
    * Copyright (c) 2009 Louis-Remi Babe
    * Licensed under the GPL license.
    * http://docs.jquery.com/License
    *
    */
    var event = $.event,
      resizeTimeout;

    event.special.smartresize = {
        setup: function () {
            $(this).bind("resize", event.special.smartresize.handler);
        },
        teardown: function () {
            $(this).unbind("resize", event.special.smartresize.handler);
        },
        handler: function (event, execAsap) {
            // Save the context
            var context = this,
          args = arguments;

            // set correct event type
            event.type = "smartresize";

            if (resizeTimeout) { clearTimeout(resizeTimeout); }
            resizeTimeout = setTimeout(function () {
                jQuery.event.handle.apply(context, args);
            }, execAsap === "execAsap" ? 0 : 100);
        }
    };

    $.fn.smartresize = function (fn) {
        return fn ? this.bind("smartresize", fn) : this.trigger("smartresize", ["execAsap"]);
    };



    // masonry code begin
    $.fn.masonry = function (options, callback) {

        // all my sweet methods
        var msnry = {
            getBricks: function ($wall, props, opts) {
                var hasItemSelector = (opts.itemSelector === undefined);
                if (opts.appendedContent === undefined) {
                    // if not appendedContent
                    props.$bricks = hasItemSelector ?
                $wall.children() :
                $wall.find(opts.itemSelector);
                } else {
                    //  if appendedContent...
                    props.$bricks = hasItemSelector ?
                opts.appendedContent :
                opts.appendedContent.filter(opts.itemSelector);
                }
            },

            placeBrick: function ($brick, setCount, setY, props, opts) {
                // get the minimum Y value from the columns...
                var minimumY = Math.min.apply(Math, setY),
            setHeight = minimumY + $brick.outerHeight(true),
            i = setY.length,
            shortCol = i,
            setSpan = props.colCount + 1 - i;
                // Which column has the minY value, closest to the left
                while (i--) {
                    if (setY[i] == minimumY) {
                        shortCol = i;
                    }
                }

                var position = {
                    left: props.colW * shortCol + props.posLeft,
                    top: minimumY
                };

                // position the brick
                $brick.applyStyle(position, $.extend(true, {}, opts.animationOptions));

                // apply setHeight to necessary columns
                for (i = 0; i < setSpan; i++) {
                    props.colY[shortCol + i] = setHeight;
                }
            },

            setup: function ($wall, opts, props) {
                msnry.getBricks($wall, props, opts);

                if (props.masoned) {
                    props.previousData = $wall.data('masonry');
                }

                if (opts.columnWidth === undefined) {
                    props.colW = props.masoned ?
              props.previousData.colW :
              props.$bricks.outerWidth(true);
                } else {
                    props.colW = opts.columnWidth;
                }

                props.colCount = Math.floor($wall.width() / props.colW);
                props.colCount = Math.max(props.colCount, 1);
            },

            arrange: function ($wall, opts, props) {
                var i;

                if (!props.masoned || opts.appendedContent !== undefined) {
                    // just the new bricks
                    props.$bricks.css('position', 'absolute');
                }

                // if masonry hasn't been called before
                if (!props.masoned) {
                    $wall.css('position', 'relative');

                    // get top left position of where the bricks should be
                    var $cursor = $(document.createElement('div'));
                    $wall.prepend($cursor);
                    props.posTop = Math.round($cursor.position().top);
                    props.posLeft = Math.round($cursor.position().left);
                    $cursor.remove();
                } else {
                    props.posTop = props.previousData.posTop;
                    props.posLeft = props.previousData.posLeft;
                }

                // set up column Y array
                if (props.masoned && opts.appendedContent !== undefined) {
                    // if appendedContent is set, use colY from last call
                    props.colY = props.previousData.colY;

                    /*
                    *  in the case that the wall is not resizeable,
                    *  but the colCount has changed from the previous time
                    *  masonry has been called
                    */
                    for (i = props.previousData.colCount; i < props.colCount; i++) {
                        props.colY[i] = props.posTop;
                    }

                } else {
                    // start new colY array, with starting values set to posTop
                    props.colY = [];
                    i = props.colCount;
                    while (i--) {
                        props.colY.push(props.posTop);
                    }
                }

                // are we animating the rearrangement?
                // use plugin-ish syntax for css or animate
                $.fn.applyStyle = (props.masoned && opts.animate) ? $.fn.animate : $.fn.css;


                // layout logic
                if (opts.singleMode) {
                    props.$bricks.each(function () {
                        var $brick = $(this);
                        msnry.placeBrick($brick, props.colCount, props.colY, props, opts);
                    });
                } else {
                    props.$bricks.each(function () {
                        var $brick = $(this),
                        //how many columns does this brick span
                colSpan = Math.ceil($brick.outerWidth(true) / props.colW);
                        colSpan = Math.min(colSpan, props.colCount);

                        if (colSpan === 1) {
                            // if brick spans only one column, just like singleMode
                            msnry.placeBrick($brick, props.colCount, props.colY, props, opts);
                        } else {
                            // brick spans more than one column

                            //how many different places could this brick fit horizontally
                            var groupCount = props.colCount + 1 - colSpan,
                  groupY = [];

                            // for each group potential horizontal position
                            for (i = 0; i < groupCount; i++) {
                                // make an array of colY values for that one group
                                var groupColY = props.colY.slice(i, i + colSpan);
                                // and get the max value of the array
                                groupY[i] = Math.max.apply(Math, groupColY);
                            }

                            msnry.placeBrick($brick, groupCount, groupY, props, opts);
                        }
                    }); //    /props.bricks.each(function() {
                }  //     /layout logic

                // set the height of the wall to the tallest column
                props.wallH = Math.max.apply(Math, props.colY);
                var wallCSS = { height: props.wallH - props.posTop };
                $wall.applyStyle(wallCSS, $.extend(true, [], opts.animationOptions));

                // add masoned class first time around
                if (!props.masoned) {
                    // wait 1 millisec for quell transitions
                    setTimeout(function () {
                        $wall.addClass('masoned');
                    }, 1);
                }

                // provide props.bricks as context for the callback
                callback.call(props.$bricks);

                // set all data so we can retrieve it for appended appendedContent
                //    or anyone else's crazy jquery fun
                $wall.data('masonry', props);

            }, // /msnry.arrange

            resize: function ($wall, opts, props) {
                props.masoned = !!$wall.data('masonry');
                var prevColCount = $wall.data('masonry').colCount;
                msnry.setup($wall, opts, props);
                if (props.colCount != prevColCount) {
                    msnry.arrange($wall, opts, props);
                }
            }
        };


        /*
        *  let's begin
        *  IN A WORLD...
        */
        return this.each(function () {

            var $wall = $(this),
          props = {};

            // checks if masonry has been called before on this object
            props.masoned = !!$wall.data('masonry');

            var previousOptions = props.masoned ? $wall.data('masonry').options : {},
          opts = $.extend(
                    {},
                    $.fn.masonry.defaults,
                    previousOptions,
                    options
                  ),
          resizeOn = previousOptions.resizeable;

            // should we save these options for next time?
            props.options = opts.saveOptions ? opts : previousOptions;

            //picked up from Paul Irish
            callback = callback || function () { };

            msnry.getBricks($wall, props, opts);

            // if brickParent is empty, do nothing, go back home and eat chips
            if (!props.$bricks.length) {
                return this;
            }

            // call masonry layout
            msnry.setup($wall, opts, props);
            msnry.arrange($wall, opts, props);

            // binding window resizing
            if (!resizeOn && opts.resizeable) {
                $(window).bind('smartresize.masonry', function () { msnry.resize($wall, opts, props); });
            }
            if (resizeOn && !opts.resizeable) {
                $(window).unbind('smartresize.masonry');
            }


        });    //    /return this.each(function()
    };      //    /$.fn.masonry = function(options)


    // Default plugin options
    $.fn.masonry.defaults = {
        singleMode: false,
        columnWidth: undefined,
        itemSelector: undefined,
        appendedContent: undefined,
        saveOptions: true,
        resizeable: true,
        animate: false,
        animationOptions: {}
    };

})(jQuery);
