(function($){
    
    with (pagedGallery = function(settings, container){
        this.container = container;

        // required params
        this.jsonBackend = settings.jsonBackend;
        this.itemsOnPage = settings.itemsOnPage;
        this.itemRenderer = settings.itemRenderer;
        this.pagingRenderer = settings.pagingRenderer;
        this.ajaxRenderer = settings.ajaxRenderer;
        this.customRenderer = settings.customRenderer;

        // optional params
        if (settings.data) {
            this.data = settings.data;
        }

        this.init();
    }) {
        // runtime vars
        prototype.container;
        prototype.itemsCount = null;
        prototype.pagesCache = {};
        prototype.pages = 0;
        prototype.page = 0;
        
        // settings
        prototype.jsonBackend;
        prototype.itemsOnPage;
        prototype.itemRenderer;
        prototype.pagingRenderer;
        prototype.ajaxRenderer;
        prototype.customRenderer;
        prototype.data = {};

        prototype.init = function()
        {
            this.changePage(1, function(){
                this.fixItemsPlaceholderSize();
                this.renderPaging();
            });
        }

        prototype.fixItemsPlaceholderSize = function()
        {
            var placeholder = $(this.container).find('.itemsPlaceholder');
            var height = placeholder.height();
            placeholder.css('height', height + 'px');
        }

        prototype.loadPage = function(page, callback)
        {
            var t = this;
            var params = this.data;
            params['itemsOnPage'] = this.itemsOnPage;
            params['page'] = page;

            $.getJSON(this.jsonBackend, params, function(data){
                t.pagesCache[page] = data['items'];
                t.itemsCount = data['total'];
                t.pages = Math.ceil(t.itemsCount / t.itemsOnPage);
                callback.call(t);
            });
        }

        prototype.renderPage = function(page, callback)
        {
            if (this.pagesCache[page]) {
                var placeholder = $(this.container).find('.itemsPlaceholder');

                placeholder.empty();
                var items = this.pagesCache[page];
                for (i in items) {
                    var itemData = items[i];
                    var item = this.itemRenderer(itemData);
                    placeholder.append(item);
                }

                if (callback) {
                    callback.call(this);
                }
            }
        }

        prototype.renderPaging = function()
        {
            var t = this;
            var handler = function(page){
                t.changePage(page);
            }
            this.pagingRenderer(this.pages, handler);
        }

        prototype.renderAjaxDecor = function()
        {
            var placeholder = $(this.container).find('.itemsPlaceholder').empty();

            var ajaxPlaceholder = $('<div></div>')
                .css('position', 'relative')
                .css('width', '100%')
                .css('height', '100%')
                .appendTo(placeholder);
            var pic = this.ajaxRenderer.call(this)
                .css('position', 'absolute')
                .appendTo(ajaxPlaceholder);
                
            var top = (ajaxPlaceholder.height()/2) - (pic.height()/2);
            var left = (ajaxPlaceholder.width()/2) - (pic.width()/2);

            pic.css('top', top).css('left', left);
        }

        prototype.changePage = function(page, callback)
        {
            if (page != this.page) {
                if (!this.pagesCache[page]) {
                    this.renderAjaxDecor();
                    this.loadPage(page, function(){
                        this.changePage(page, callback);
                    });
                } else {
                    this.page = page;
                    this.renderPage(page, callback);
                    this.customRenderer.call(this);
                }
            }
        }
    }
    
    $.fn.pagedGallery = function(settings)
    {
        new pagedGallery(settings, $(this));
    }
})(jQuery);