﻿/* Grid
*************************************************************************************/
(function ($)
{
    $.fn.indigoSlidingGrid = function (options)
    {
        // default configuration properties
        var defaults = {
            name: "default",
            itemWidth: 260,
            itemHeight: 100,
            itemsCanExpand: true,
            horizontalRowsExpanded: 1,
            verticalRowsExpanded: 2,
            cornerSize: 7,
            cornerExtendedSize: 220,
            cornerAnimateSize: 21,
            gutterSize: 20,
            filterFunctionName: ""
        };

        var options = $.extend(defaults, options);

        return this.each(function ()
        {
            var grid = new slidingGrid($(this));

            grid.name = options.name;
            grid.itemWidth = options.itemWidth;
            grid.itemHeight = options.itemHeight;
            grid.itemsCanExpand = options.itemsCanExpand;
            grid.horizontalRowsExpanded = options.horizontalRowsExpanded;
            grid.verticalRowsExpanded = options.verticalRowsExpanded;
            grid.cornerSize = options.cornerSize;
            grid.cornerExtendedSize = options.cornerExtendedSize;
            grid.cornerAnimateSize = options.cornerAnimateSize;
            grid.gutterSize = options.gutterSize;
            grid.filterFunctionName = options.filterFunctionName;
        });
    };
})(jQuery);


/* Sliding Grid
*************************************************************************************/
function slidingGrid(root)
{
    var _this = this;
    _this.grid = $(root);
    _this.name = "default";
    _this.filter = new filter(_this);
    _this.items = new indigo.collection();
    _this.itemsCanExpand = true;
    _this.gutterSize = 20;
    _this.columns = 3;
    _this.animating = false;
    _this.expandedItem = -1;
    _this.itemIsExpanded = false;
    _this.filterFunctionName = "";

    // Item parameters
    _this.itemWidth = 260;
    _this.itemHeight = 100;
    _this.horizontalRowsExpanded = 1;
    _this.verticalRowsExpanded = 2;
    _this.cornerSize = 7;
    _this.cornerExtendedSize = 220;
    _this.cornerAnimateSize = 21;

    _this.initialise();
}
slidingGrid.prototype.initialise = function ()
{
    var _this = this;

    $(".Filter, .Item, .Item-Text, .Item-Blank", _this.grid).each(function (index)
    {
        if (index == 0)
            _this.items.add(new slidingGridFilterItem($(this), _this));
        else
            _this.items.add(new slidingGridItem($(this), _this, false));
    });

    // Calculate the height
    var h = ($(_this.items.items[0].item).height() + _this.gutterSize) * Math.ceil($(".Filter, .Item, .Item-Text, .Item-Blank", _this.grid).length / _this.columns);

    // Remove the non-javascript behaviour.
    $(_this.grid).css({
        "position": "relative",
        "height": h // Items will be positioned absolutely - maintain size
    });

    $(_this.grid).children().each(function ()
    {
        $(this).css({
            "top": $(this).position().top,
            "left": $(this).position().left
        });
    });
    $(_this.grid).children().css({ "position": "absolute", "margin": 0 });

    $(".Clear", _this.grid).remove();

    // Animate the corners
    var current = 1;
    function _animateNext()
    {
        if (current < _this.items.count - 1)
        {
            current++;
            if (!$(_this.items.items[current].item).hasClass("Item-Blank") && !$(_this.items.items[current].item).hasClass("Item-Text"))
                _this.items.items[current].animateCorner(_animateNext);
            else
                _animateNext();
        }
    }

    if (_this.items.count > 1)
        _this.items.items[1].animateCorner(_animateNext);
};
slidingGrid.prototype.itemClicked = function (item)
{
    var _this = this;

    var 
        itemIndex = (item != 0) ? _this.items.indexOf(item) : 0,
        column = itemIndex % _this.columns,
        overlaying = new Object(),
        reverse = false,
        delta = 0;

    _this.animating = true;

    if (_this.filter.expanded)
        column = (itemIndex + 2) % _this.columns;

    if (column == 2)
        reverse = true;

    _this.items.each(function (index)
    {
        if (this)
        {
            if ($(this.item).hasClass("Item-Expanded"))
                this.contract();

            delta = (index > 0 && _this.filter.expanded ? 2 : 0);

            if ((_this.expandedItem == -1 || itemIndex != _this.expandedItem) && itemIndex != 0)
            {
                if (column < _this.columns - 1)
                {
                    if (index == itemIndex + 1)
                        delta += 1;
                    else if (index == itemIndex + _this.verticalRowsExpanded)
                        delta += 3;
                    else if (index > itemIndex)
                        delta += 1 + (2 * _this.verticalRowsExpanded);
                    else
                        delta += 0;
                }
                else
                {
                    if (index == itemIndex - 1)
                        delta += 2;
                    else if (index == itemIndex)
                        delta += 0;
                    else if (index == itemIndex + 1)
                        delta += 3;
                    else if (index > itemIndex)
                        delta += 1 + (2 * _this.verticalRowsExpanded);
                    else
                        delta += 0;
                }
            }

            if (reverse && index == itemIndex)
            {
                $(this.item).animate({
                    top: Math.floor((index + delta) / _this.columns) * (_this.itemHeight + 20),
                    right: 0
                }, 500);
            }
            else
            {
                $(this.item).animate({
                    top: Math.floor((index + delta) / _this.columns) * (_this.itemHeight + 20),
                    left: ((index + delta) % _this.columns) * (_this.itemWidth + 20)
                }, 500);
            }
        }
    });

    // Expand/contract
    if (itemIndex == 0 && _this.filter.expanded)
        item.expand(function () { _this.animating = false; });
    else if (itemIndex == 0 && !_this.filter.expanded)
        item.contract(function () { _this.animating = false; });
    else if (_this.expandedItem != itemIndex)
        item.expand(reverse, function () { _this.animating = false; });
    else
        _this.animating = false;

    if (_this.expandedItem == itemIndex)
        _this.expandedItem = -1;
    else if (itemIndex > -1)
        _this.expandedItem = itemIndex;
};
slidingGrid.prototype.filterClicked = function (fn)
{
    var _this = this;
    _this.itemClicked(_this.items.items[0]);

    if (fn)
        fn();
};
slidingGrid.prototype.setHeight = function (fn)
{
    var _this = this;

    var count = _this.items.count;
    var stop = false;
    _this.items.each(function (index)
    {
        if (!stop && $(_this.items.items[(_this.items.count - 1 - index)].item).hasClass("Item-Blank"))
            count--;
        else
            stop = true; ;
    });

    var h = Math.ceil((((_this.filter.expanded) ? 2 : 0) + count + ((_this.itemIsExpanded) ? 6 : 0)) / _this.columns);
    h = (h * _this.itemHeight) + ((h - 1) * _this.gutterSize);
    $(_this.grid).stop().animate({ height: h }, 500, function ()
    {
        $(_this.grid).css({ "overflow": "visible" });   // JQuery adds overflow hidden during animation. Set visible to stop highlights being clipped.
    });

    if (fn)
        fn();
};
slidingGrid.prototype.hideAll = function (fn)
{
    var _this = this;
    _this.items.each(function (index)
    {
        if (index > 0)
            $(this.item).hide();
    });
    if (fn)
        fn();
};
slidingGrid.prototype.fadeInAll = function (fn)
{
    var _this = this;
    _this.items.each(function (index)
    {
        if (index > 0)
            $(this.item).fadeIn();
    });
    if (fn)
        fn();
};

