/**
 * A paginated pool of game selections
 * Member:
 *   A searched game list from filters
 *   A cached game odds info from ajax server
 * Events:
 *  - BAD_GAME
 *  - RESPONSE_GAME_LIST
 */

nb.module({builder: function(nb) {

    var SelectionPaginator = function(page_size) {
        this.page_size = page_size;
        this.current_index = -1;
        this.cached_games = {};
        this.cache_item_life_time = 5 * 60 * 1000; // 5 minutes;
        // page element cache, jQuery selector get page element is too slow.
        // Using these cache to decrease search range can improve performance
        // eg. $('#next', this.paginatorArea)
        this.paginatorArea = $('a.paginator').parent();
        this.next_link = $('#next', this.paginatorArea);
        this.prev_link = $('#prev', this.paginatorArea);
    };

    SelectionPaginator.prototype = {
        /**
         * Cached games whose life is longer than cache_item_life_time minutes
         * will be cleaned
         */
        purgeCache: function(force) {
            var current_date = new Date();
            if(force) {
                this.cached_games = {};
            } else {
                for(game_id in this.cached_games) {
                    var cache  = this.cached_games[game_id];
                    if(current_date - cache.time_stamp > this.cache_item_life_time) {
                        delete this.cached_games[game_id];
                    }
                }
            }
        },

        setResults: function(game_id_list) {
            this.searched_game_list = [];

            for(var i=0; i< game_id_list.length; i++) {
                this.searched_game_list.push({id: game_id_list[i],
                                                 is_bad: false});
            }
            this.purgeCache();
            this.current_index = -this.page_size;
            this.nextPage($('a#search'));
        },

        cleanBadGames: function(start_index, number) {
            var arguments = [start_index, number];
            for(var i=start_index; i< start_index + number && i< this.searched_game_list.length; i++) {
                var game_obj = this.searched_game_list[i];
                if(game_obj.is_bad) {
                    $(document).trigger(nb.sbfilter.EventTypes.BAD_GAME, [game_obj]);
                } else {
                    arguments.push(game_obj);
                }
            }
            this.searched_game_list.splice.apply(this.searched_game_list,
                                                 arguments);
            if(this.searched_game_list.length <= 0) {
                nb.sbfilter.showMessage('no_game');
            }
        },

        /**
         * Return a new list of game from either ajax response or cache
         */
        getResponseGameList: function(request_game_list, response_game_list) {
            var new_game_list = new Array();
            var has_bad_games = false;
            var i = 0;
            for(var j=0; j< request_game_list.length; j++) {
                var game_obj = request_game_list[j];
                game_obj.is_bad = false;
                if(i < response_game_list.length &&
                   game_obj.id == response_game_list[i].id) {
                    var ref_game = response_game_list[i];
                    // Refresh cached games
                    this.cached_games[ref_game.id] = {obj: ref_game,
                                                      time_stamp: new Date()};
                    ref_game.is_fresh = true;
                    new_game_list.push(ref_game);
                    i++;
                } else if (game_obj.id in this.cached_games) {
                    var gobj = this.cached_games[game_obj.id].obj;
                    gobj.is_fresh = false;
                    new_game_list.push(gobj);
                } else {
                    // A game is bad if it is neither contained in ajax
                    // response nor cache.
                    // A bad game should be removed from searched_game_lists
                    // later.
                    game_obj.is_bad = true;
                    has_bad_games = true;
                }
            }
            return {has_bad_games: has_bad_games, game_list: new_game_list};
        },

        getFreshGameIdList: function(game_obj_list) {
            var game_id_list = [];
            var j = 0;
            for(; j< game_obj_list.length; j++) {
                var game_obj = game_obj_list[j];
                if(!(game_obj.id in this.cached_games) &&
                   !game_obj.is_bad) {
                    game_id_list.push(game_obj.id);
                }
            }
            return game_id_list;
        },

        nextPage: function(pressed_button) {
            var pool = this;
            var new_index = this.current_index + this.page_size;
            if(pressed_button == undefined) {
                pressed_button = this.next_link;
            }
            this.sendSearchRequest(new_index, 2 * pool.page_size, function(game_list, identifier) {
                pool.updatePages(new_index, game_list, identifier);
            }, pressed_button);
        },

        updatePages: function(new_index, game_list, identifier) {
            var show_prev = new_index > 0;
            var prev_link = this.prev_link;
            var next_link = this.next_link;

            if(show_prev) {
                // hack here because after #2948 l10n can not include %s
                // but js format can not parse %(key)s
                var prev_matches = nb.sbfilter.LABELS.PREV_MATCHES.replace(/%\(.*?\)s/g, '%s');
                prev_link.text(nb.sbfilter.format(prev_matches, this.page_size));
            }
            var show_next = (this.searched_game_list.length >
                             new_index + this.page_size);
            if(show_next) {
                var next_page_size = Math.min(this.searched_game_list.length -
                                         new_index - this.page_size,
                                              this.page_size);
                var next_matches = nb.sbfilter.LABELS.NEXT_MATCHES.replace(/%\(.*?\)s/g, '%s');
                next_link.text(nb.sbfilter.format(next_matches, next_page_size));
            }

            prev_link.toggle(show_prev);
            next_link.toggle(show_next);

            this.current_index = new_index;
            $(document).trigger(nb.sbfilter.EventTypes.RESPONSE_GAME_LIST,
                                [game_list, this.page_size, identifier]);
        },

        prevPage: function() {
            var pool = this;
            var new_index = this.current_index - this.page_size;
            if(this.current_index == new_index) {
                return;
            }
            this.sendSearchRequest(new_index, 2 * pool.page_size,
                                   function(game_list, identifier) {
                                       pool.updatePages(new_index,
                                                        game_list,
                                                        identifier);
                                   }, this.prev_link);
        },

        sendSearchRequest: function(start_index, number, callback, pressed_button) {
            var request_game_obj_list = this.searched_game_list.slice(start_index,
                                                              start_index + number);
            var pool = this;
            var fresh_game_id_list = this.getFreshGameIdList(request_game_obj_list);
            if(fresh_game_id_list.length == 0) {
                var new_game_list = this.getResponseGameList(request_game_obj_list,
                                                         []).game_list;
                callback(new_game_list);
                return;
            }

            var args = {
                cmd: 'search',
                match: fresh_game_id_list
            };

            pressed_button.sbfilter('getJson', nb.sbfilter.OPTIONS.ajaxURL, args, function(response) {
                nb.sbfilter.verifyLogin();
                var result = pool.getResponseGameList(request_game_obj_list,
                                                      response.game_list);
                if(result.has_bad_games) {
                    // has bad games
                    pool.cleanBadGames(start_index, number);
                }
                callback(result.game_list, response.identifier);
            });
        }
    };

    function initPaginator() {
        $(document).ready(function() {
            nb.ssbs.paginator = new SelectionPaginator(nb.sbfilter.OPTIONS.paginatorPageSize);

            $(document).bind(nb.sbfilter.EventTypes.AJAX_LOADER_START, function(event, target){
                $('a.paginator', nb.ssbs.paginator.paginatorArea).sbfilter('disableCommand');
            });

            $(document).bind(nb.sbfilter.EventTypes.AJAX_LOADER_STOP, function(event, target){
                $('a.paginator', nb.ssbs.paginator.paginatorArea).sbfilter('enableCommand');
            });

            nb.ssbs.paginator.prev_link.click(function() {
                if($(this).sbfilter('isDisabled')) {
                    return;
                }
                nb.ssbs.paginator.prevPage();
            });

            nb.ssbs.paginator.next_link.click(function() {
                if($(this).sbfilter('isDisabled')) {
                    return;
                }
                nb.ssbs.paginator.nextPage();
            });
        });
    }

    nb.ssbs.initPaginator = initPaginator;

}});

