/**
 * 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
 */
function SelectionPaginator(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 imporve performance
    // eg. $('#next', this.paginatorArea)
    this.paginatorArea = $('a.paginator').parent();
    this.next_link = $('#next', this.paginatorArea);
    this.prev_link = $('#prev', this.paginatorArea);
}

/**
 * Cached games whose life is longer than cache_item_life_time minutes
 * will be cleaned
 */
SelectionPaginator.prototype.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];
            }
        }
    }
};

SelectionPaginator.prototype.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'));
};

SelectionPaginator.prototype.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(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) {
        showMessage('no_game');
    }
};

/**
 * Return a new list of game from either ajax response or cache
 */
SelectionPaginator.prototype.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};
};


SelectionPaginator.prototype.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;
};

SelectionPaginator.prototype.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);
};

SelectionPaginator.prototype.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 = LABELS.PREV_MATCHES.replace(/%\(.*?\)s/g, '%s');
        prev_link.text(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 = LABELS.NEXT_MATCHES.replace(/%\(.*?\)s/g, '%s');
        next_link.text(format(next_matches, next_page_size));
    }

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

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

SelectionPaginator.prototype.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);
};

SelectionPaginator.prototype.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.getJson(OPTIONS.ajaxURL, args, function(response) {
        $(document).verifyLogin(response.login == true);
        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);
    });
};

$(document).ready(function() {
    var paginator = new SelectionPaginator(OPTIONS.paginatorPageSize);
    $.fn.paginator = function() {
        return paginator;
    };

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

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

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

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