function sort_by(arr, key) {

    var sort_f = function(a, b) {
        return a[key] < b[key] ? -1 : 1;
    }
    arr.sort(sort_f);
}

function sort_markets(a, b) {
    return a.marketTypeOrdinalPos - b.marketTypeOrdinalPos;
}

function sort_outcomes(a, b) {
    return a.ordinalPosition - b.ordinalPosition;
}

var row_style_counter = 0;
function row_style_cycle()
{
    return ((row_style_counter=(row_style_counter+1)%2)) ? "" : " t-alt";
}

function market_compact_key(event_, market)
{
    return 'e' + event_.eventId + '-m' + market.marketTypeId + '-' + market.marketTypeDescription;
}


// TODO: cycle

function price_text(outcome)
{
    var text = '<a onclick="new Ajax.Request(\'/' + offside_language + '/web/add_to_slip?description=' + encodeURI(outcome.outcomeDescription) + '&outcome_id=' + outcome.outcomeId + '&period=0&pointadjustment_id=-1&price_decimal=' + outcome.formattedPrice + '&price_id=' + outcome.priceId + '\', {asynchronous:true, evalScripts:true, onComplete:function(request){Element.hide(\'spinner\')}, onLoading:function(request){Element.show(\'spinner\')}}); return false;" href="#">' + outcome.formattedPrice + '</a>';
    return text;
}

function price_spread(outcome)
{
    var text =
        '<span style="color:red;">'
        + (outcome.spread == "" ? "" : '[' + outcome.spread + (outcome.spread2 == "" ? "" : ','+outcome.spread2) + ']')
        + '</span>'
        + '<a onclick="new Ajax.Request(\'/' + offside_language + '/web/add_to_slip?description=' + encodeURI(outcome.outcomeDescription) + '&outcome_id=' + outcome.outcomeId + '&period=0&pointadjustment_id=-1&price_decimal=' + outcome.formattedPrice + '&price_id=' + outcome.priceId + '\', {asynchronous:true, evalScripts:true, onComplete:function(request){Element.hide(\'spinner\')}, onLoading:function(request){Element.show(\'spinner\')}}); return false;" href="#">' + outcome.formattedPrice + '</a>';
    return text;
}

function buypoints_combo(outcome)
{
    if (outcome.pointAdjustments.length <= 1)
        return "";

    var text = '<select id="' + outcome.outcomeId + '" name="' + outcome.outcomeId + '" onClick="getPointAdjustment(this); return false;" class="buypoints_combo" style="width:95px;margin:0px 0pt 0pt;float:right;">';
    for (var i=0; i<outcome.pointAdjustments.length; ++i) {
        var adj = outcome.pointAdjustments[i];

        text += '<option id="' + [adj.pointAdjustmentId, adj.pointAdjustmentPrice, adj.pointAdjustmentSpread, adj.priceId, outcome.outcomeDescription, outcome.outcomeId, offside_language].join(';') + '"'
            + (parseInt(adj.pointAdjustmentId) < 0 ? ' selected="selected">' : '>')
            + adj.pointAdjustment
        + '</option>';
    }

    text += '</select>';

    return text;
}

function default_buypoints_row_contents(outcome)
{
    var adj = outcome.pointAdjustments.filter( 'parseInt(_.pointAdjustmentId)<0'.lambda() )[0];
    return
        '<div class="' + (outcome.pointAdjustments.length > 1 ? "odds-buypoints-cell" : "odds-cell") + '">'
        + buypoints_combo(outcome) 
        + '<div class="buypoints_div" style="color:red;float:right;padding-right:5px;" id="_OUTCOMESPREAD_' + outcome.pointAdjustments[0].priceId + '">';
        + (adj ? '[' + adj.pointAdjustmentSpread + '] <a href="#" onclick="javascript:addPointAdjustmentToBetSlip(\'' + [adj.pointAdjustmentId, adj.pointAdjustmentPrice, encodeURI(outcome.outcomeDescription), outcome.outcomeId, outcome.priceId, offside_language].join(';') + '\');">' + adj.pointAdjustmentPrice + '</a>' : '')
        + '</div></div>';
        /*for (var i=0; i<outcome.pointAdjustments.length; ++i) {
            var adj = outcome.pointAdjustments[i];

            if (parseInt(adj.pointAdjustmentId) < 0)
                text += '[' + adj.pointAdjustmentSpread + '] <a href="#" onclick="javascript:addPointAdjustmentToBetSlip(\'' + [adj.pointAdjustmentId, adj.pointAdjustmentPrice, encodeURI(outcome.outcomeDescription), outcome.outcomeId, outcome.priceId, offside_language].join(';') + '\');">' + adj.pointAdjustmentPrice + '</a>';
        }*/
}

