SF.ns('widget', function() {

    return {
        /**
         * PageBrowser constructor
         * 
         * Example:
         *      //Create new instance
         *      var pageBrowser = new SF.widget.PageBrowser('#container');
         * 
         *      //Set listener
         *      SF.on('PageBrowser:update', pageBrowser.update);
         * 
         *      //Update the widget
         *      SF.fire('PageBrowser:update', 87, 1, 20);
         *      
         *      pageBrowser.onChange(function(start, count){
         *          //do something
         *      });
         * 
         * @param {HTMLNode/String} container - Node or CSS selector of the element where page browser should be placed
         */
        PageBrowser: function(container, strings) {
            var container = $(container),
                btnStrings = strings,
                changeCallbackFn = [], //all callback functions for change event
                itemCount, 
                selectedPage = 1, 
                itemsPerPage,
                pagesCount, 
                pageLists, 
                selectedList,
                pageBrowser = this;
            

            /**
             * Sets  widget status to default values
             */
            function reset() {
                selectedPage = 1;
            }


            /**
             * Create widget HTML and put in into container
             */
            function draw() {
                var ulBlock = $('.pb-links', container);
                var prevBtn = $('.pb-prev', container);
                var nextBtn = $('.pb-next', container);
                //empty list
                ulBlock.empty();
                (selectedPage == pagesCount) ? nextBtn.css('visibility', 'hidden') : nextBtn.css('visibility', 'visible');
                (selectedPage == 1) ? prevBtn.css('visibility', 'hidden') : prevBtn.css('visibility', 'visible');
                for(var i = 1 ; i <= pagesCount; i++) {
                    if (i !== selectedPage)
                        ulBlock.append('<a href="#" class="' + i +  '">' + i + '</a>');
                    else
                        ulBlock.append('<strong>' + i + '</strong>')
                }
            }
            
            
            /**
             * Applies all callback functions
             */
            function applyCallBacks (){
                //callbacks
                var start = (selectedPage-1) * itemsPerPage + 1;
                var count = (selectedPage != pagesCount) ? itemsPerPage : itemCount - start + 1;
                var e;
                for(var i = 0; i < changeCallbackFn.length; i++){
                    e = changeCallbackFn[i];
                    if(SF.isFunction(e.action)) {
                        e.action.apply(e.context, [{start: start, count: count, target: 'PageBrowser'}]);
                    }
                }
            }
            
            /**
             * Initialization "prev" and "next" buttons
             */
            function initButtons() {
                container.empty();
                container.append('<span class="pb-prev">' + btnStrings['prev_btn'] + '</span>'+'<span class="pb-links"></span>'+'<span class="pb-next">' + btnStrings['next_btn'] + '</span>');
                $('.pb-prev', container).click(function(event){
                    selectedPage--;
                    draw();
                    applyCallBacks();
                });
                $('.pb-next', container).click(function(event){
                    selectedPage++;
                    draw();
                    applyCallBacks();
                });
                $('.pb-links', container).click(function(event){
                    var pageNum = event.target.className;
                    if (Number(pageNum) == pageNum){
                        selectedPage = parseInt(pageNum);
                        draw();
                        applyCallBacks();
                    }
                    event.preventDefault();
                });
            }
            
            /**
             * Listener of custom event "PageBrowser:update"
             * This method updates state of the widget and re-draws it. 
             * 
             * @param {Object} subscribedData The context of the function
             * @param {Number} itCount
             * @param {Number} iPerPage
             */
            this.update = function(itCount, iPerPage, selPage) {
                //init all needed variables
                
                if(itCount != itemCount || iPerPage != itemsPerPage) {
                    reset();
                }
                
                selectedPage = selPage || selectedPage;
                
                itemCount = itCount;
                itemsPerPage = iPerPage;
                
                pagesCount = Math.ceil(itemCount/itemsPerPage);
                initButtons();
                //draw list
                if (itemCount > itemsPerPage) {
                    draw();
                }
            }
            
            
            /**
             * Public function which allows to set selected page remotely
             * 
             * @param {Number} selPage
             */
            this.setSelectedPage = function(selPage) {
                selectedPage = selPage || selectedPage;
                
                if(selectedPage > pagesCount) {
                    selectedPage = pagesCount;
                }
                
                draw();
            }
            
            
            /**
             * Registers callback wich is called when user changes seleted page.
             * Callback is called with two arguments:
             *      start - start index of visible items
             *      count - amount of visible items 
             * 
             * @param {Function} callback
             * @param {Object} context - callback method context 
             */
            this.onChange = function(callback, context) {
                changeCallbackFn.push({
                    action: callback,
                    context: context || null
                });
            }
        }
    }
    
});