/* Sliding Grid Item
*************************************************************************************/
function slidingGridItem(element, grid, inserted)
{
    var _this = this;
    _this.id = 0;
    _this.item = element;
    _this.grid = grid;
    _this.inserted = inserted;
    _this.highlightItem = null;

    if (!$(_this.item).hasClass("Item-Blank") && !$(_this.item).hasClass("Item-Text"))
        _this.initialise();
}
slidingGridItem.prototype.initialise = function ()
{
    var _this = this;
    _this.id = $(_this.item).attr("id");

    if (_this.inserted)
    {
        $(_this.item).css({
            "position": "absolute",
            "top": 0,
            "left": -1 * _this.grid.itemWidth,
            "margin": 0
        });
    }

    $(".Overlay", _this.item)
        .removeClass("Overlay")
        .addClass("Overlay-Text")
        .append('<div class="Corner"></div>')
        .children("span").css({ "position": "relative",
            "display": "block",
            "opacity": "0",
            "z-index": "75"
        });

    if (_this.inserted)
        _this.contractCorner();

    // Hover behaviour
    $(_this.item).hoverIntent(function ()
    {
        $(this).addClass("Item-Hover");
        if (!$(this).hasClass("Item-Expanded"))
            _this.expandCorner($(this));
    },
    function ()
    {
        $(this).removeClass("Item-Hover");
        if (!$(this).hasClass("Item-Expanded"))
            _this.contractCorner($(this));
    });

    // Click behaviour
    $(_this.item).children(".Overlay-Text").click(function (evt)
    {
        if (_this.grid.itemsCanExpand)
        {
            evt.preventDefault();
            if (!$(this).parent().hasClass("Item-CannotExpand") && !$(this).hasClass("Item-Expanded") && !_this.grid.animating)
            {
                _this.grid.itemClicked(_this);
            }
        }
    });
}
slidingGridItem.prototype.expand = function (reverse, fn)
{
    var _this = this;
    $(_this.item).addClass("Item-Expanded");
    _this.grid.itemIsExpanded = true;

    $(".Corner", _this.item).fadeOut(200);
    $(_this.item).children(".Overlay-Text").fadeOut(200);

    _this.grid.setHeight();

    if (reverse)
        $(_this.item).addClass("Item-Reversed").css({ "left": "auto", "right": 0 });

    $(_this.item).animate({
        width: (_this.grid.itemWidth * 2) + _this.grid.gutterSize,
        height: (_this.grid.itemHeight * (_this.grid.verticalRowsExpanded + 1)) + (_this.grid.gutterSize * _this.grid.verticalRowsExpanded)
    }, 500, function ()
    {
        $(_this.item).append('<a class="Close"></a>');
        $(".Close", _this.item).animate({ "opacity": 1 }, 200)
                                        .click(function ()
                                        {
                                            _this.grid.itemClicked(_this);
                                        });
        if (fn)
            fn();
    });
}
slidingGridItem.prototype.contract = function (reverse, fn)
{
    var _this = this;
    _this.grid.itemIsExpanded = false;

    $(".Close", _this.item).fadeOut(200).remove();
    $(".Corner, .Overlay-Text", _this.item).show();

    _this.grid.setHeight();

    $(_this.item).animate({
        width: _this.grid.itemWidth,
        height: _this.grid.itemHeight
    }, 500, function ()
    {
        if ($(_this.item).hasClass("Item-Reversed"))
            $(_this.item).removeClass("Item-Reversed").css({ "left": $(_this.item).position().left, "right": "" });

        $(_this.item).removeClass("Item-Expanded");

        if (!$(_this.item).hasClass("Item-Hover"))
            _this.contractCorner();
        if (fn)
            fn();
    });
}
slidingGridItem.prototype.expandCorner = function ()
{
    var _this = this;
    $(".Corner", _this.item).animate({ borderWidth: _this.grid.cornerExtendedSize }, 250)
        .siblings("span").delay(250).animate({ opacity: 1 }, 150);
}
slidingGridItem.prototype.contractCorner = function ()
{
    var _this = this;
    $(".Overlay-Text", _this.item).children("span").animate({ opacity: 0 }, 100)
        .siblings(".Corner").delay(100).animate({ borderWidth: _this.grid.cornerSize }, 250);
}
slidingGridItem.prototype.animateCorner = function (fn)
{
    var _this = this;
    $(".Corner", _this.item).stop().animate({ borderWidth: _this.grid.cornerAnimateSize }, 250, function ()
    {
        $(this).animate({ borderWidth: _this.grid.cornerSize }, 150);
        if (fn)
            fn();
    });
};
slidingGridItem.prototype.remove = function ()
{
    var _this = this;
    _this.grid.items.remove(_this);
    _this.item.fadeOut(250, function ()
    {
        _this.item.remove();
    });
};
slidingGridItem.prototype.highlight = function ()
{
    var _this = this;
    if (!_this.grid.animating)
    {
        $(_this.item).addClass("Item-Highlighted");
        _this.highlightItem = $('<div class="Item-Highlight"></div>').insertAfter(_this.item);
        _this.highlightItem.css({
            top: $(_this.item).position().top - 13,
            left: $(_this.item).position().left - 13
        }).fadeIn(250);
    }
};
slidingGridItem.prototype.unhighlight = function ()
{
    var _this = this;
    $(_this.item).removeClass("Item-Highlighted");
    if (_this.highlightItem);
    {
        $(_this.highlightItem).fadeOut(150, function ()
        {
            $(_this.highlightItem).remove();
            _this.highlightItem = null;
        });
    }
};
slidingGridItem.prototype.hide = function ()
{
    var _this = this;
    $(_this.item).hide();
};
slidingGridItem.prototype.fadeIn = function (duration)
{
    var _this = this;
    $(_this.item).fadeIn(duration);
};