function default_withdrawn_row(outcome)
{
    var text =
    '<tr class="event_detail' + row_style_cycle() + '">' + "\n"
    + '<td class="event_detail t-lcol"><span class="outcome_descr">' + outcome.outcomeDescription + '</span></td>'
    + '<td class="event_detail t-rcol"><span class="odds-cell" id="<%="odds_id_' + outcome.outcomeId + '">' + outcome.formattedPrice + '</span></td>'
    + '</tr>' + "\n";
    return text;
}

function default_buypoints_row(outcome)
{
    var text =
    '<tr class="event_detail' + row_style_cycle() + '">' + "\n"
        + '<td class="event_detail t-lcol"><span class="outcome_descr">' + outcome.outcomeDescription + '</span></td>'
        + '<td class="event_detail t-rcol">' + default_buypoints_row_contents(outcome) +'</td>'
     +'</tr>' + "\n";
    return text;
}

function default_display_row(outcome)
{
    var text =
    '<tr class="event_detail' + row_style_cycle() + '">' + "\n"
        + '<td class="event_detail t-lcol"><span class="outcome_descr">' + outcome.outcomeDescription + '</span></td>'
        + '<td class="event_detail t-rcol">'
            + '<span class="odds-cell" id="odds_id_' + outcome.outcomeId + '">'
            + ( outcome.hidden ? "" : outcome.spread != "" ? price_spread(outcome) : price(outcome) )
            + '</span>'
    + '</td></tr>' + "\n";
    return text;
}

function wdw_coupon(event_, market)
{
    var text;

    /*<!-- thrown away neat, nice, beautiful not-IE-friendly layout :(
    <div class="table" style="width:100%">
        <div class="tr row alt">
            <div class="td lcol"><span class="period_descr"><%=period["periodDescription"]%></span></div>
            <div class="td t-rcol"><span class="odds-cell"><span class="odds"><%="Home".t%></span></span></div>
            <div class="td t-rcol"><span class="odds-cell"><span class="odds"><%="Draw".t%></span></span></div>
            <div class="td t-rcol"><span class="odds-cell"><span class="odds"><%="Away".t%></span></span></div>
        </div>
    </div>
    -->*/

    sort_by(market.outcomes, "ordinalPosition");
    text = 
    '<table style="width:100%">' + "\n"
        + '<tr class="event_detail t-alt">' + "\n"
            + '<td class="event_detail t-lcol"><span class="period_descr">' + market.marketPeriodDescription + '</span></td>'
            + '<td class="event_detail t-rcol"><span class="odds-cell"><span class="odds">' + offside_translations["Home"] + '</span></span></td>'
            + '<td class="event_detail t-rcol"><span class="odds-cell"><span class="odds">' + offside_translations["Draw"] + '</span></span></td>'
            + '<td class="event_detail t-rcol"><span class="odds-cell"><span class="odds">' + offside_translations["Away"] + '</span></span></td>'
        + '</tr>' + "\n"

        + '<tr class="event_detail">' + "\n"
            + '<td class="event_detail t-lcol"><span class="outcome_descr">' + event_.eventDescription + '</span></td>';

    for(var i=1;i<4;++i) {
        var outcome = market.outcomes.filter( ('i.ordinalPosition=='+i).lambda() )[0];

        text += '<td class="event_detail t-rcol"><span class="odds-cell" id="odds_id_' + outcome.outcomeId + '">';
        if (!outcome.hidden)
            text += price_text( outcome );
        text += '</span></td>';
    }

    text += '</tr></table>' + "\n";

    return text;
}

function handicap_coupon(event_, market)
{
    var text;

    text = 
    '<table style="width:100%">' + "\n"
        + '<tr class="event_detail t-alt">' + "\n"
            + '<td class="event_detail t-lcol"><span class="period_descr">' + market.marketPeriodDescription + '</span></td>'
            + '<td class="event_detail t-rcol"><span class="odds-cell"><span class="odds">' + offside_translations["Home"] + '</span></span></td>'
            + (market.outcomes.length == 3 ? 
              '<td class="event_detail t-rcol"><span class="odds-cell"><span class="odds">' + offside_translations["Draw"] + '</span></span></td>' : '')
            + '<td class="event_detail t-rcol"><span class="odds-cell"><span class="odds">' + offside_translations["Away"] + '</span></span></td>'
            + (event_._is_meeting ?
              '<td class="event_detail t-rcol-market" style="width:40px"></td>' : '')
        + '</tr>' + "\n"

        + '<tr class="event_detail">' + "\n"
            + '<td class="event_detail t-lcol"><span class="outcome_descr">' + event_.eventDescription + '</span></td>';

        for (var i=0; i<market.outcomes.length; ++i) {
            var outcome = market.outcomes[i];
            text += '<td class="event_detail t-rcol">';
                if (!outcome.hidden) {
                    if (outcome.pointAdjustments.length > 0)
                        text += default_buypoints_row_contents(outcome);
                    else
                        text += '<span class="odds-cell" id="odds_id_' + outcome.outcomeId + '">' + price_spread(outcome) + '</span>';
                }
            text += '</td>';
        }

        if (event_._is_meeting) {
            text += '<td class="event_detail t-rcol-market" style="width:40px"><span class="odds-cell">';
            if (event.markets.length > 1)
                text += 'link_to "+#{event["marketList"].size - 1}", event_detail_path(:event_path_id => params[:event_path_id], :event_id => event["eventId"], :period => 0) %>';
            text += '</span></td>';
        }


    text += '</tr></table>' + "\n";

    return text;
}

