
/**
 * A Media Grid data provider that implements $.loadable behavior.
 *
 * @version 0.2.0
 * @author Jon Ferrer <jon.ferrer@mlb.com>
 *
 * @requires $.bindable
 * @requires $.loadable
 * @requires $.pollable
 * @requires $.etc
 */
(function(window, document, $, bam) {

    var mediagridInstance;

    /**
     * Returns padded numbers
     * @private
     */
    function addLeadingZeros (val, len) {
        val += '';
        while (val.length < (len || 2)) {
            val = '0' + val;
        }
        return val;
    }

    /**
     * Returns media nodes based on criteria like content_id, 
     * playback_scenario or type (audio/video)
     *
     * @methodOf game object
     * @param {Object} criteria
     * @return {Object} media nodes for game that match criteria
     */
    function getMedia (criteria) {
        var mediaItems = $.deep(this, 'game_media.homebase.media'),
            returnMedia = [];

        if (mediaItems) {
            mediaItems = $.ensureArray(mediaItems);

            criteria = criteria || null; 

            $.each(mediaItems, $.proxy(function(i, mediaItem) {
                if (criteria) {
                    if (criteria.content_id && mediaItem.id !== criteria.content_id) {
                        return true;
                    }

                    if (criteria.state && (mediaItem.state !== criteria.state && ($.isArray(criteria.state) && $.inArray(mediaItem.state, criteria.state) < 0))) {
                        return true;
                    }

                    if (criteria.playback_scenario && mediaItem.playback_scenario !== criteria.playback_scenario) {
                        return true;
                    }

                    if (criteria.type && mediaItem.type !== criteria.type) {
                        return true;
                    }

                }
                $.extend(mediaItem, {
                    calendar_event_id : this.calendar_event_id
                });

                returnMedia.push(mediaItem);
               
            }, this));

        } else {

            returnMedia = null;

        }

        return returnMedia;
    }

    /**
     * @constructor
     */
    function MediaGrid(config) {
        config = config || {};

        if ( ! (this instanceof MediaGrid)) {
            if ( ! mediagridInstance) {
                mediagridInstance = new MediaGrid(config);
            }
            return mediagridInstance;
        }

        this.sportCode = config.sportCode || "mlb";    
        this.fileName  = (config.fileName) ? config.fileName : "grid";
    }

    $.loadable(MediaGrid, {
        dataType : "text",
        cache :    !bam.env.host.isDev, // bust cache on dev
        dataFilter : function(response, type) {
            var data = $.parseJSON(response),
                games,
                gamesByEventID = {},
                gamesByGamedayID  = {},
                gamesByGameID  = {};

            data = $.deep(data, "data.games");
            games = $.ensureArray(data.game);

            $.each(games, function(i, game) {
                gamesByEventID[game.calendar_event_id] = game;
                gamesByGamedayID[game.id.replace(/[\/\-]/g, '_')] = game;
                gamesByGameID[game.id] = game;
                game.getMedia = $.proxy(getMedia, game);
            });
            
            return {
                /**
                 * Date of the Media Grid datafile
                 */
                date  : data.date,

                /**
                 * An array of game objects as defined in the grid.json response. 
                 * The order of games is the same as the order in the datafile.
                 */
                games : $.ensureArray(data.game),

                /**
                 * Finds and returns a game object from grid.json datafile based on
                 * search criteria. Search criteria can be either calendar_event_id
                 * or game_id
                 *
                 * @param {Object} criteria  { game_id : YYYY_MM_DD_[away team code][away sport code]_[home team code][home sport code]_[game number]
                 *                           { calendar_event_id : 14-305726-2011-03-15 }
                 *
                 * @return {Object}
                 */
                find : function(criteria) {
                    var returnGame = null;

                    criteria = criteria || {};

                    if ( !! criteria.game_id) {
                        returnGame = gamesByGamedayID[criteria.game_id];
                    }

                    else if ( !! criteria.calendar_event_id) {
                        returnGame = gamesByEventID[criteria.calendar_event_id];
                    }

                    else if ( !! criteria.id) {
                        returnGame = gamesByGameID[criteria.id];
                    }

                    return returnGame;
                },

                /**
                 * Returns an associative array of the games from the grid.json datafile. 
                 * The key for the associative array is defined by the indexName argument. 
                 * If no indexName is specified, then indexBy() returns the array of games.
                 *
                 * @param {String} indexName Can be either "calendar_event_id" or "game_id"
                 *
                 * @returns {Mixed} Array of game objects if no indexName is specified. Hash of game objects indexed by the indexName argument
                 */
                indexBy : function(indexName) {
                    var gamesHash = games;

                    if (indexName.indexOf("calendar_event_id") !== -1) {
                        gamesHash = gamesByEventID; 
                    } else if (indexName.indexOf("game_id") !== -1) {
                        gamesHash = gamesByGamedayID; 
                    } else if (indexName === "id") {
                        gamesHash = gamesByGameID; 
                    }

                    return gamesHash;
                }
            };
        }
    });

    MediaGrid.prototype.loadableConfig = (function (loadableConfig) {
        return function (date) {
                
          // If undefined, set date current date/time Eastern and display
          // previous day's scoreboard until 11am ET (or specified time)
          if (typeof date === 'undefined') {
            date = bam.getDateByOffset(bam.EASTERN_OFFSET);
            if (date.getHours() < MediaGrid.crossover) {
              date.setDate(date.getDate() - 1);
            }
          } else {        
            date = $.ensureDate(date);
          }
      
          var url = '/gdcross/components/game/' + this.sportCode +
            '/year_'  + date.getFullYear() +
            '/month_' + addLeadingZeros(date.getMonth() + 1) +
            '/day_'   + addLeadingZeros(date.getDate()) +
            '/' + this.fileName + '.json';

          return loadableConfig.call(this, url);
          
        };
      })(MediaGrid.prototype.loadableConfig);

    $.pollable(MediaGrid);

    // Keep crossover time public for exceptional override
    MediaGrid.crossover = 11;

    bam.namespace('services').MediaGrid = MediaGrid;
    
})(this, this.document, this.$, this.bam);


