/**
 * BetManager, maintains the function and UI part below search buttons
 * Paginator and messages are beyound this module's logic
 *
 * This module mainly maintains a collection of checked outcomes(see
 * this.checked_outcomes).
 *
 * Functions:
 *  - Accept and perform search request
 *  - Show/hide all odds
 *  - Odds checking/unchecking
 *  - Conflict detection
 *  - Auto calculating of potential wining amount
 *  - Submit ticket
 *
 * Events:
 *  - ODDS_CHANGED: 3 subtypes
 *    - init: when the search result page is initialized
 *    - user_input: triggered when user check/uncheck the chebox or bet
 *      amount input
 *    - update_odds: when new page of odds are updated
 *  - PLACE_BET_RETURN
 */

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

    var ODDS_NO_OPTION = '1.0';

    function onOddsBoxClick() {
        var bet_manager = nb.ssbs.bet_manager;
        if (bet_manager.is_bet_complete) {
            nb.sbfilter.verifyLogin();
            bet_manager.is_bet_complete = false;
        }
        var valid = false;
        if ($(this).attr('checked')) {
            valid = bet_manager.oddsChecked(this);
        } else {
            valid = bet_manager.oddsUnchecked(this);
        }
        if (valid) {
            $(document).trigger(nb.sbfilter.EventTypes.ODDS_CHANGED,
                    ['user_input', this]);
        }
    }

    function onOddsSpanClick() {
        var checkBox = $(this).prev('input:checkbox');
        if (checkBox.attr('checked')) {
            checkBox.removeAttr('checked');
        } else {
            checkBox.attr('checked', 'checked');
        }
        onOddsBoxClick.apply(checkBox);
    }

    var BetManager = function() {
        this.page_outcomes = {};
        this.checked_outcomes = {};
        this.total_odds = 0;
        this.is_bet_complete = false;
        this.game_ids_from_cookie = [];
        this.readHistory();
        // page element cache, jQuery selector get page element is too slow.
        // Using these cache to decrease search range can imporve performance
        // eg. $('#identifier', this.ticketForm)
        this.oddsArea = $('#simp_selec_odds');
        this.ticketForm = $('#ticketform');
        this.potential_win_div = $('#potential_win', this.ticketForm);
        this.possible_win_div = $('#possible_win', this.ticketForm);
        this.total_odds_span = $('#total_odds', this.oddsArea);
        this.confirm_button = $('#confirm', this.ticketForm);
        this.bet_amount_input = $('#bet_amount', this.ticketForm);
        this.clear_selection_link = $('#clear', this.ticketForm);
    };

    BetManager.prototype = {
        setSearchResults: function(searched_game_id_list) {
            if (searched_game_id_list == undefined) {
                searched_game_id_list = this.game_ids_from_cookie;
            }
            var game_id_list = this.getCheckedGameIdList(searched_game_id_list);
            if (!game_id_list || game_id_list.length <= 0) {
                nb.sbfilter.showMessage('no_game');
            }
            nb.ssbs.paginator.setResults(game_id_list);
        },

        syncCookie: function() {
            var cookie_values = [];
            this.game_ids_from_cookie = [];
            for (var outcome_id in this.checked_outcomes) {
                var outcome = this.checked_outcomes[outcome_id];
                cookie_values.push(outcome.game_id + '_' + outcome_id);
                this.game_ids_from_cookie.push(outcome.game_id);
            }
            cookie_values.sort();
            if (cookie_values.length > 0) {
                var cookie_val = cookie_values.join(':');
                if ($.cookie('outcomes') != cookie_val) {
                    $.cookie('outcomes', cookie_val, {path: '/'});
                }
            } else {
                $.cookie('outcomes', null, {path: '/'});
            }
        },

        readHistory: function() {
            var outcomes_from_cookie = $.cookie('outcomes');
            if (outcomes_from_cookie) {
                var records = outcomes_from_cookie.match(/\d+_\d+/g);
                for (var i = 0; i < records.length; i++) {
                    var outcome_info = records[i].split('_');
                    var game_id = outcome_info[0];
                    var outcome_id = outcome_info[1];
                    this.game_ids_from_cookie.push(game_id);
                    this.checked_outcomes[outcome_id] = {id: outcome_id, game_id: game_id};
                }
            }
        },

        hasStuffInCookie: function() {
            return this.game_ids_from_cookie.length > 0;
        },

        clear: function() {
            this.page_outcomes = {};
        },

        clearCheckedOutcomes: function() {
            this.checked_outcomes = {};
            this.syncCookie();
            this.scanCurrentPage();
        },

        removeBadGame: function(game_obj) {
            for (var outcome_id in this.checked_outcomes) {
                var outcome = this.checked_outcomes[outcome_id];
                if (outcome.game_id == game_obj.id) {
                    delete this.checked_outcomes[outcome_id];
                    this.syncCookie();
                }
            }
        },

        getCheckedGameIdList: function(new_game_id_list) {
            var game_id_list = [];
            var checked_game_dict = {};
            for (var outcome_id in this.checked_outcomes) {
                var outcome = this.checked_outcomes[outcome_id];
                checked_game_dict[outcome.game_id] = 1;
            }

            for (var i = 0; i < new_game_id_list.length; i++) {
                var game_id = new_game_id_list[i];
                if (!(game_id in checked_game_dict)) {
                    game_id_list.push(game_id);
                }
            }

            for (var game_id in checked_game_dict) {
                game_id_list.push(game_id);
            }
            return game_id_list;
        },

        addOutcomes: function(game) {
            this.addOutcome(game, '1');
            this.addOutcome(game, 'X');
            this.addOutcome(game, '2');
        },

        updateCheckedGame: function(game) {
            var attrs = ['1', 'X', '2'];
            for (var i = 0; i < attrs.length; i++) {
                var outcome_row = game.outcomes[attrs[i]];
                if (outcome_row == undefined) {
                    continue;
                }
                var outcome_id = outcome_row[0];
                if (outcome_id in this.checked_outcomes) {
                    this.checked_outcomes[outcome_id] = this.rowToObject(game, outcome_row);
                }
            }
        },

        rowToObject: function(game, outcome_row) {
            return {
                id: outcome_row[0],
                title: outcome_row[1],
                odds: outcome_row[2],
                game_id: game.id
            };
        },

        addOutcome: function(game, t) {
            var outcome_row = game.outcomes[t];
            if (outcome_row == undefined) {
                return;
            }
            var outcome_id = outcome_row[0];
            this.page_outcomes[outcome_id] = this.rowToObject(game, outcome_row);
        },

        oddsChecked: function(checkbox) {
            var outcome_id = $(checkbox).attr('rel');
            var outcome = this.page_outcomes[outcome_id];
            if (outcome != undefined) {
                return this.checkConflict(checkbox, outcome);
            }
            return false;
        },

        oddsUnchecked: function(checkbox) {
            var outcome_id = $(checkbox).attr('rel');
            var outcome = this.checked_outcomes[outcome_id];

            if (outcome == undefined) {
                return false;
            }
            delete this.checked_outcomes[outcome_id];
            this.syncCookie();
            return true;
        },

        scanCurrentPage: function() {
            var manager = this;
            $('#selectionstbl input:checkbox', this.oddsArea).each(function() {
                var outcome_id = $(this).attr('rel');
                var outcome = manager.checked_outcomes[outcome_id];
                if (outcome) {
                    $(this).attr('checked', 'checked');
                } else {
                    $(this).removeAttr('checked');
                }
            });
        },

        refreshTotalOdds: function() {
            this.total_odds = 0;
            for (var outcome_id in this.checked_outcomes) {
                if (this.total_odds == 0) {
                    this.total_odds = 1;
                }
                this.total_odds *= parseFloat(this.checked_outcomes[outcome_id].odds);
            }
            return this.total_odds;
        },

        checkConflict: function(checkbox, new_outcome) {
            var game_id = $(checkbox).parents('tr').attr('rel');
            var game = nb.ssbs.filter_cache.all_options.matches[game_id];
            var checked_outcome_length = 0;
            var conflict_part_name = '';

            for (var outcome_id in this.checked_outcomes) {
                if (outcome_id == new_outcome.id) {
                    continue;
                }
                var checked_outcome = this.checked_outcomes[outcome_id];
                var checked_game = nb.ssbs.filter_cache.all_options.matches[checked_outcome.game_id];
                if (game_id != checked_game.id) {
                    checked_outcome_length ++;
                    var part_id_set = [checked_game.home_id, checked_game.away_id];
                    if (conflict_part_name == '' &&
                            ($.inArray(game.home_id, part_id_set) != -1 ||
                                    $.inArray(game.away_id, part_id_set) != -1)) {
                        conflict_part_name = checked_game.name;
                    }
                } else {
                    // only one outcome can be checked for the same game
                    delete this.checked_outcomes[outcome_id];
                }
            }
            var valid = false;
            if (checked_outcome_length >= nb.sbfilter.OPTIONS.max_num_selection) {
                nb.sbfilter.showMessage('max_selections');
            } else if (conflict_part_name != "") {
                nb.sbfilter.showMessage('team_conflict', conflict_part_name);
            } else {
                this.checked_outcomes[new_outcome.id] = new_outcome;
                valid = true;
            }
            this.syncCookie();
            this.scanCurrentPage();
            return valid;
        },

        clearSelections: function() {
            this.clearCheckedOutcomes();
            this.scanCurrentPage();
            this.initSelectionsInfo();
        },

        preSubmit: function(form_data, obj, options) {
            if (this.confirm_button.sbfilter('isDisabled')) {
                return false;
            } else {
                for (var outcome_id in this.checked_outcomes) {
                    var outcome = this.checked_outcomes[outcome_id];
                    form_data.push({name: 'outcome_info',
                        value: outcome.game_id + '_' + outcome_id});
                }
                this.confirm_button.sbfilter('startLoading');
            }
        },

        initSelectionsInfo: function(identifier, clearBetAmount) {
            if (identifier != undefined)
                $('#identifier', this.ticketForm).val(identifier);
            if (clearBetAmount == undefined || clearBetAmount == true) {
                this.bet_amount_input.val(nb.sbfilter.OPTIONS.zeroString);
                this.possible_win_div.text(nb.sbfilter.formatCurrency(0));
                this.disableTicket();
            }
            this.is_bet_complete = true;
            $(document).trigger(nb.sbfilter.EventTypes.ODDS_CHANGED,
                    ['init']);
        },

        /**
         * show or hide bet amount input according to the switch is_login
         */
        checkLoginStatus: function(is_login) {
            if (is_login) {
                this.bet_amount_input.removeAttr('disabled');
            } else {
                this.bet_amount_input.attr('disabled', 'disabled');
            }
        },

        disableTicket: function() {
            this.potential_win_div.addClass('ticket_disabled');
            this.total_odds_span.addClass('ticket_disabled');
            this.confirm_button.sbfilter('disableCommand');
        },

        enableTicket: function() {
            this.potential_win_div.removeClass('ticket_disabled');
            $('#message_area', this.oddsArea).removeClass('ticket_disabled');
            this.confirm_button.sbfilter('enableCommand');
        },

        updateTotalOdds: function() {
            var total_odds = this.refreshTotalOdds();
            total_odds = total_odds.toFixed(2);
            if (isNaN(total_odds)) {
                total_odds = '0.00';
            }
            this.total_odds_span.text(total_odds);
        },

        showAllOdds: function(show) {
            var odds_span = $('span.odds_span', this.oddsArea);
            odds_span.toggle(show);
        },

        buildSimpleSelectionOdds: function(game, outcome, th_class) {
            var hide = $('#show_all_odds_check', this.oddsArea).attr('checked') ? '' : ' style="display:none;"';
            var comp = null;
            if (outcome) {
                var outSpan = $('<span class="bet_span"/>');
                if (outcome[2] == ODDS_NO_OPTION) {
                    var no_option_span = $('<span class="noOption"/>').text(outcome[1]);
                    comp = outSpan.append(no_option_span);
                } else {
                    comp = outSpan.append($('<input id="outcome_info" name="outcome_info" ' +
                            'type="checkbox"/>')
                            .click(onOddsBoxClick)
                            .attr('rel', outcome[0]))
                            .append($('<span class="odds_span" ' + hide + '/>')
                            .click(onOddsSpanClick)
                            .text(outcome[1]));
                }
            } else {
                comp = $('<span class="bet_span"></span>');
            }
            return comp;
        },

        setOddsPosition: function() {
            $('#selectionstbl th.bet', this.oddsArea).each(function() {
                var index = $('#selectionstbl th', this.oddsArea).index(this);
                var temp_span = $(this).children('div')
                        .wrapInner('<span />').find('span');
                var word_width = ($(this).children('div').width() > temp_span.width()) ?
                        temp_span.width() : $(this).children('div').width();
                var left_width = parseInt($(this).children('div').css('margin-left'));
                if (isNaN(left_width)) {
                    left_width = 0;
                }
                $(this).children('div').text(temp_span.text());
                $('#selectionstbl tr:not(:first)', this.oddsArea).each(function() {
                    var oddsContent = $(this).children().eq(index)
                            .children('span').children().eq(0);
                    var center_place = word_width / 2 + left_width;
                    center_place -= oddsContent.width() / 2;
                    if (oddsContent)
                        oddsContent.css('margin-left', (center_place > 0) ? center_place : 0);
                });
            });
        },

        onPlaceBetComplete: function(response, statusText) {
            this.confirm_button.sbfilter('endLoading');
            if (response.is_logged_out) {
                window.location.reload();
            }
            if (response.error) {
                $('#identifier', this.ticketForm).val(response.identifier);
            } else if (response.success) {
                this.clearCheckedOutcomes();
                nb.sbfilter.showTicketLink(response.ticket_uri);
                window.login.location.reload();
                this.initSelectionsInfo(response.identifier);
            }
        },

        autoCalcPotentialWin: function() {
            var bet_amount = this.bet_amount_input.val();
            bet_amount = bet_amount.replace(',', '.');
            if (bet_amount == '') bet_amount = '0';
            if (isNaN(bet_amount)) {
                this.possible_win_div.html('invalid stake');
            } else {
                var possible_win = parseFloat(bet_amount) * this.total_odds;
                possible_win = nb.sbfilter.formatCurrency(possible_win);
                if (possible_win.length >= 22) {
                    possible_win = possible_win.substr(0, 22);
                }
                this.possible_win_div.html(possible_win);
            }
            this.verifyConfirmButton();
        },

        verifyConfirmButton: function() {
            var possibleWin = this.possible_win_div.html();
            var invalidValue = [nb.sbfilter.formatCurrency(0), 'invalid stake', 'NaN'].join(' ');
            if (invalidValue.indexOf(possibleWin) != -1) {
                this.disableTicket();
            } else {
                this.enableTicket();
            }
        },

        updateOdds: function(game_list, page_size, identifier) {
            this.initSelectionsInfo(identifier, false);
            $('#selectionstbl', this.oddsArea).find('tr:not(:first)').remove();
            this.clear();
            var row_ske = ('<tr class="outcome_set_info">' +
                    '<td class="endingtime"><div></div></td>' +
                    '<td class="sport_icon"></td>' +
                    '<td class="home team"></td>' +
                    '<td class="vs">vs.</td>' +
                    '<td class="away team"></td>' +
                    '<td class="bet home_win"></td>' +
                    '<td class="bet draw"></td>' +
                    '<td class="bet away_win"></td>' +
                    '</tr>');

            for (var i = 0; i < game_list.length; i++) {
                var game = game_list[i];
                if (game.is_fresh) {
                    this.updateCheckedGame(game);
                }
            }

            if (game_list.length < page_size) {
                page_size = game_list.length;
            }
            for (var i = 0; i < page_size; i++) {
                var game = game_list[i];
                this.addOutcomes(game);
                var row = $(row_ske);
                row.attr('rel', game.id);
                $('td.endingtime div', row).text(game.betting_end)
                        .attr('title', game.betting_end);
                $('td.sport_icon', row).attr('title', game.sport + '/' + game.region);
                $('td.home', row).append(this.buildSimpleSelectionTeamName(game.participants[0].name));
                $('td.away', row).append(this.buildSimpleSelectionTeamName(game.participants[1].name));
                $('td.home_win', row).append(this.buildSimpleSelectionOdds(game,
                        game.outcomes['1'],
                        'home_win'));
                $('td.draw', row).append(this.buildSimpleSelectionOdds(game,
                        game.outcomes['X'],
                        'draw'));
                $('td.away_win', row).append(this.buildSimpleSelectionOdds(game,
                        game.outcomes['2'],
                        'away_win'));
                if (game.icon) {
                    $('td.sport_icon', row).append('<img src="' + game.icon + '"/>');
                }

                $('#selectionstbl', this.oddsArea).append(row);
            }

            $('#selectionstbl td div.team', this.oddsArea).sbfilter('cutStringForMultipleLine');
            this.setOddsPosition();
            this.scanCurrentPage();
            $(document).trigger(nb.sbfilter.EventTypes.ODDS_CHANGED, ['update_odds']);
        },

        buildSimpleSelectionTeamName: function (teamName) {
            return $('<div class="team"/>').text(teamName)
                    .attr('title', teamName);
        },

        onReady: function() {
            var bet_manager = this;
            this.possible_win_div.text(nb.sbfilter.formatCurrency(0));
            this.bet_amount_input.val(nb.sbfilter.OPTIONS.zeroString);
            $('#selectionstbl th div', this.oddsArea).sbfilter('cutStringByElementWidth');

            $(document).bind(nb.sbfilter.EventTypes.ODDS_CHANGED, function() {
                bet_manager.updateTotalOdds();
            });
            $(document).bind(nb.sbfilter.EventTypes.ODDS_CHANGED, function() {
                bet_manager.autoCalcPotentialWin();
            });
            $(document).bind(nb.sbfilter.EventTypes.SEARCH, function(evt, game_list) {
                bet_manager.setSearchResults(game_list);
            });
            $(document).bind(nb.sbfilter.EventTypes.BAD_GAME, function(evt, game) {
                bet_manager.removeBadGame(game);
            });

            $(document).bind(nb.sbfilter.EventTypes.RESPONSE_GAME_LIST, function(evt, game_list, page_size, identifier) {
                bet_manager.updateOdds(game_list, page_size, identifier);
            });

            // Ajax load hooks
            var old_confirm_disabled = null;
            $(document).bind(nb.sbfilter.EventTypes.AJAX_LOADER_START, function(event, target) {
                old_confirm_disabled = bet_manager.confirm_button.sbfilter('isDisabled');
                bet_manager.confirm_button.sbfilter('disableCommand');
                bet_manager.bet_amount_input.attr('disabled', 'disabled');
                bet_manager.clear_selection_link.sbfilter('disableCommand');
                $('#selectionstbl input:checkbox', bet_manager.oddsArea).attr('disabled', 'disabled');
            });

            $(document).bind(nb.sbfilter.EventTypes.AJAX_LOADER_STOP, function (event, target) {
                bet_manager.clear_selection_link.sbfilter('enableCommand');
                $('#selectionstbl input:checkbox', bet_manager.oddsArea).removeAttr('disabled');
                bet_manager.checkLoginStatus(fromBridge('authenticated'));

                if (old_confirm_disabled == false) {
                    // Restore confirmed
                    bet_manager.confirm_button.sbfilter('enableCommand');
                    old_confirm_disabled = null;
                }
            });

            $(this.ticketForm).ajaxForm({
                target:'#ticketform',
                success: function(response, status) {
                    $(document).trigger(nb.sbfilter.EventTypes.PLACE_BET_RETURN, [response]);
                    bet_manager.onPlaceBetComplete(response, status);
                },
                beforeSubmit: function(form, obj, options) {
                    return bet_manager.preSubmit(form, obj, options);
                },
                dataType: 'json'
            });

            $('#show_all_odds_check', this.oddsArea).click(function() {
                bet_manager.showAllOdds($(this).attr('checked'));
            });

            this.confirm_button.click(function() {
                if ($(this).sbfilter('isDisabled')) {
                    return;
                }
                $(this).parents('form').submit();
            });

            this.bet_amount_input.keyup(function() {
                $(document).trigger(nb.sbfilter.EventTypes.ODDS_CHANGED,
                        ['user_input', this]);
            }).blur(function() {
                if ($(this).val() == '') {
                    $(this).val(nb.sbfilter.OPTIONS.zeroString);
                }
                $(document).trigger(nb.sbfilter.EventTypes.ODDS_CHANGED,
                        ['user_input', this]);
            });

            this.clear_selection_link.click(function() {
                if ($(this).sbfilter('isDisabled')) {
                    return;
                }
                bet_manager.clearSelections();
            });
        }
    };

    nb.ssbs.BetManager = BetManager;

}});

