/*global jQuery */
(function($) {
    // defines function "carousel" that applies the parameters to each
    // of the matching elements
    $.fn.carousel = function(params) {

        // apply defaults and override with parameters
        params = $.extend({
            manifest: [],
            max_selected: 0,
            multiselect: true,
            selectable: true,
            size: "medium"
        }, params);

        // apply selected attribute
        for(var i = 0; i < params.manifest.length; i++) {
            params.manifest[i] = $.extend({ selected: false }, params.manifest[i]);
        }

        // process each element in the selection and return the whole
        // stack for chaining purposes
        return this.each(function() {
            var carousel = $(this);
            var wrapper = carousel.find('div.wrapper');
            var container = wrapper.find('div.container');
            var elements_per_page = 0;

            /*
            carousel.data("page", 0).css("overflow", "hidden");
*/
            container.children().remove();
            /*
            container.css({
                margin: "0 auto",
                overflow: "hidden"
            });*/

            $(this).data("params", params);

            carousel.find('div.page_forward').unbind("click").click(function() {
                carousel.get(0).nextPage();
                return false;
            }).css("cursor", "pointer");

            carousel.find('div.page_back').unbind("click").click(function() {
                carousel.get(0).previousPage();
                return false;
            }).css("cursor", "pointer");

            carousel.find('div.jump_start').unbind("click").click(function() {
                carousel.get(0).firstPage();
                return false;
            }).css("cursor", "pointer");

            carousel.find('div.jump_end').unbind("click").click(function() {
                carousel.get(0).lastPage();
                return false;
            }).css("cursor", "pointer");

            var back_controls = carousel.find("div.page_back,div.jump_start");
            var forward_controls = carousel.find("div.page_forward,div.jump_end");

            // size controls

            carousel.find('a.thumb_small').unbind("click").click(function() {
                carousel.get(0).setThumbnailSize("small");
                return false;
            });
            carousel.find('a.thumb_medium').unbind("click").click(function() {
                carousel.get(0).setThumbnailSize("medium");
                return false;
            });
            carousel.find('a.thumb_large').unbind("click").click(function() {
                carousel.get(0).setThumbnailSize("large");
                return false;
            });


            /**
             * Creates a new node for the carousel from a resource descriptor
             *
             * @return Object
             */
            this.resourceFactory = function(resource) {
                if(typeof resource != "undefined") {
                    return $('<div class="resource" title="' + resource.name + '" resource_id="' + resource.id + '"><div class="image"><img src="' + resource.thumbnails[params.size] + '" alt="' + resource.name + '" /></div><div class="caption">' + resource.name + '</div></div>').data("resource", resource);
                }
            };

            // ----------------------------
            // | The control's public API |
            // ----------------------------
            this.addAllResources = function (resources) {
                if (!resources || resources.length == 0) {
                    return;
                }

                var params = carousel.data("params");
                var addedResources = new Array();
                var skip = false;
                var resource;

                for (var ridx = 0; ridx < resources.length; ridx++) {
                    skip = false;
                    resource = resources[ridx];

                    for (var i = 0; i < params.manifest.length; i++) {
                        if (resource.id == params.manifest[i].id) {
                            skip = true;
                            break;
                        }
                    }

                    if (!skip) {
                        addedResources.push(resource);
                        params.manifest.push(resource);
                    }
                }

                carousel.data("params", params);
                carousel.trigger("add", [addedResources]);
                carousel.trigger("change");
            };

            this.addResource = function(resource) {
                var params = carousel.data("params");
                for (var i = 0; i < params.manifest.length; i++) {
                    if(resource.id == params.manifest[i].id) {
                        return;
                    }
                }
                params.manifest.push(resource);
                carousel.data("params", params);
                carousel.trigger("add", [[resource.id]]);
                carousel.trigger("change");

                // go to the last page to show the added resource
                this.lastPage();
            };

            this.pushResource = function (resource) {
                var params = carousel.data("params");
                for (var i = 0; i < params.manifest.length; i++) {
                    if (resource.id == params.manifest[i].id) {
                        return;
                    }
                }
                params.manifest.unshift(resource);
                carousel.data("params", params);
                carousel.trigger("add", [[resource.id]]);
                carousel.trigger("change");

                this.firstPage();
            }

            this.removeResource = function(id) {
                var params = carousel.data("params");
                var temp = [];
                for(var i = 0; i < params.manifest.length; i++) {
                    if(params.manifest[i].id != id) {
                        temp.push(params.manifest[i]);
                    }
                }
                params.manifest = temp;
                carousel.data("params", params);
                carousel.trigger("remove", [[id]]);
                carousel.trigger("change");

                // try to stay on the same page when removing, but scroll
                // back if the page is out of range (last single element on page)
                this.setPage($(this).data("page"));
            };

            this.removeAllResources = function() {
                var ids = [];
                var params = carousel.data("params");
                for(var i = 0; i < params.manifest.length; i++) {
                    ids.push(params.manifest[i].id);
                }
                params.manifest = [];
                carousel.data("params", params);
                this.firstPage();

                carousel.trigger("remove", [ids]);
                carousel.trigger("change");
            };

            this.getAllResources = function() {
                return carousel.data("params").manifest;
            };


            this.getResource = function(id) {
                var resources = this.getAllResources();
                for(var i = 0; i < resources.length; i++) {
                    if(resources[i].id == id) {
                        return resources[i];
                    }
                }
                return false;
            };

            this.getSelectedResources = function() {
                var resources = $(this).data("params").manifest;
                var ids = [];
                for(var i = 0; i < resources.length; i++) {
                    if(resources[i].selected) {
                        ids.push(resources[i].id);
                    }
                }
                return ids;
            };

            this.selectResource = function(id) {
                var params = carousel.data("params");
                var mark = false;

                // Deselect all but do not trigger "selectionChange" event.
                if (!params.multiselect) {
                    for (var i = 0; i < params.manifest.length; i++) {
                        params.manifest[i].selected = false;
                    }
                    container.find('div.resource').removeClass("selected");
                    mark = true;
                }
                for (var i = 0; i < params.manifest.length; i++) {
                    if(params.manifest[i].id == id) {
                        params.manifest[i].selected = true;
                        mark = true;
                    }
                }
                container.find('div.resource[resource_id=' + id + ']').addClass("selected");
                carousel.data("params", params);
                if (mark) {
                    carousel.trigger("selectionChange");
                }
            };

            this.selectAllResources = function() {
                var params = $(this).data("params");
                var mark = false;
                if(!params.multiselect) {
                    for(var i = 0; i < params.manifest.length; i++) {
                        if(params.manifest[i].selected !== true) {
                            mark = true;
                        }
                        params.manifest[i].selected = true;
                    }
                    container.find('div.resource').addClass("selected");
                    if(mark) {
                        carousel.triger("selectionChange");
                    }
                }
            };

            this.deselectResource = function(id) {
                var params = carousel.data("params");
                for(var i = 0; i < params.manifest.length; i++) {
                    if(params.manifest[i].id == id) {
                        params.manifest[i].selected = false;
                        carousel.trigger("selectionChange");
                    }
                }
                carousel.data("params", params);
                container.find('div.resource[resource_id=' + id + ']').removeClass("selected");
            };

            this.deselectAllResources = function() {
                var params = carousel.data("params");
                var mark = false;
                for(var i = 0; i < params.manifest.length; i++) {
                    if(params.manifest[i].selected !== false) {
                        mark = true;
                    }
                    params.manifest[i].selected = false;
                }
                container.find('div.resource').removeClass("selected");
                if(mark) {
                    carousel.trigger("selectionChange");
                }
            };

            this.setThumbnailSize = function(size) {
                if(/^small|medium|large$/.test(size.toString())) {
                    var params = carousel.data("params");
                    params.size = size;
                    carousel.data("params", params);

                    container.removeClass("large").removeClass("medium").removeClass("small").addClass(size);
                    carousel.find("a.act").removeClass("act");
                    carousel.find("a.thumb_" + size).addClass("act");

                    // recalculate the space a single element takes
                    var element_size = this.getElementSize();
                    elements_per_page = Math.floor(wrapper.width() / element_size);
                    container.css({
                        width: elements_per_page * element_size + "px"
                    });
                    this.setPage(0);
                }
            };

            this.getParameters = function() {
                return carousel.data("params");
            };

            this.getElementSize = function() {
                var e = this.resourceFactory({ name: "dummy", thumbnails: { small: "", medium: "", large: "" }, id: "dummy" });
                var size = e.appendTo(container).horizontalClearing();
                e.remove();
                return size;
            };

            this.nextPage = function() {
                this.setPage(carousel.data("page") + 1);
            };

            this.previousPage = function() {
                this.setPage(carousel.data("page") - 1);
            };

            this.firstPage = function() {
                this.setPage(0);
            };

            this.lastPage = function() {
                this.setPage(Math.floor(carousel.data("params").manifest.length / elements_per_page));
            };


            this.setPage = function(page) {
                var resources = carousel.data("params").manifest;
                var max_page = Math.max(0, Math.ceil(resources.length / elements_per_page) - 1);

                // calculate a valid page
                page = (page > max_page)? page = max_page: page;
                page = (page < 0)? 0: page;
                carousel.data("page", page);

                // remove all child elements
                container.children().remove();

                // start adding elements
                for(var i = page * elements_per_page; (i < resources.length && i < (page + 1) * elements_per_page); i++) {
                    var element = this.resourceFactory(resources[i]);
                    // Blank background hack for items with id == -1
                    if (element.attr('resource_id') == -1) {
                        element.children('div.image:first').css('background-image', 'none');
                    }
                    container.append(element);

                    if(resources[i].selected === true) {
                        element.addClass("selected");
                    }
                    element.data("resource", resources[i]);
                }

                $('div.resource', container).click(function() {
                    var resource = $(this).data("resource");
                    if(resource.selected) {
                        carousel.get(0).deselectResource(resource.id);
                    } else {
                        carousel.get(0).selectResource(resource.id);
                    }
                }).css({
                    cursor: "pointer"
                });

                // if it's the last or first page, hide the appropriate controls
                forward_controls.css("visibility", "visible");
                back_controls.css("visibility", "visible");
                if(page == 0) {
                    back_controls.css("visibility", "hidden");
                }
                if(page == max_page) {
                    forward_controls.css("visibility", "hidden");
                }
            };

            this.redraw = function() {
                if (carousel.is(":visible")) {
                    carousel[0].setThumbnailSize(carousel.data("params").size);
                }
            };

            // initialize the component
            this.setThumbnailSize(params.size);

        });
    };
})(jQuery);