function default_coupon(event_, market)
{
    var text;

    text = 
    '<table style="width:100%">' + "\n"
        + '<tr class="event_detail t-alt">' + "\n"
            + '<td class="event_detail t-lcol"><span class="period_descr">' + market.marketPeriodDescription + '</span></td>'
            + '<td class="event_detail t-rcol"><span class="odds-cell"><span class="odds">' + offside_translations["Odds"] + '</span></span></td>'
        + '</tr>' + "\n";

    if (!market._dont_sort_outcomes)
        sort_by(market.outcomes, Functional.every( '_.ordinalPosition!=0', market.outcomes) ? 'ordinalPosition' : 'priceDecimal');

    for (var i=0; i<market.outcomes.length; ++i) {
        var outcome = market.outcomes[i];

        if (!outcome.hidden) {
            if (!outcome.withdrawn)
                text += default_withdrawn_row(outcome);
            else {
                if (outcome.pointAdjustments.length > 0)
                    text += default_buypoints_row(outcome);
                else
                    text += default_display_row(outcome);
            }
        }
    }

    text += '</table>' + "\n";

    return text;
}

function get_market_coupon_name(marketTypeId)
{
        switch (marketTypeId) {
            case 1:
                return wdw_coupon;
            case 103:
            case 107:
            case 111:
            case 115:
            case 12:
            case 14:
            case 1503:
            case 1603:
            case 17:
            case 1703:
            case 1753:
            case 202:
            case 222:
            case 232:
            case 242:
            case 244:
            case 252:
            case 294:
            case 295:
            case 296:
            case 297:
            case 298:
            case 37:
            case 47:
            case 63:
            case 67:
            case 71:
            case 75:
            case 79:
            case 83:
            case 87:
            case 9:
            case 91:
            case 95:
            case 99:
                return handicap_coupon;
        }
        return default_coupon;
}

function event_detail_message(container, text)
{
    container.update('<div class="content-toolbar-coupon"><span class="toolbar-text">&nbsp; ' + text + '</span></div>');
}

function compact_market(market)
{
    if ( [27, 28].filter( ('_=='+market.marketTypeId).lambda() ).length )
        market._dont_sort_outcomes = true;
}

function cancel_event_compact(event_)
{
    event_._cancel_compact = true;

    for (var k in event_._compact_markets) {
        var markets = event_._compact_markets[k];

        for (var m=0;m<event_.markets.length;++m) {
            var market = event_.markets[m];

            delete market._col0_title;
            delete market._col1_title;
            delete market._col2_title;
            delete market._coupon_name;
            delete market._row_title;
        }
    }
}

