/**
 * 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
 */

var ODDS_NO_OPTION = '1.0';
function BetManager() {
    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) {
        showMessage('no_game');
    }
    $(document).paginator().setResults(game_id_list);
};

BetManager.prototype.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: '/'});
    }
};

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

BetManager.prototype.hasStuffInCookie = function() {
    return this.game_ids_from_cookie.length > 0;
};

BetManager.prototype.clear = function() {
    this.page_outcomes = {};
};

BetManager.prototype.clearCheckedOutcomes = function() {
    this.checked_outcomes = {};
    this.syncCookie();
    this.scanCurrentPage();
};

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

BetManager.prototype.getCheckedGameIdList = function(new_game_id_list) {
    var game_id_list = [];
    var checked_game_dict = {};
    for(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;
};

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

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

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

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

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

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

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

BetManager.prototype.refreshTotalOdds = function() {
    this.total_odds = 0;
    for(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;
};


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

    for(outcome_id in this.checked_outcomes) {
        if(outcome_id == new_outcome.id){
            continue;
        }
        var checked_outcome = this.checked_outcomes[outcome_id];
        var checked_game = $(document).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 >= OPTIONS.max_num_selection) {
        showMessage('max_selections');
    } else if (conflict_part_name != "") {
        showMessage('team_conflict', conflict_part_name);
    } else {
        this.checked_outcomes[new_outcome.id] = new_outcome;
        valid = true;
    }
    this.syncCookie();
    this.scanCurrentPage();
    return valid;
};

BetManager.prototype.clearSelections = function() {
    this.clearCheckedOutcomes();
    this.scanCurrentPage();
    this.initSelectionsInfo();
};

BetManager.prototype.preSubmit = function(form_data, obj, options) {
    if (this.confirm_button.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.startLoading();
    }
};

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

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

BetManager.prototype.disableTicket = function() {
    this.potential_win_div.addClass('ticket_disabled');
    this.total_odds_span.addClass('ticket_disabled');
    this.confirm_button.disableCommand();
}

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

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

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

function onOddsBoxClick() {
    var bet_manager = $(this).bet_manager();
    if (bet_manager.is_bet_complete) {
        $(document).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(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);
}

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

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

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

BetManager.prototype.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 = formatCurrency(possible_win);
        if (possible_win.length >= 22) {
            possible_win = possible_win.substr(0, 22);
        }
        this.possible_win_div.html(possible_win);
    }
    this.verifyConfirmButton();
};

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

BetManager.prototype.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).cutStringForMultipleLine();
    this.setOddsPosition();
    this.scanCurrentPage();
    $(document).trigger(EventTypes.ODDS_CHANGED, ['update_odds']);
};

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

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

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

    $(document).bind(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(EventTypes.AJAX_LOADER_START, function(event, target){
            old_confirm_disabled = bet_manager.confirm_button.isDisabled();
            bet_manager.confirm_button.disableCommand();
            bet_manager.bet_amount_input.attr('disabled', 'disabled');
            bet_manager.clear_selection_link.disableCommand();
            $('#selectionstbl input:checkbox', bet_manager.oddsArea).attr('disabled', 'disabled');
    });

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

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

    $(this.ticketForm).ajaxForm({
              target:'#ticketform',
              success: function(response, status) {
                  $(document).trigger(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).isDisabled()) {
            return;
        }
        $(this).parents('form').submit();
    });

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

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