/* Sliding Grid Filter Item
*************************************************************************************/
function slidingGridFilterItem(element, grid)
{
    var _this = this;
    _this.item = element;
    _this.grid = grid;
    _this.categories = new Array();

    _this.initialise();
}
slidingGridFilterItem.prototype.initialise = function ()
{
    var _this = this;
    $(".Box > p > a", _this.item).click(function (evt)
    {
        evt.preventDefault();
        _this.grid.filter.open();
    });
}
slidingGridFilterItem.prototype.expand = function (fn)
{
    var _this = this;
    $(_this.item).addClass("Filter-Expanded");    
    _this.grid.setHeight();
    
    $(_this.item).animate({
        width: $(_this.grid.grid).outerWidth()
    }, 500, function ()
    {
        if (fn)
            fn();
    });
}
slidingGridFilterItem.prototype.contract = function (fn)
{
    var _this = this;
    _this.grid.setHeight();

    $(_this.item).animate({
        width: _this.grid.itemWidth
    }, 500, function ()
    {
        $(_this.item).removeClass("Filter-Expanded");
        if (fn)
            fn();
    });
}

/* Filter
*************************************************************************************/
function filter(grid)
{
    var _this = this;
    _this.overlay = $(".Overlay-Filter");
    _this.modal = null;
    _this.grid = grid;
    _this.sectors = new Array();
    _this.services = new Array();
    _this.activeFilters = new Array();
    _this.activeFilterContainer = $(".Filters", grid.grid);
    _this.expanded = false;

    _this.initialise();
}
filter.prototype.initialise = function ()
{
    var _this = this;
    _this.overlay.detach().appendTo("body");
    _this.modal = $('<div class="Overlay-Modal"></div>').appendTo("body");

    $(".Sectors", _this.overlay).children(".Button").each(function (index)
    {
        _this.sectors[index] = new filterOverlayButton(this, $(".Text", this).text(), $(this).attr("href").replace(/\//gi, ""), false);
    });

    $(".Services", _this.overlay).children(".Button").each(function (index)
    {
        _this.services[index] = new filterOverlayButton(this, $(".Text", this).text(), $(this).attr("href").replace(/\//gi, ""), false);
    });

    $(".Close", _this.overlay).click(function (evt)
    {
        evt.preventDefault();
        _this.close(function () { _this.resetFilters(); });
    });

    $(".ClearSearch", _this.overlay).click(function (evt)
    {
        evt.preventDefault();
        _this.clearFilters();
    });

    $(".Button-Submit", _this.overlay).click(function (evt)
    {
        evt.preventDefault();
        _this.close(function ()
        {
            _this.applyFilters();
        });
    });
};
filter.prototype.open = function ()
{
    var _this = this;
    _this.resetFilters();
    $(_this.modal).css({
        "height": document.body.offsetHeight
    }).fadeTo(250, 0.4, function ()
    {
        $(_this.overlay).css({
            "top": "50%",
            "margin-top": -(_this.overlay.outerHeight() / 2)
        }).fadeIn();
    });
};
filter.prototype.close = function (fn)
{
    var _this = this;
    $(_this.overlay).fadeOut(250, function ()
    {
        if (fn)
            fn();
        $(_this.modal).fadeOut(250);
    });
};
filter.prototype.applyFilters = function ()
{
    var _this = this;
    $(_this.sectors).add(_this.services).each(function ()
    {
        if (this.selected)
        {
            this.active = true;
            if (_this.activeFilters.indexOf(this) == -1)
            {
                _this.activeFilters[_this.activeFilters.length] = this;
                this.button = new activeFilterButton(_this, this);
            }
        }
        else
        {
            this.active = false;
            var i = _this.activeFilters.indexOf(this)
            if (i != -1)
            {
                _this.activeFilters.splice(i, 1);
                this.button.remove();
            }
        }
    });

    if (_this.activeFilters.length > 0)
        _this.expanded = true;
    else
        _this.expanded = false;

    // Delete grid items.
    var current = 1;
    while (_this.grid.items.count != current)
    {
        if ($(_this.grid.items.items[current].item).hasClass("Item-Blank") ||
            $(_this.grid.items.items[current].item).hasClass("Item-Text"))
            current++;
        else
            _this.grid.items.items[current].remove();
    }
    _this.grid.itemIsExpanded = false;

    // FILTER GRID ITEMS
    // Compile filters into a comma delimited string.
    var f = "";
    $(_this.activeFilters).each(function ()
    {
        f += this.value + ",";
    });
    if (f.length > 0)
        f = f.substring(0, f.length - 1).replace(/\#/gi, "").replace(/\./gi, "");

    // Make webservice call
    var service = new indigo.communication.webService(CONTENT_URL + "Service.asmx");
    service.getDataSet(_this.grid.filterFunctionName, "Filter=" + f, true, function (ds)
    {
        if (ds.tables.count > 0)    // Add new items to the grid.
        {
            var pos = 1;
            ds.tables.items[0].rows.each(function ()
            {
                var item = $(this.getValue("HTML")).appendTo(_this.grid.grid);
                _this.grid.items.addAt(pos, new slidingGridItem(item, _this.grid, true));
                pos++;
                if (_this.grid.name == "default" && (pos == 6 || pos == 8 || pos == 13))      // Preserve the position of blank or text items.
                    pos++;
                if (_this.grid.name == "our-work" && pos == 8)
                {
                    if (_this.grid.items[pos + 1] != null)
                        pos++;
                }
                if (_this.grid.name == "our-work" && pos == 9)
                {
                    if (_this.grid.items[pos + 1] != null)
                        pos++;
                }
            });
        }

        // Apply a filter click to the grid - moves the items into place.
        _this.grid.hideAll(function ()
        {
            _this.grid.filterClicked(function ()
            {
                _this.grid.setHeight(function ()
                {
                    _this.grid.fadeInAll(500);
                });
            });
        });
    });
};
filter.prototype.removeFilter = function (item)
{
    var _this = this;
    item.toggle();
    _this.applyFilters();
};
filter.prototype.resetFilters = function ()
{
    var _this = this;
    $(_this.sectors).add(_this.services).each(function ()
    {
        if (this.selected && !this.active ||
            !this.selected && this.active)
            this.toggle();
    });
};
filter.prototype.clearFilters = function ()
{
    var _this = this;
    $(_this.sectors).add(_this.services).each(function ()
    {
        if (this.selected || this.active)
            this.clear();
    });
}
filter.prototype.highlightFilter = function (button)
{
    var _this = this;
    var highlightValue = (button.value).replace(/\#/gi, "").replace(/\./gi, "");

    _this.grid.items.each(function ()
    {
        var item = this;
        if ($(".Categories", this.item).text().indexOf(highlightValue) != -1)
            this.highlight();
    });
};
filter.prototype.unHighlightFilter = function (button)
{
    var _this = this;
    _this.grid.items.each(function ()
    {
        var item = this;
        if ($(this.item).hasClass("Item-Highlighted"))
            this.unhighlight();
    });
};

/* Filter Overlay Button
************************************************************************************
    A button used in the filter overlay. Also holds information on the state
    of the filter.
************************************************************************************/
function filterOverlayButton(element, text, val, isSelected, isActive)
{
    var _this = this;
    _this.element = element;
    _this.text = text;
    _this.value = val;
    _this.selected = isSelected;
    _this.active = isActive;
    _this.button = null;            // Grid item active filter button.

    _this.initialise();
}
filterOverlayButton.prototype.initialise = function ()
{
    var _this = this;
    $(_this.element).click(function (evt)
    {
        evt.preventDefault();
        _this.toggle();
    });
};
filterOverlayButton.prototype.toggle = function ()
{
    var _this = this;
    _this.selected = !_this.selected;
    if (_this.selected)
        $(_this.element).addClass("Button-Pressed");
    else
        $(_this.element).removeClass("Button-Pressed");
};
filterOverlayButton.prototype.clear = function ()
{
    var _this = this;
    _this.selected = false;
    $(_this.element).removeClass("Button-Pressed");
}

/* Active Filter Button
*************************************************************************************
    A button used when the grid item filter is expanded to show which filters
    are currently active.
************************************************************************************/
function activeFilterButton(filter, item)
{
    var _this = this;
    _this.filter = filter;
    _this.item = item;
    _this.element = null;

    _this.initialise();
}
activeFilterButton.prototype.initialise = function ()
{
    var _this = this;
    _this.element = $('<a class="Button Button-Horizontal Button-Small Button-Filter " href="#"><span class="Button-End"><span class="Button-Mid"><span class="Gradient"></span><span class="Icon"></span><span class="Text">' + _this.item.text + '</span><span class="Arrow"></span></span></span></a>');
    $(_this.element).click(function (evt)
    {
        evt.preventDefault();
        _this.filter.removeFilter(_this.item);
    });

    $(_this.element).hover(function ()
    {
        _this.filter.highlightFilter(_this.item);
    },
    function ()
    {
        _this.filter.unHighlightFilter(_this.item);
    });

    $(_this.filter.activeFilterContainer).append(_this.element);
};
activeFilterButton.prototype.remove = function ()
{
    var _this = this;
    $(_this.element).fadeOut(250, function ()
    {
        $(_this.element).remove();
    });

    $(".Item-Highlight", _this.filter.grid.grid).fadeOut(150, function ()
    {
        $(this).remove();
    })
};