
/**
 * Series Schedule lookup DAO
 *
 * @version 0.4.1
 * @author Jon Ferrer <jon.ferrer@mlb.com>
 *
 * @requires jquery.js
 * @requires jquery.bindable.js
 * @requires bam.js
 *
 * @event load:success( {jq event} event, {obj} SeriesSchedule obj )  Triggers when the Series Schedule has been served via the load() method
 *
 * --> USAGE:
 *
 * bam.dao.ScheduleSeries.one( "load:success", function( e, sked ) { console.dir( sked ) } );
 * bam.dao.ScheduleSeries.load({
 *     "season"     : "2010",
 *     "sport_code" : "'mlb'",
 *     "game_type"  : [ "'D'", "'L'", "'W'" ]
 * });
 *
 */
(function( $ ) {

    var ScheduleSeries = $.bindable({}), // main object. it's bindable too!

        defaultProps, // default params for lookup

        URI_SCHEDULE_SERIES_LOOKUP = "/lookup/json/named.schedule_series.bam"; // lookup endpoint for load method

    /**
     * Returns a SERIES object, which is a grouping of games of a specific matchup
     * @private
     */
    function series( gameType, obj ) {

        var series    = [],
            tmpSeries = [],
            numSeries = [], // array series of IDs for each game type; length of array for DS should be 4; LCS should be 2, WS should be 1
            allMatchupsKnown = true; 

        // filter for games of gameType (aka round of interest) and find the number of series in the round
        $.each( obj.row, function( i, row ) {
            if( row.game_type.indexOf( gameType ) !== -1 ) {
                if( numSeries.length === 0 || numSeries[ numSeries.length - 1 ].indexOf( row.ser_home_nbr ) === -1 ) {
                    numSeries.push( row.ser_home_nbr );
                    numSeries.sort();
                }
                tmpSeries.push( row );

                // silly flag check to see if all matchups are known within current round
                if( 
                    row.home_name_abbrev.indexOf( "TBD" ) !== -1 || 
                    row.away_name_abbrev.indexOf( "TBD" ) !== -1 ||  
                    row.home_name_abbrev.indexOf( "AL" ) !== -1 || 
                    row.away_name_abbrev.indexOf( "AL" ) !== -1 || 
                    row.home_name_abbrev.indexOf( "NL" ) !== -1 || 
                    row.away_name_abbrev.indexOf( "NL" ) !== -1 
                  ) {
                    allMatchupsKnown = false;
                }
            }
        });

        // groups games in round by series and decorate each series obj with useful attributes
        $.each( numSeries, function( i, sn ) {
            var aSeries = {
                "seriesNum" : sn,
                "games"     : []
            },
            numGamesInSeries,
            visitingWins = 0,
            homeWins = 0,
            numWinsNeeded,
            numGamesRequired;

            // group games by series within game_type
            $.each( tmpSeries, function( j, game ) {
                if( game.ser_home_nbr.indexOf( sn ) !== -1 ) {
                    aSeries.games.push( game );

                    // set homeFieldAdvantage and visiting team objects if we're looking at game 1 of a series
                    if( game.ser_game_nbr === "1" && !aSeries.homeFieldAdvantage ) {

                        aSeries.gt_name_short = game.gt_name_short;

                        // home field advantage properties 
                        aSeries.homeFieldAdvantage = { 
                            "club" : game.home_name_abbrev, 
                            "team_code" : game.home_team_code, 
                            "league" : game.home_league,
                            "name_brief" : game.home_name_brief,
                            "name_full" : game.home_name_full
                        };

                        // visiting team properties
                        aSeries.visiting = {
                            "club" : game.away_name_abbrev,
                            "team_code" : game.away_team_code,
                            "league" : game.away_league,
                            "name_brief" : game.away_name_brief,
                            "name_full" : game.away_name_full
                        };
                    }

                    // tally number of wins for each team
                    if( 
                        ( game.away_team_code === aSeries.visiting.team_code && game.away_result === "W" ) || 
                        ( game.home_team_code === aSeries.visiting.team_code && game.home_result === "W" ) 
                      ) {
                        visitingWins += 1;
                    } else if( 
                        ( game.away_team_code === aSeries.homeFieldAdvantage.team_code && game.away_result === "W" ) || 
                        ( game.home_team_code === aSeries.homeFieldAdvantage.team_code && game.home_result === "W" ) 
                     ) {
                        homeWins += 1;
                    }
                }
            });

            // expose number of wins
            aSeries.homeFieldAdvantage.numWins = homeWins;
            aSeries.visiting.numWins           = visitingWins;

            // use wins tally for both teams to determine which games in series are "if necessary" 
            numGamesInSeries = parseInt( aSeries.games[ 0 ].ser_games, 10 );
            if( numGamesInSeries === aSeries.games.length ) {

                numWinsNeeded    = Math.ceil( numGamesInSeries / 2 );
                numGamesRequired = visitingWins + homeWins + numWinsNeeded - ( visitingWins <= homeWins ? homeWins : visitingWins ); 

                // flag if necessary games
                $.each( aSeries.games, function( i, game ) {
                    if( ( i + 1 ) > numGamesRequired ) {
                        game.ifNecessary = true;      
                    }  
                });
            }

            series.push( aSeries );
        });

        return { 
            "series"  : series,
            "isKnown" : allMatchupsKnown
        };

    }

    /**
     * Returns a ROUND object, which is a grouping of games based on game_type
     * @private
     */
    function round( gameType, obj ) {
        var ser = series( gameType, obj ); 
        return {
            "type"      : gameType.toLowerCase() + "s",
            "game_type" : gameType.toUpperCase(),
            "isKnown"   : ser.isKnown,
            "series"    : ser.series
        };
    }

    defaultProps = {
        "season"     : "2010",
        "sport_code" : "'mlb'",
        "game_type"  : [ "'D'", "'L'", "'W'" ]
    };

    $.extend( ScheduleSeries, {

        /**
         * Loads series schedule data asynchronously from lookup service and triggers
         * an observable event containing the schedule once the data has loaded.
         *
         * @public
         */
        "load" : function( p ) {
            var props     = $.extend( {}, defaultProps, p ),
                requestID = "ScheduleSeries.load_" + new Date().valueOf();

            $.ajax({
                "url"         : URI_SCHEDULE_SERIES_LOOKUP,
                "data"        : props,
                "dataType"    : "json",
                "traditional" : true,
                "success"     : function( data ) {
                    // @TODO: make this sort of thing AOP-style...

                    var postseason;

                    // ensure array of game types
                    if( !(props.game_type instanceof Array ) ) {
                        props.game_type = [ props.game_type ];
                    }

                    postseason = {
                        "requestID" : requestID,
                        "year"      : props.season,
                        "round"     : []
                    };

                    // add rounds for each gametype in load()'s config obj 
                    $.each( props.game_type, function( i, el ) {
                        var gt = el.charAt( 1 );
                        postseason.round.push( round( gt, data.schedule_series.queryResults ) );
                    });

                    ScheduleSeries.trigger( "load:success", [ postseason ] );
                }
            });

            return requestID;
        }
    });


    // expose in bam namespace
    if( window.bam ) {

       if( !window.bam.dao ) {
            window.bam.dao = {};          
       }

       $.extend( window.bam.dao, { "ScheduleSeries" : ScheduleSeries } );

    // if bam is not included, expose as global var in window obj
    } else {
        
        window.ScheduleSeries = ScheduleSeries;
    }


})( jQuery );


