(function ($, window, untitled) {

  // Globals
  var bam            = window.bam,
      playerbio      = window.playerbio,
      clubProps,
      globals,
      flags,

  // bam namespaces
  DG                 = bam.datagrid,
  DT                 = bam.datetime,

  // DataGrid classes
  DataGrid           = DG.DataGrid,
  ExpandableDataGrid = DG.ExpandableDataGrid,

  // DataGrid config values
  NUMBER             = DG.DataType.Number,
  TEXT               = DG.DataType.Text,
  ASC                = DG.SortOrder.Asc,
  DESC               = DG.SortOrder.Desc,

  // Shortcuts to utility methods
  getDeepValue       = bam.object.getDeepValue,
  ensureArray        = bam.util.ensureArray,
  getQueryResults    = bam.util.getQueryResults,
  getQueryResult     = bam.util.getQueryResult,
  countQueryResults  = bam.util.countQueryResults,
  wrapQueryResults   = bam.util.wrapQueryResults,

  STAT_TYPE_HITTING  = '1',
  ERROR_LOADING_DATA = '<div class="error dataError">Error loading data</div>',

  MLB                       = 'mlb',
  MLB_SPORT_CODE            = "'mlb'",
  GAME_TYPE_REGULAR_SEASON  = "'R'",
  GAME_TYPE_ALL_STAR_GAME   = "'A'",
  GAME_TYPE_FIRST_ROUND     = "'F'",
  GAME_TYPE_DIVISION_SERIES = "'D'",
  GAME_TYPE_LEAGUE_SERIES   = "'L'",
  GAME_TYPE_WORLD_SEASON    = "'W'",

  LOADING_MASK_CLASS_NAME = 'loadingMask',

  baseDatagridConfig = {
    tableClass:   'stats_table',
    showHeader:   true,
    dataType:     'json',
    sortable:     false,
    autoClassify: true
  },

  clubPropLookupHash,
  ticketingHash = {},

  /* DATA FIELD CONSTANTS ***************************************************/

  AB                      = 'ab',
  ACTIVE_SW               = 'active_sw',                // col_ex
  AO                      = 'ao',                       // col_ex
  AVG                     = 'avg',
  BB                      = 'bb',
  CG                      = 'cg',
  CS                      = 'cs',
  DESCRIPTION             = 'description',
  ER                      = 'er',
  ERA                     = 'era',
  G                       = 'g',
  GAME_DATE               = 'game_date',
  GAME_ID                 = 'game_id',
  GAME_PK                 = 'game_pk',
  GAME_TIME_ET            = 'game_time_et',
  GAME_TYPE               = 'game_type',
  GO                      = 'go',                       // col_ex
  GO_AO                   = 'go_ao',
  GS                      = 'gs',
  H                       = 'h',
  H2B                     = 'h2b',
  H3B                     = 'h3b',
  HB                      = 'hb',
  HOME_AWAY               = 'home_away',
  HR                      = 'hr',
  IBB                     = 'ibb',
  IP                      = 'ip',
  L                       = 'l',
  LEAGUE_DISPLAY_ABBREV   = 'league_display_abbrev',    // col_ex
  LEAGUE_DISPLAY_FULL     = 'league_display_full',      // col_ex
  LEAGUE_DISPLAY_SHORT    = 'league_display_short',     // col_ex
  LEAGUE_ID               = 'league_id',                // col_ex
  NAME_DISPLAY_FIRST_LAST = 'name_display_first_last',  // col_ex
  NAME_DISPLAY_LAST_FIRST = 'name_display_last_first',  // col_ex
  NAME_LAST               = 'name_last',                // col_ex
  OBP                     = 'obp',
  OPP                     = 'opp',
  OPP_PROBABLE_ERA        = 'opp_probable_era',
  OPP_PROBABLE_ID         = 'opp_probable_id',
  OPP_PROBABLE_L          = 'opp_probable_l',
  OPP_PROBABLE_SP         = 'opp_probable_sp',
  OPP_PROBABLE_W          = 'opp_probable_w',
  OPP_TEAM_ABBREV         = 'opp_team_abbrev',
  OPS                     = 'ops',
  PLAYER_ID               = 'player_id',                // col_ex
  R                       = 'r',
  RBI                     = 'rbi',
  SB                      = 'sb',
  SEASON                  = 'season',
  SHO                     = 'sho',
  SIT_DESC                = 'sit_desc',
  SLG                     = 'slg',
  SO                      = 'so',
  SORT_ORDER              = 'sort_order',
  SV                      = 'sv',
  SVO                     = 'svo',
  TB                      = 'tb',
  TEAM                    = 'team_display_abbrev',
  TEAM_COUNT              = 'team_count',               // col_ex
  TEAM_DISPLAY_ABBREV     = 'team_display_abbrev',      // col_ex
  TEAM_DISPLAY_FULL       = 'team_display_full',        // col_ex
  TEAM_DISPLAY_SHORT      = 'team_display_short',       // col_ex
  TEAM_ID                 = 'team_id',
  TEAM_SEQ                = 'team_seq',
  W                       = 'w',
  WHIP                    = 'whip',

  /* COLUMN TITLE CONSTANTS *************************************************/

  EMPTY_TITLE             = '',
  AB_TITLE                = '<abbr title="At Bats">AB</abbr>',
  AVG_TITLE               = '<abbr title="Batting Average">AVG</abbr>',
  BB_TITLE                = '<abbr title="Bases on Balls">BB</abbr>',
  CG_TITLE                = '<abbr title="Complete Games">CG</abbr>',
  CS_TITLE                = '<abbr title="Caught Stealing">CS</abbr>',
  ERA_TITLE               = '<abbr title="Earned Run Average">ERA</abbr>',
  ER_TITLE                = '<abbr title="Earned Runs">ER</abbr>',
  GAME_DATE_TITLE         = 'DATE',
  GAME_PK_TICKETING_TITLE = 'TICKETS',
  GAME_TIME_TITLE         = 'TIME',
  GO_AO_TITLE             = '<abbr title="Ground Outs/Air Outs">GO/AO</abbr>',
  GS_TITLE                = '<abbr title="Games Started">GS</abbr>',
  G_TITLE                 = '<abbr title="Games">G</abbr>',
  H2B_TITLE               = '<abbr title="Doubles">2B</abbr>',
  H3B_TITLE               = '<abbr title="Triples">3B</abbr>',
  HB_TITLE                = '<abbr title="Hit Batsmen">HB</abbr>',
  HR_TITLE                = '<abbr title="Home Runs">HR</abbr>',
  H_TITLE                 = '<abbr title="Hits">H</abbr>',
  IBB_TITLE               = '<abbr title="Intentional Bases on Balls">IBB</abbr>',
  IP_TITLE                = '<abbr title="Innings Pitched">IP</abbr>',
  L_TITLE                 = '<abbr title="Losses">L</abbr>',
  OBP_TITLE               = '<abbr title="On-Base Percentage">OBP</abbr>',
  OPP_PROBABLE_SP_TITLE   = '<abbr title="Probable Starting Pitcher (Opponent)">PROB</abbr>',
  OPP_TITLE               = '<abbr title="Opponent">OPP</abbr>',
  OPS_TITLE               = '<abbr title="On-Base Plus Slugging">OPS</abbr>',
  RBI_TITLE               = '<abbr title="Runs Batted In">RBI</abbr>',
  R_TITLE                 = '<abbr title="Runs">R</abbr>',
  SB_TITLE                = '<abbr title="Stolen Bases">SB</abbr>',
  SEASON_TITLE            = 'SEASON',
  SHO_TITLE               = '<abbr title="Shutouts">SHO</abbr>',
  SLG_TITLE               = '<abbr title="Slugging Percentage">SLG</abbr>',
  SO_TITLE                = '<abbr title="Strikeouts">SO</abbr>',
  SVO_TITLE               = '<abbr title="Save Opportunities">SVO</abbr>',
  SV_TITLE                = '<abbr title="Saves">SV</abbr>',
  TB_TITLE                = '<abbr title="Total Bases">TB</abbr>',
  TEAM_TITLE              = 'TEAM',
  WHIP_TITLE              = '<abbr title="Walks and Hits per Inning Pitched">WHIP</abbr>',
  W_TITLE                 = '<abbr title="Wins">W</abbr>',

  /* HELPER FUNCTIONS *******************************************************/

  rehash = function (data, newKey) {
    var ret = {},
        oldKey,
        datum;
    for (oldKey in data) {
      if (data.hasOwnProperty(oldKey)) {
        datum = data[oldKey];
        if (newKey in datum) {
          ret[datum[newKey]] = datum;
        }
      }
    }
    return ret;
  },

  getColumnDataFields = function (cfg) {
    var cols = cfg.columns,
        included = [],
        i, n;
    for (i = 0, n = cols.length; i < n; ++i) {
      included.push(cols[i].dataField);
    }
    return included;
  },

  /* DATAGRID DECORATORS ****************************************************/

  stripeEveryFiveRowsDecorator = function (tr) {
    if (this.index % 5 === 4) {
      $('td', tr).addClass('stripey');
    }
  },

  expandableSeasonDecorator = function (cell) {
    var toggle = ExpandableDataGrid.expandableDecorator.call(this, cell);
    return cell.value + toggle;
  },

  expandableTeamDisplayAbbrevDecorator = function (cell) {

    var prop;

    if (cell.value === null) {
      return '';
    }

    // Lazy instantiation of clubProps for quick lookup
    clubPropLookupHash = clubPropLookupHash || rehash(clubProps, TEAM_ID);

    prop = clubPropLookupHash[this.cell(TEAM_ID).value];

    return (typeof prop !== 'undefined') ?
      '<a href="/stats/historical/player_stats.jsp?c_id=' + prop.club +
      '&baseballScope=mlb&subScope=teamCode&teamPosCode=' + prop.historical_team_code +
      '&statType=Overview&sitSplit=&venueID=&timeFrame=1&timeSubFrame=' + this.cell(SEASON).value +
      '&Submit=Submit">' + cell.value + '</a>' : cell.value;
  },

  normalizeGameId = function (gameId) {
    return gameId.replace(/[\-\/]/g, '_');
  },

  makeGamedayLink = function (id, text) {
    return '<a href="javascript:void(launchGameday({gid:\'' + id + '\'}));">' + text + '</a>';
  },

  gameDateDecorator = function (cell) {
    if (this.cell(GAME_ID).value === null) { return cell.value; }
    var id   = normalizeGameId(this.cell(GAME_ID).value),
        date = DT.parseISODate(cell.value).toShortDate();
    return makeGamedayLink(id, date);
  },

  gameDateShortDecorator = function (cell) {
    if (this.cell(GAME_ID).value === null) { return cell.value; }
    var id   = normalizeGameId(this.cell(GAME_ID).value),
        date = DT.parseISODate(cell.value).formatDate('MM/dd');
    return makeGamedayLink(id, date);
  },

  gameTimeDecorator = function (cell) {
    var html = DT.parseISODate(cell.value).formatDate('h:mm a');
    return (html === ('3:33 am')) ? 'TBD' : html;
  },

  oppDecorator = function (cell) {
    return (this.cell(HOME_AWAY).value === 'A') ? '@' + cell.value : cell.value;
  },

  oppProbableSpDecorator = function (cell) {
    var id    = this.cell(OPP_PROBABLE_ID).value,
        w     = this.cell(OPP_PROBABLE_W).value,
        l     = this.cell(OPP_PROBABLE_L).value,
        era   = this.cell(OPP_PROBABLE_ERA).value,
        url   = '/team/player.jsp?player_id=' + id,
        title = w + '-' + l + ', ' + era + 'ERA';
    return '<a href="' + url + '" title="' + title + '">' + cell.value + '</a>';
  },

  gamePkTicketingDecorator = function (cell) {

    var html = '',
        ticketData,
        ticketLinks,
        ticketLink,
        location,
        i, n;

    if (typeof ticketingHash !== 'undefined' && cell.value in ticketingHash) {
      ticketData  = ticketingHash[cell.value];
      ticketLinks = ensureArray(ticketData.ticket_link);

      for (i = 0, n = ticketLinks.length; i < n; ++i) {
        ticketLink = ticketLinks[i];
        if (ticketLink.ticket_category === 'TICKETS') {
          location = (ticketData.home_team_id === clubProps[globals.cid].team_id) ? 'home' : 'away';
          html = '<a href="javascript:openTIXXWindow(\'' + ticketLink.tlink + '\', \'' + location + '\');" title="Buy Tickets"><img src="/images/schedule/icon_ticket.gif" class="dynTixLinkIcon TICKETS" alt="Buy Tickets" style="cursor:pointer;"/></a>';
          break;
        }
      }
    }

    return html;
  },

  postSeasonDescriptionDecoratorRegExp = /[^A-Z]/g,

  postSeasonDescriptionDecorator = function (cell) {
    var abbr = cell.value.replace(postSeasonDescriptionDecoratorRegExp, '');
    return '<abbr title="' + cell.value + '">' + abbr + '</abbr>';
  },

  /* CAREER & SUMMARY STATS *************************************************/

  careerSummaryConfig,
  careerSummaryPanel,
  summaryPanel,
  careerPanel,

  careerSummaryConfigFactory = function (statType) {

    var config = {
      summaryDatagridConfig: $.extend({}, baseDatagridConfig),
      careerDatagridConfig: $.extend({}, baseDatagridConfig, {
        sortable: true,
        rowDecorator: stripeEveryFiveRowsDecorator,
        onColumnSort: function () {
          this.parent.refresh();
        }
      }),
      totalColEx: [
        ACTIVE_SW,
        AO,
        GO,
        NAME_DISPLAY_FIRST_LAST,
        NAME_DISPLAY_LAST_FIRST,
        NAME_LAST,
        PLAYER_ID,
        TEAM_COUNT,
        TEAM_DISPLAY_ABBREV,
        TEAM_ID,
        TEAM_SEQ
      ],
      seasonColEx: [
        LEAGUE_DISPLAY_ABBREV,
        LEAGUE_DISPLAY_FULL,
        LEAGUE_DISPLAY_SHORT,
        LEAGUE_ID,
        PLAYER_ID,
        TEAM_DISPLAY_FULL,
        TEAM_DISPLAY_SHORT
      ],
      careerColEx: [
        AO,
        GO,
        PLAYER_ID,
        SEASON
      ]
    };

    // Hitting config
    if (statType === STAT_TYPE_HITTING) {

      $.extend(config, {
        url:                 '/lookup/json/named.mlb_bio_hitting_summary.bam',
        seasonSportcode:     'mlb_individual_hitting_season_sportcode.season',
        totalProperty:       'mlb_bio_hitting_summary.mlb_individual_hitting_season_total',
        seasonProperty:      'mlb_bio_hitting_summary.mlb_individual_hitting_season',
        careerProperty:      'mlb_bio_hitting_summary.mlb_individual_hitting_career',
        totalColExProperty:  'mlb_individual_hitting_season_total.col_ex',
        seasonColExProperty: 'mlb_individual_hitting_season.col_ex',
        careerColExProperty: 'mlb_individual_hitting_career.col_ex'
      });

      $.extend(config.summaryDatagridConfig, {
        columns: [
          { dataField: SEASON, type: TEXT, title: EMPTY_TITLE },
          { dataField: G, type: NUMBER, title: G_TITLE },
          { dataField: AB, type: NUMBER, title: AB_TITLE },
          { dataField: R, type: NUMBER, title: R_TITLE },
          { dataField: H, type: NUMBER, title: H_TITLE },
          { dataField: TB, type: NUMBER, title: TB_TITLE },
          { dataField: H2B, type: NUMBER, title: H2B_TITLE },
          { dataField: H3B, type: NUMBER, title: H3B_TITLE },
          { dataField: HR, type: NUMBER, title: HR_TITLE },
          { dataField: RBI, type: NUMBER, title: RBI_TITLE },
          { dataField: BB, type: NUMBER, title: BB_TITLE },
          { dataField: IBB, type: NUMBER, title: IBB_TITLE },
          { dataField: SO, type: NUMBER, title: SO_TITLE },
          { dataField: SB, type: NUMBER, title: SB_TITLE },
          { dataField: CS, type: NUMBER, title: CS_TITLE },
          { dataField: AVG, type: NUMBER, title: AVG_TITLE },
          { dataField: OBP, type: NUMBER, title: OBP_TITLE },
          { dataField: SLG, type: NUMBER, title: SLG_TITLE },
          { dataField: OPS, type: NUMBER, title: OPS_TITLE },
          { dataField: GO_AO, type: NUMBER, title: GO_AO_TITLE }
        ]
      });

      $.extend(config.careerDatagridConfig, {
        columns: [
          { dataField: SEASON, type: NUMBER, sortState: ASC, title: SEASON_TITLE, decorator: expandableSeasonDecorator },
          { dataField: TEAM, type: TEXT, sortState: ASC, title: TEAM_TITLE, decorator: expandableTeamDisplayAbbrevDecorator },
          { dataField: G, type: NUMBER, sortState: DESC, title: G_TITLE },
          { dataField: AB, type: NUMBER, sortState: DESC, title: AB_TITLE },
          { dataField: R, type: NUMBER, sortState: DESC, title: R_TITLE },
          { dataField: H, type: NUMBER, sortState: DESC, title: H_TITLE },
          { dataField: TB, type: NUMBER, sortState: DESC, title: TB_TITLE },
          { dataField: H2B, type: NUMBER, sortState: DESC, title: H2B_TITLE },
          { dataField: H3B, type: NUMBER, sortState: DESC, title: H3B_TITLE },
          { dataField: HR, type: NUMBER, sortState: DESC, title: HR_TITLE },
          { dataField: RBI, type: NUMBER, sortState: DESC, title: RBI_TITLE },
          { dataField: BB, type: NUMBER, sortState: DESC, title: BB_TITLE },
          { dataField: IBB, type: NUMBER, sortState: DESC, title: IBB_TITLE },
          { dataField: SO, type: NUMBER, sortState: DESC, title: SO_TITLE },
          { dataField: SB, type: NUMBER, sortState: DESC, title: SB_TITLE },
          { dataField: CS, type: NUMBER, sortState: DESC, title: CS_TITLE },
          { dataField: AVG, type: NUMBER, sortState: DESC, title: AVG_TITLE },
          { dataField: OBP, type: NUMBER, sortState: DESC, title: OBP_TITLE },
          { dataField: SLG, type: NUMBER, sortState: DESC, title: SLG_TITLE },
          { dataField: OPS, type: NUMBER, sortState: DESC, title: OPS_TITLE },
          { dataField: GO_AO, type: NUMBER, sortState: DESC, title: GO_AO_TITLE },
          { dataField: TEAM_ID, type: NUMBER, visible: false },
          { dataField: TEAM_SEQ, type: NUMBER, visible: false }
        ]
      });

    // Pitching config
    } else {

      $.extend(config, {
        url:                 '/lookup/json/named.mlb_bio_pitching_summary.bam',
        seasonSportcode:     'mlb_individual_pitching_season_sportcode.season',
        totalProperty:       'mlb_bio_pitching_summary.mlb_individual_pitching_season_total',
        seasonProperty:      'mlb_bio_pitching_summary.mlb_individual_pitching_season',
        careerProperty:      'mlb_bio_pitching_summary.mlb_individual_pitching_career',
        totalColExProperty:  'mlb_individual_pitching_season_total.col_ex',
        seasonColExProperty: 'mlb_individual_pitching_season.col_ex',
        careerColExProperty: 'mlb_individual_pitching_career.col_ex'
      });

      $.extend(config.summaryDatagridConfig, {
        columns: [
          { dataField: SEASON, type: TEXT, title: EMPTY_TITLE },
          { dataField: W, type: NUMBER, title: W_TITLE },
          { dataField: L, type: NUMBER, title: L_TITLE },
          { dataField: ERA, type: NUMBER, title: ERA_TITLE },
          { dataField: G, type: NUMBER, title: G_TITLE },
          { dataField: GS, type: NUMBER, title: GS_TITLE },
          { dataField: CG, type: NUMBER, title: CG_TITLE },
          { dataField: SHO, type: NUMBER, title: SHO_TITLE },
          { dataField: SV, type: NUMBER, title: SV_TITLE },
          { dataField: SVO, type: NUMBER, title: SVO_TITLE },
          { dataField: IP, type: NUMBER, title: IP_TITLE },
          { dataField: H, type: NUMBER, title: H_TITLE },
          { dataField: R, type: NUMBER, title: R_TITLE },
          { dataField: ER, type: NUMBER, title: ER_TITLE },
          { dataField: HR, type: NUMBER, title: HR_TITLE },
          { dataField: HB, type: NUMBER, title: HB_TITLE },
          { dataField: BB, type: NUMBER, title: BB_TITLE },
          { dataField: SO, type: NUMBER, title: SO_TITLE },
          { dataField: AVG, type: NUMBER, title: AVG_TITLE },
          { dataField: WHIP, type: NUMBER, title: WHIP_TITLE },
          { dataField: GO_AO, type: NUMBER, title: GO_AO_TITLE }
        ]
      });

      $.extend(config.careerDatagridConfig, {
        columns: [
          { dataField: SEASON, type: NUMBER, sortState: ASC, title: SEASON_TITLE, decorator: expandableSeasonDecorator },
          { dataField: TEAM, type: TEXT, sortState: ASC, title: TEAM_TITLE, decorator: expandableTeamDisplayAbbrevDecorator },
          { dataField: W, type: NUMBER, sortState: DESC, title: W_TITLE },
          { dataField: L, type: NUMBER, sortState: DESC, title: L_TITLE },
          { dataField: ERA, type: NUMBER, sortState: DESC, title: ERA_TITLE },
          { dataField: G, type: NUMBER, sortState: DESC, title: G_TITLE },
          { dataField: GS, type: NUMBER, sortState: DESC, title: GS_TITLE },
          { dataField: CG, type: NUMBER, sortState: DESC, title: CG_TITLE },
          { dataField: SHO, type: NUMBER, sortState: DESC, title: SHO_TITLE },
          { dataField: SV, type: NUMBER, sortState: DESC, title: SV_TITLE },
          { dataField: SVO, type: NUMBER, sortState: DESC, title: SVO_TITLE },
          { dataField: IP, type: NUMBER, sortState: DESC, title: IP_TITLE },
          { dataField: H, type: NUMBER, sortState: DESC, title: H_TITLE },
          { dataField: R, type: NUMBER, sortState: DESC, title: R_TITLE },
          { dataField: ER, type: NUMBER, sortState: DESC, title: ER_TITLE },
          { dataField: HR, type: NUMBER, sortState: DESC, title: HR_TITLE },
          { dataField: HB, type: NUMBER, sortState: DESC, title: HB_TITLE },
          { dataField: BB, type: NUMBER, sortState: DESC, title: BB_TITLE },
          { dataField: SO, type: NUMBER, sortState: DESC, title: SO_TITLE },
          { dataField: AVG, type: NUMBER, sortState: DESC, title: AVG_TITLE },
          { dataField: WHIP, type: NUMBER, sortState: DESC, title: WHIP_TITLE },
          { dataField: GO_AO, type: NUMBER, sortState: DESC, title: GO_AO_TITLE },
          { dataField: TEAM_ID, type: NUMBER, visible: false },
          { dataField: TEAM_SEQ, type: NUMBER, visible: false }
        ]
      });
    }

    return config;
  },

  mergeTotalsAndPartials = function (totals, partials) {

    var rows = ExpandableDataGrid.mergeParentsAndChildren(totals, partials, SEASON, SEASON, function (idx, partial) {
      return partial[TEAM_SEQ] - 1;
    }),
    i, n,
    row,
    children,
    child;

    // Extend row with team_display_abbrev if team_display_abbrev is unique
    for (i = 0, n = rows.length; i < n; ++i) {
      row      = rows[i];
      children = row.children || [];
      if (children.length === 1) {
        child = children[0];
        row[TEAM] = child[TEAM];
        row[TEAM_ID] = child[TEAM_ID];
      }
    }

    return rows;
  },

  handleLoadSummaryDataSuccess = function (data) {

    var summaryTable = new DataGrid(careerSummaryConfig.summaryDatagridConfig);

    summaryTable.loadData({
      data:     data,
      callback: function () {
        summaryTable.render('stats_summary_table');
        summaryPanel.show();
      }
    });
  },

  handleLoadCareerStatsSuccess = function (data) {

    var careerTable,
        cfg      = careerSummaryConfig,
        totals   = getQueryResults(data, cfg.totalProperty),
        partials = getQueryResults(data, cfg.seasonProperty),
        merged   = mergeTotalsAndPartials(totals, partials),
        career   = getQueryResults(data, cfg.careerProperty)[0],
        summary  = [],
        season   = parseInt(globals.season, 10),
        i, n;

    if (typeof career === 'undefined') {
      career = {};
    }
    career.season = 'CAREER';

    if (flags.is_historical !== 'true') {
      for (i = 0, n = merged.length; i < n; ++i) {
        if (merged[i].season === globals.season) {
          summary.push($.extend({}, merged[i], { season: 'SEASON' }));
          break;
        }
      }
      summary.push(career);

      handleLoadSummaryDataSuccess(wrapQueryResults(summary));
    }

    careerTable = new ExpandableDataGrid(cfg.careerDatagridConfig);

    careerTable.loadData({
      data:     wrapQueryResults(merged),
      callback: function () {
        careerTable.insertFooterRow(career);
        careerTable.sortColumn(0, DESC);
        careerTable.render('career_toggle1');
        careerPanel.show();
      }
    });
  },

  handleLoadCareerStatsError = function () {
    careerSummaryPanel.html(ERROR_LOADING_DATA);
  },

  handleLoadCareerStatsComplete = function () {
    careerSummaryPanel.removeClass(LOADING_MASK_CLASS_NAME);
  },

  loadCareerStats = function (playerId, statType) {

    careerSummaryConfig = careerSummaryConfig || careerSummaryConfigFactory(statType);

    // Configure request
    var cfg = careerSummaryConfig,
        params = {
          game_type: GAME_TYPE_REGULAR_SEASON,
          sort_by:   "'season_asc'",
          player_id: playerId
        };

    params[cfg.seasonSportcode] = playerbio.utils.get_year();

    // Optimize query (not a complete optimization, but significant)
    params[cfg.careerColExProperty] = cfg.careerColEx;
    params[cfg.totalColExProperty]  = cfg.totalColEx;
    params[cfg.seasonColExProperty] = cfg.seasonColEx;

    $.ajax({
      url:      cfg.url,
      data:     params,
      dataType: 'json',
      success:  handleLoadCareerStatsSuccess,
      error:    handleLoadCareerStatsError,
      complete: handleLoadCareerStatsComplete
    });
  },

  /* POST-SEASON STATS ******************************************************/

  postSeasonConfig,
  postSeasonPanel,

  postSeasonGameTypes = [
    GAME_TYPE_DIVISION_SERIES,
    GAME_TYPE_LEAGUE_SERIES,
    GAME_TYPE_WORLD_SEASON
  ],

  postSeasonConfigFactory = function (statType) {

    var config = {
      gameTypeProperty: 'lk_game_type',
      datagridConfig:   $.extend({}, baseDatagridConfig)
    };

    // Hitting config
    if (statType === STAT_TYPE_HITTING) {

      $.extend(config, {
        url:             '/lookup/json/named.mlb_bio_hitting_postseason_summary.bam',
        colInProperty:   'mlb_individual_hitting_season.col_in',
        gameTypeParam:   'mlb_individual_hitting_season_game_type_repeater.game_type',
        summaryProperty: 'mlb_bio_hitting_postseason_summary',
        seasonProperty:  'mlb_individual_hitting_season_game_type_repeater.mlb_individual_hitting_season',
        totalsProperty:  'mlb_individual_hitting_season'
      });

      $.extend(config.datagridConfig, {
        columns: [
          { dataField: DESCRIPTION, type: TEXT, title: EMPTY_TITLE, decorator: postSeasonDescriptionDecorator },
          { dataField: G, type: NUMBER, title: G_TITLE },
          { dataField: AB, type: NUMBER, title: AB_TITLE },
          { dataField: R, type: NUMBER, title: R_TITLE },
          { dataField: H, type: NUMBER, title: H_TITLE },
          { dataField: TB, type: NUMBER, title: TB_TITLE },
          { dataField: H2B, type: NUMBER, title: H2B_TITLE },
          { dataField: H3B, type: NUMBER, title: H3B_TITLE },
          { dataField: HR, type: NUMBER, title: HR_TITLE },
          { dataField: RBI, type: NUMBER, title: RBI_TITLE },
          { dataField: BB, type: NUMBER, title: BB_TITLE },
          { dataField: IBB, type: NUMBER, title: IBB_TITLE },
          { dataField: SO, type: NUMBER, title: SO_TITLE },
          { dataField: SB, type: NUMBER, title: SB_TITLE },
          { dataField: CS, type: NUMBER, title: CS_TITLE },
          { dataField: AVG, type: NUMBER, title: AVG_TITLE },
          { dataField: OBP, type: NUMBER, title: OBP_TITLE },
          { dataField: SLG, type: NUMBER, title: SLG_TITLE },
          { dataField: OPS, type: NUMBER, title: OPS_TITLE },
          { dataField: GO_AO, type: NUMBER, title: GO_AO_TITLE }
        ]
      });

    // Pitching config
    } else {

      $.extend(config, {
        url:             '/lookup/json/named.mlb_bio_pitching_postseason_summary.bam',
        colInProperty:   'mlb_individual_pitching_season.col_in',
        gameTypeParam:   'mlb_individual_pitching_season_game_type_repeater.game_type',
        summaryProperty: 'mlb_bio_pitching_postseason_summary',
        seasonProperty:  'mlb_individual_pitching_season_game_type_repeater.mlb_individual_pitching_season',
        totalsProperty:  'mlb_individual_pitching_season'
      });

      $.extend(config.datagridConfig, {
        columns: [
          { dataField: DESCRIPTION, type: TEXT, title: EMPTY_TITLE, decorator: postSeasonDescriptionDecorator },
          { dataField: W, type: NUMBER, title: W_TITLE },
          { dataField: L, type: NUMBER, title: L_TITLE },
          { dataField: ERA, type: NUMBER, title: ERA_TITLE },
          { dataField: G, type: NUMBER, title: G_TITLE },
          { dataField: GS, type: NUMBER, title: GS_TITLE },
          { dataField: CG, type: NUMBER, title: CG_TITLE },
          { dataField: SHO, type: NUMBER, title: SHO_TITLE },
          { dataField: SV, type: NUMBER, title: SV_TITLE },
          { dataField: SVO, type: NUMBER, title: SVO_TITLE },
          { dataField: IP, type: NUMBER, title: IP_TITLE },
          { dataField: H, type: NUMBER, title: H_TITLE },
          { dataField: R, type: NUMBER, title: R_TITLE },
          { dataField: ER, type: NUMBER, title: ER_TITLE },
          { dataField: HR, type: NUMBER, title: HR_TITLE },
          { dataField: HB, type: NUMBER, title: HB_TITLE },
          { dataField: BB, type: NUMBER, title: BB_TITLE },
          { dataField: SO, type: NUMBER, title: SO_TITLE },
          { dataField: AVG, type: NUMBER, title: AVG_TITLE },
          { dataField: WHIP, type: NUMBER, title: WHIP_TITLE },
          { dataField: GO_AO, type: NUMBER, title: GO_AO_TITLE }
        ]
      });
    }

    return config;
  },

  sortByGameType = function (a, b) {
    var aa = a[SORT_ORDER],
        bb = b[SORT_ORDER];
    return aa < bb ? -1 : aa > bb ? 1 : 0;
  },

  handleLoadPostSeasonStatsSuccess = function (data) {

    var cfg = postSeasonConfig,
        postSeasonTable,
        summary,
        seasons,
        i, n,
        gameTypes,
        rows = [],
        row;

    summary   = getDeepValue(data, cfg.summaryProperty);
    gameTypes = rehash(getQueryResults(summary, cfg.gameTypeProperty), GAME_TYPE);
    seasons   = getDeepValue(summary, cfg.seasonProperty);

    for (i = 0, n = seasons.length; i < n; ++i) {
      row = getQueryResult(seasons[i]);
      if (typeof row !== 'undefined') {
        rows.push($.extend({}, row, gameTypes[seasons[i][GAME_TYPE].replace(/'/g, '')]));
      }
    }

    if (rows.length > 0) {

      postSeasonTable = new DataGrid(cfg.datagridConfig);

      postSeasonTable.loadData({
        data:     wrapQueryResults(rows.sort(sortByGameType)),
        callback: function () {
          var totals = getQueryResult(summary, cfg.totalsProperty);
          if (typeof totals !== 'undefined') {
            totals[DESCRIPTION] = 'TOTALS';
            postSeasonTable.insertFooterRow(totals);
          }
          postSeasonTable.render('postseason_stats');
        }
      });

      $('#more_career_postseason').attr('href', '/stats/individual_player_postseason.jsp?statType='+globals.statType+'&playerID=' + globals.player_id);
      $('#postseason_stats_year').text(globals.season + ' POSTSEASON STATS SUMMARY');
      postSeasonPanel.show();
    }
  },

  handleLoadPostSeasonStatsError = function () {},

  handleLoadPostSeasonStatsComplete = function () {},

  loadPostSeasonStats = function (playerId, statType, season) {

    postSeasonConfig = postSeasonConfig || postSeasonConfigFactory(statType);

    // Configure request
    var cfg = postSeasonConfig,
        params = {
          game_type:  postSeasonGameTypes,
          sport_code: MLB_SPORT_CODE,
          season:     season,
          player_id:  playerId
        };

    params[cfg.gameTypeParam] = postSeasonGameTypes;

    // Optimize query
    params[cfg.colInProperty] = getColumnDataFields(cfg.datagridConfig);

    $.ajax({
      url:      cfg.url,
      data:     params,
      dataType: 'json',
      success:  handleLoadPostSeasonStatsSuccess,
      error:    handleLoadPostSeasonStatsError,
      complete: handleLoadPostSeasonStatsComplete
    });
  },

  /* LAST 10 TOTALS *********************************************************/

  lastTenConfig,
  lastTenPanel,
  lastTenLoaded = false,

  lastTenConfigFactory = function (statType) {

    var config = {
      gameTypes:  [
        GAME_TYPE_REGULAR_SEASON
      ],
      datagridConfig: $.extend({}, baseDatagridConfig)
    };

    // Hitting config
    if (statType === STAT_TYPE_HITTING) {

      $.extend(config, {
        url:                  '/lookup/json/named.mlb_bio_hitting_last_10.bam',
        colInProperty:        'mlb_individual_hitting_last_x_total.col_in',
        gameLogProperty:      'mlb_bio_hitting_last_10.mlb_individual_hitting_game_log',
        lastTenTotalProperty: 'mlb_bio_hitting_last_10.mlb_individual_hitting_last_x_total'
      });

      $.extend(config.datagridConfig, {
        columns: [
          { dataField: GAME_DATE, type: TEXT, title: GAME_DATE_TITLE, decorator: gameDateDecorator },
          { dataField: OPP, title: OPP_TITLE, type: TEXT, decorator: oppDecorator },
          { dataField: AB, type: NUMBER, title: AB_TITLE },
          { dataField: R, type: NUMBER, title: R_TITLE },
          { dataField: H, type: NUMBER, title: H_TITLE },
          { dataField: HR, type: NUMBER, title: HR_TITLE },
          { dataField: RBI, type: NUMBER, title: RBI_TITLE },
          { dataField: BB, type: NUMBER, title: BB_TITLE },
          { dataField: SO, type: NUMBER, title: SO_TITLE },
          { dataField: SB, type: NUMBER, title: SB_TITLE },
          { dataField: AVG, type: NUMBER, title: AVG_TITLE },
          { dataField: HOME_AWAY, type: TEXT, visible: false},
          { dataField: GAME_ID, type: TEXT, visible: false},
          { dataField: GAME_TYPE, type: TEXT, visible: false}
        ]
      });

    // Pitching config
    } else {

      $.extend(config, {
        url:                  '/lookup/json/named.mlb_bio_pitching_last_10.bam',
        colInProperty:        'mlb_individual_pitching_last_x_total.col_in',
        gameLogProperty:      'mlb_bio_pitching_last_10.mlb_individual_pitching_game_log',
        lastTenTotalProperty: 'mlb_bio_pitching_last_10.mlb_individual_pitching_last_x_total'
      });

      $.extend(config.datagridConfig, {
        columns: [
          { dataField: GAME_DATE, type: TEXT, title: GAME_DATE_TITLE, decorator: gameDateDecorator },
          { dataField: OPP, title: OPP_TITLE, type: TEXT, decorator: oppDecorator },
          { dataField: W, type: NUMBER, title: W_TITLE },
          { dataField: L, type: NUMBER, title: L_TITLE },
          { dataField: ERA, type: NUMBER, title: ERA_TITLE },
          { dataField: SV, type: NUMBER, title: SV_TITLE },
          { dataField: IP, type: NUMBER, title: IP_TITLE },
          { dataField: H, type: NUMBER, title: H_TITLE },
          { dataField: ER, type: NUMBER, title: ER_TITLE },
          { dataField: BB, type: NUMBER, title: BB_TITLE },
          { dataField: SO, type: NUMBER, title: SO_TITLE },
          { dataField: HOME_AWAY, type: TEXT, visible: false },
          { dataField: GAME_ID, type: TEXT, visible: false },
          { dataField: GAME_TYPE, type: TEXT, visible: false}
        ]
      });
    }

    return config;
  },

  handleLoadLastTenSuccess = function (data) {

    var cfg = lastTenConfig,
        lastTenTable = new DataGrid(cfg.datagridConfig),
        totals;

    lastTenTable.loadData({
      data:     getDeepValue(data, cfg.gameLogProperty),
      callback: function () {
        if (countQueryResults(data, cfg.lastTenTotalProperty)) {
          totals = getQueryResults(data, cfg.lastTenTotalProperty)[0];
          totals[GAME_DATE] = 'TOTALS';
          lastTenTable.insertFooterRow(totals);
        }
        lastTenTable.render('lastTenPanel');
      }
    });
  },

  handleLoadLastTenError = function () {
    lastTenPanel.html(ERROR_LOADING_DATA);
  },

  handleLoadLastTenComplete = function () {
    lastTenPanel.removeClass(LOADING_MASK_CLASS_NAME);
  },

  loadLastTen = function (playerId, statType, season) {

    if (lastTenLoaded) {
      return;
    }

    lastTenLoaded = true;
    lastTenConfig = lastTenConfig || lastTenConfigFactory(statType);
    lastTenPanel  = $('#lastTenPanel');

    // Configure request
    var cfg = lastTenConfig,
        params = {
          results:    10,
          game_type:  cfg.gameTypes,
          season:     season || playerbio.utils.get_year(),
          player_id:  playerId
        };

    // Optimize query
    params[cfg.colInProperty] = getColumnDataFields(cfg.datagridConfig);

    $.ajax({
      url:      cfg.url,
      dataType: 'json',
      data:     params,
      success:  function (data) {

        if (countQueryResults(data, cfg.gameLogProperty) > 0) {
          handleLoadLastTenSuccess(data);
        } else if (season === playerbio.utils.get_year()) {
          $('#upcomingGamesTab').trigger('click');
          $('#splitsTab, #splitsPanel').hide();
          loadLastTen(playerId, statType, season - 1);
        }

      },
      error:    handleLoadLastTenError,
      complete: handleLoadLastTenComplete
    });

  },

  /* UPCOMING GAMES *********************************************************/

  upcomingGamesConfig,
  upcomingGamesPanel,
  upcomingGamesLoaded = false,

  upcomingGamesConfigFactory = function () {

    var config = {
      url:           '/lookup/json/named.mlb_upcoming_games.bam',
      gameTypes: [
        GAME_TYPE_REGULAR_SEASON,
        GAME_TYPE_ALL_STAR_GAME,
        GAME_TYPE_FIRST_ROUND,
        GAME_TYPE_DIVISION_SERIES,
        GAME_TYPE_LEAGUE_SERIES,
        GAME_TYPE_WORLD_SEASON
      ],
      colInProperty: 'mlb_upcoming_games.col_in',
      gamesProperty: 'mlb_upcoming_games',
      datagridConfig: $.extend({}, baseDatagridConfig)
    };

    $.extend(config.datagridConfig, {
      columns: [
        { dataField: GAME_DATE, type: TEXT, title: GAME_DATE_TITLE, decorator: gameDateShortDecorator },
        { dataField: OPP_TEAM_ABBREV, title: OPP_TITLE, type: TEXT, decorator: oppDecorator },
        { dataField: GAME_TIME_ET, title: GAME_TIME_TITLE, type: TEXT, decorator: gameTimeDecorator },
        { dataField: OPP_PROBABLE_SP, title: OPP_PROBABLE_SP_TITLE, type: TEXT, decorator: oppProbableSpDecorator },
        { dataField: GAME_PK, title: GAME_PK_TICKETING_TITLE, type: TEXT, decorator: gamePkTicketingDecorator },
        { dataField: HOME_AWAY, type: TEXT, visible: false },
        { dataField: GAME_ID, type: TEXT, visible: false },
        { dataField: OPP_PROBABLE_ID, type: TEXT, visible: false },
        { dataField: OPP_PROBABLE_W, type: TEXT, visible: false },
        { dataField: OPP_PROBABLE_L, type: TEXT, visible: false },
        { dataField: OPP_PROBABLE_ERA, type: TEXT, visible: false },
        { dataField: GAME_TYPE, type: TEXT, visible: false}
      ]
    });

    return config;
  },

  handleLoadUpcomingGamesSuccess = function (data) {

    var cfg = upcomingGamesConfig,
        upcomingGamesTable = new DataGrid(cfg.datagridConfig);

    upcomingGamesTable.loadData({
      data:     getDeepValue(data, cfg.gamesProperty),
      callback: function () {
        upcomingGamesTable.render('upcomingGamesPanel');

        var link = '<a id="schedule_link" href="/schedule/index.jsp?c_id=' +
          clubProps[globals.cid].club + '">Full Schedule &gt;</a>';
        upcomingGamesPanel.after(link);
      }
    });
  },

  handleLoadUpcomingGamesError = function () {
    upcomingGamesPanel.html(ERROR_LOADING_DATA);
  },

  handleLoadUpcomingGamesComplete = function () {
    upcomingGamesPanel.removeClass(LOADING_MASK_CLASS_NAME);
  },

  loadUpcomingGames = function () {

    if (upcomingGamesLoaded) {
      return;
    }

    upcomingGamesLoaded = true;
    upcomingGamesConfig = upcomingGamesConfig || upcomingGamesConfigFactory();
    upcomingGamesPanel  = $('#upcomingGamesPanel');

    // Configure request
    var cfg = upcomingGamesConfig,
        params = {
          results:    10,
          game_type:  cfg.gameTypes,
          player_id:  globals.player_id
        };

    // Optimize query
    params[cfg.colInProperty] = getColumnDataFields(cfg.datagridConfig);

    $.ajax({
      url:      cfg.url,
      dataType: 'json',
      data:     params,
      success:  handleLoadUpcomingGamesSuccess,
      error:    handleLoadUpcomingGamesError,
      complete: handleLoadUpcomingGamesComplete
    });
  },

  /* TICKETING **************************************************************/

  ticketingLoaded = false,

  handleLoadTicketingSuccess = function (data) {

    var games = ensureArray(getDeepValue(data, 'events.game')),
        game,
        i, n;

    for (i = 0, n = games.length; i < n; ++i) {
      game = games[i];
      if(!ticketingHash[game.schedule_id]) {
        ticketingHash[game.schedule_id] = game;
      } else {
        $.extend(ticketingHash[game.schedule_id], game);
      }
    }
  },

  handleLoadTicketingError = function () {},

  handleLoadTicketingComplete = function () {
    loadUpcomingGames();
  },

  loadTicketing = function () {

    if (ticketingLoaded) {
      return;
    }

    ticketingLoaded = true;

    var now = DT.DateTime(new Date()),
        params = {
          sport_id:     1,
          site_section: "'DEFAULT'",
          team_id:      clubProps[globals.cid].team_id,
          year:         now.getFullYear(),
          //begin_date:   now.toYMD(),
          //end_date:     now.incrementMonth(1).toYMD()
		  game_type:["'R'", "'D'", "'L'", "'W'"],
		  events: "10"
        };

    $.ajax({
      url:      '/ticketing-client/json/Game.tiksrv',
      dataType: 'json',
      data:     params,
      success:  handleLoadTicketingSuccess,
      error:    handleLoadTicketingError,
      complete: handleLoadTicketingComplete
    });

  },

  /* SPLITS *****************************************************************/

  splitsConfig,
  splitsPanel,
  splitsLoaded = false,

  splitsConfigFactory = function (statType) {

    var config = {};

    // Hitting config
    if (statType === STAT_TYPE_HITTING) {

      $.extend(config, {
        url:             '/lookup/json/named.mlb_individual_hitting_bio_sits.bam',
        colInProperty:   'mlb_individual_hitting_bio_sits.col_in',
        bioSitsProperty: 'mlb_individual_hitting_bio_sits'
      });

    // Pitching config
    } else {

      $.extend(config, {
        url:             '/lookup/json/named.mlb_individual_pitching_bio_sits.bam',
        colInProperty:   'mlb_individual_pitching_bio_sits.col_in',
        bioSitsProperty: 'mlb_individual_pitching_bio_sits'
      });

    }

    return config;
  },

  handleLoadSplitsSuccess = function (data) {

    var cfg = splitsConfig,
        splits = rehash(getQueryResults(data, cfg.bioSitsProperty), SIT_DESC),
        tableDefinitions,
        tableDefinition,
        tableName,
        tables = {},
        table,
        tbody,
        key,
        val,
        i, n;

    if (countQueryResults(data, cfg.bioSitsProperty) > 0) {

      tableDefinitions = {
        leftRight:   ['vs Left', 'vs Right'],
        homeAway:    ['Home Games', 'Away Games'],
        grassTurf:   ['On Grass', 'On Turf'],
        dayNight:    ['Day Games', 'Night Games'],
        currentLast: ['Current Month', 'Last 30 Days']
      };

      for (tableName in tableDefinitions) {
        if (tableDefinitions.hasOwnProperty(tableName)) {
          tableDefinition = tableDefinitions[tableName];

          if (tableDefinition.length > 0) {

            table = $('<table></table>').addClass('quick_splits');
            tbody = $('<tbody></tbody>');

            for (i = 0, n = tableDefinition.length; i < n; ++i) {

              key = tableDefinition[i];
              val = getDeepValue(splits, key + '.avg') || '--';

              if (key === 'Current Month') {
                key = DT.getMonthFullName((new Date()).getMonth() + 1);
              }

              $('<tr></tr>').append(
                $('<th></th>').text(key),
                $('<td></td>').text(val)
              ).appendTo(tbody);
            }

            tbody.appendTo(table);
            tables[tableName] = table;
          }
        }
      }

      splitsPanel
        .empty()
        .append($('<div></div>')
          .attr('id', 'splits_col_left')
          .append(tables.leftRight)
          .append(tables.homeAway)
          .append(tables.grassTurf))
        .append($('<div></div>')
          .attr('id', 'splits_col_right')
          .append(tables.dayNight)
          .append(tables.currentLast));
    }
  },

  handleLoadSplitsError = function () {
    splitsPanel.html(ERROR_LOADING_DATA);
  },

  handleLoadSplitsComplete = function () {
    splitsPanel.removeClass(LOADING_MASK_CLASS_NAME);
  },

  loadSplits = function (playerId, statType, season) {

    if (splitsLoaded) {
      return;
    }

    splitsLoaded = true;
    splitsConfig = splitsConfig || splitsConfigFactory(statType);
    splitsPanel  = $('#splitsPanel');

    // Configure request
    var cfg = splitsConfig,
        params = {
          sport_code: MLB_SPORT_CODE,
          game_type:  GAME_TYPE_REGULAR_SEASON,
          season:     season,
          player_id:  playerId
        };

    // Optimize query
    params[cfg.colInProperty] = [SIT_DESC, AVG];

    $.ajax({
      url:      cfg.url,
      dataType: 'json',
      data:     params,
      success:  handleLoadSplitsSuccess,
      error:    handleLoadSplitsError,
      complete: handleLoadSplitsComplete
    });
  },

  /* INIT *******************************************************************/

  initPitchingStats = function () {

  },

  initPlayerStats = function () {

    // Import globals into closure
    globals   = window.globals;
    flags     = window.flags;
    clubProps = window.clubProps;

    var playerId = globals.player_id,
        statType = globals.statType,
        season   = globals.season,
        clubId   = globals.cid;

    $.ajaxSetup({
      timeout: 30000
    });

    $('.stats_table th.sortable, .expandable_toggle')
      .live('mouseover', function () {
        $(this).addClass('hover');
      })
      .live('mouseout', function () {
        $(this).removeClass('hover');
      });

    careerSummaryPanel = $('#stats_career_summary_wrapper');
    careerPanel        = $('#stats_career_wrapper');

    loadCareerStats(playerId, statType);

    if (flags.is_historical !== 'true') {

      summaryPanel = $('#stats_summary');

      $('#stats_wrapper').tigerTabs({
        beforeShow: function (e, panel) {

          switch(panel) {

            case '#lastTenPanel':
              loadLastTen(playerId, statType, playerbio.utils.get_year());
              break;

            case '#upcomingGamesPanel':
              // @todo DRY this up, decouple ticketing and upcoming games
              // Code duplicated below in $.ready
              if (clubId !== MLB) {
                loadTicketing();
              } else {
                loadUpcomingGames();
              }
              break;

            case '#splitsPanel':
              loadSplits(playerId, statType, season);
              break;
          }
        }
      });

      postSeasonPanel = $('#postseason_stats_wrapper');
      loadPostSeasonStats(playerId, statType, season);

      // Once the page loads, call slow loadUpcomingGames service
      // Remove when query is optimized
      window.setTimeout(function () {
        if (clubId !== MLB) {
          loadTicketing();
        } else {
          loadUpcomingGames();
        }
      }, 1000);
    }
  };

  $(function () {
    playerbio.init();
    initPlayerStats();
  });

})(jQuery, window);
(function ($) {

  $.fn.tigerTabs = function (cfg) {

    var eventDispatcher = $({});

    cfg = $.extend({
      display:      0,
      activeClass:  'active',
      beforeShow:   null,
      afterShow:    null
    }, cfg || {});

    if ($.isFunction(cfg.beforeShow)) {
      eventDispatcher.bind('show:before', cfg.beforeShow);
    }

    if ($.isFunction(cfg.afterShow)) {
      eventDispatcher.bind('show:after', cfg.afterShow);
    }

    return this.each(function () {

      var $this   = $(this),
          $tabs   = $this.find('.tabs a'),
          $panels = $this.find('.panels'),
          active;

      $tabs.click(function (e) {
        e.preventDefault();

        if (active !== this) {

          var $tab = $(this);

          eventDispatcher.trigger('show:before', [this.hash]);
          $(active).removeClass(cfg.activeClass);
          $tab.addClass(cfg.activeClass);
          $panels.find(this.hash).show().siblings().hide();
          active = this;
          eventDispatcher.trigger('show:after', [this.hash]);
        }
      })

      // Display initial panel
      .eq(cfg.display).trigger('click');

    });
  };

})(jQuery);