function compact_event(event_)
{
    var is_market = (arguments.length > 1 ? arguments[1] : false);

    var grouped_markets_h = [],
        seen_grouped_markets = [],
        grouped_markets = [];

    for (var m=0;m<event_.markets.length;++m) {
        var market = event_.markets[m];

        if (!grouped_markets_h[ market.marketTypeDescription ])
            grouped_markets_h[ market.marketTypeDescription ] = [];

        grouped_markets_h[ market.marketTypeDescription ].push( market );
    }

    for (var m=0;m<event_.markets.length;++m) {
        var market = event_.markets[m];

        if (seen_grouped_markets[ market.marketTypeDescription ])
            continue;
        seen_grouped_markets[ market.marketTypeDescription ] = true;

        grouped_markets.push( grouped_markets_h[ market.marketTypeDescription ] );
    }

    event_._compact_markets = []

    for (var i=0;i<grouped_markets.length;++i) {
        var markets = grouped_markets[i];

        for (var m=0;m<event_.markets.length;++m) {
            var market = event_.markets[m];
            var key = market_compact_key(event_, market);

            if ( [27, 28].filter( ('_=='+market.marketTypeId).lambda() ).length )
                market._dont_sort_outcomes = true;

            if (!event_._compact_markets[ key ])
                event_._compact_markets[ key ] = [];
            event_._compact_markets[ key ].push( market );
        }
    }


    /* XXX:
     * 1. if any of the event's markets can't be compacted, then no other event's markets can be compacted too
     * 2. should be the same for entire meeting
     * 3. or we can compact handicap/wdw independently?
     */
    var ok2 = true,
        ok3 = true;
    var out_descrs, values;

    for (var k in event_._compact_markets) {
        var markets = event_._compact_markets[k];

        if (!ok2 && !ok3) {
            // compacting is no more possible
            break;
        }

        // try to reformat to 2 cols
        out_descrs = [];

        for (var m=0;m<event_.markets.length;++m) {
            var market = event_.markets[m];

            if (market.outcomes.length != 2) {
                ok2 = false;
                break;
            }
            for (var i=0; i<market.outcomes.length; ++i) {
                var outcome = market.outcomes[i];

                if (!out_descrs[ outcome.outcomeDescription ])
                    out_descrs[ outcome.outcomeDescription ] = 0;
                out_descrs[ outcome.outcomeDescription ] += 1;
            }
        }

        values = Hash.values(out_descrs);

        if (values.length!=2 || values[0] != values[1])
            ok2 = false;

        if (ok2) { // can be compacted
            for (var m=0;m<event_.markets.length;++m) {
                var market = event_.markets[m];

                if (is_market) {
                    //market._coupon_name = m_wdw_coupon; // TODO: implement
                    market._row_title = event_.eventDescription;
                }
                else {
                    market._col0_title = market.outcomes[0].outcomeDescription;
                    market._col2_title = market.outcomes[1].outcomeDescription;
                    market._coupon_name = handicap_coupon;
                    market._row_title = market.periodDescription;
                }
            }
            continue;
        }

        // try to reformat to 3 cols
        out_descrs = [];

        for (var m=0;m<event_.markets.length;++m) {
            var market = event_.markets[m];

            if (market.outcomes.length != 3) {
                ok3 = false;
                break;
            }
            for (var i=0; i<market.outcomes.length; ++i) {
                var outcome = market.outcomes[i];

                if (!out_descrs[ outcome.outcomeDescription ])
                    out_descrs[ outcome.outcomeDescription ] = 0;
                out_descrs[ outcome.outcomeDescription ] += 1;
            }
        }

        values = Hash.values(out_descrs);

        if (values.length!=3 
                ||
            !( (values[0] == values[1] && values[0] == values[2]) || (event_._compact_markets[ market_compact_key(event_, markets[0]) ].size == 1))
            )
            ok3 = false;


        if (ok3) { // can be compacted
            for (var m=0;m<event_.markets.length;++m) {
                var market = event_.markets[m];

                if (is_market) {
                    //market._coupon_name = m_wdw_coupon; // TODO: implement
                    market._row_title = event_.eventDescription;
                }
                else {
                    market._col0_title = market.outcomes[0].outcomeDescription;
                    market._col1_title = market.outcomes[1].outcomeDescription;
                    market._col2_title = market.outcomes[2].outcomeDescription;
                    market._coupon_name = handicap_coupon;
                    market._row_title = market.periodDescription;
                }
            }
            continue;
        }
    }

    if (!ok2 || !ok3) // should cancel previous compacts
        cancel_event_compact(event_);
}

function event_detail(container, event_, tz_offset)
{

    // TODO: use tz_offset for different servers
    var d = new Date();
    d.setTime(event_.eventDate); // it is already in milliseconds

    var text = '<div class="content-toolbar-coupon">'
                + '<span class="toolbar-text">&nbsp; '+ event_.eventDescription + ' &nbsp;(' + d.toString() + ')</span>'
            + '</div>'

            + '<div id="content-main">';

    event_.markets.sort(sort_markets);

    for (var m=0;m<event_.markets.length;++m) {
        var market = event_.markets[m];

        var coupon_func = get_market_coupon_name(market.marketTypeId);

        text += '<a name="'+market.marketTypeId + '"></a>'
            + '<div class="sport-coupon-detail-tab">'
                + '<div class="heading">'
                    + '<span>' + market.marketDescription + '</span>'
                + '</div>'
                + '<div class="content" id="' + event_.eventId + '_0_' + market.marketTypeId + '" style="display: block">'

                    + coupon_func(event_, market)

                + '</div>' // content
            + '</div>'; // sport-coupon-detail-tab
    }

    text += '</div>';

    container.insert(text);
}

function events_detail(container, result, tz_offset)
{
    container.update("");
    var events = result[0].events;
    // compact_event should be called from the loop, not from event_detail,
    // because of market coupons, which can cancel_event_compact for entire coupon
    for(var i=0;i<events.length;++i) {
        compact_event(events[i]);
        event_detail(container, events[i], tz_offset);
    }
}

