';
$td_style = 'padding: 4px 6px; border-bottom: 1px solid rgba(255,255,255,0.05); vertical-align: middle; line-height: 1.2;';
$th_style = 'padding: 8px 6px; border-bottom: 2px solid #555; background-color: #1a1a1a; color: #fff; text-transform: uppercase; font-size: 0.9em;';
if ($is_goalie) {
// 1. Header for Goaltenders (Including GS column)
$html .= '
| Season |
Age |
Team |
League |
GP |
GS |
W |
L |
T/OT |
MIN |
SO |
GA |
SV |
SA |
GAA |
Sv% |
G |
A |
PIM |
';
// 2. Data Rows & Aggregation for Goaltenders
$totals = [
'NHL' => ['GP' => 0, 'GS' => 0, 'W' => 0, 'L' => 0, 'TOT' => 0, 'MIN' => 0, 'SO' => 0, 'GA' => 0, 'SA' => 0, 'G' => 0, 'A' => 0, 'PIM' => 0],
'NYR' => ['GP' => 0, 'GS' => 0, 'W' => 0, 'L' => 0, 'TOT' => 0, 'MIN' => 0, 'SO' => 0, 'GA' => 0, 'SA' => 0, 'G' => 0, 'A' => 0, 'PIM' => 0]
];
$highs = ['GS'=>0, 'W'=>0, 'L'=>0, 'SO'=>0, 'SV_PCT'=>0, 'GAA'=>99, 'G'=>0, 'A'=>0, 'PIM'=>0, 'GP'=>0, 'TOT'=>0, 'MIN'=>0, 'GA'=>0, 'SV'=>0, 'SA'=>0];
$count = 0;
// Helper function to convert MM:SS or HHH:SS to total seconds if not already defined
if (!function_exists('toi_to_seconds_local')) {
function toi_to_seconds_local($toi) {
if (empty($toi)) return 0;
if (is_numeric($toi)) return (int)$toi;
$parts = explode(':', $toi);
if (count($parts) === 2) {
return ((int)$parts[0] * 60) + (int)$parts[1];
}
return 0;
}
}
foreach ($stats as $s) {
$games_started = (isset($s->games_started) && is_numeric($s->games_started)) ? (int)$s->games_started : 0;
$losses = (isset($s->losses) && is_numeric($s->losses)) ? (int)$s->losses : 0;
$ties = (isset($s->ties) && is_numeric($s->ties)) ? (int)$s->ties : 0;
$ot_losses = (isset($s->ot_losses) && is_numeric($s->ot_losses)) ? (int)$s->ot_losses : 0;
$shots_against = (isset($s->shots_against) && is_numeric($s->shots_against)) ? (float)$s->shots_against : 0;
$goals_against = (isset($s->goals_against) && is_numeric($s->goals_against)) ? (float)$s->goals_against : 0;
$tot = $ties + $ot_losses;
$sv = $shots_against - $goals_against;
$y1 = substr($s->season, 0, 4);
$y2 = str_pad((int)substr($s->season, 0, 4) + 1, 4, '0', STR_PAD_LEFT);
$disp_season = $y1 . '-' . substr($y2, 2, 2);
$player_age = $calc_age($s->season, $p->Birthday);
$is_nhl = ($s->league_name === 'NHL');
// Fixed: Explicitly evaluating team_name for New York Rangers rows in otg_goalie_season_stats
$is_nyr = (trim($s->team_name) === 'New York Rangers' && $is_nhl);
$row_classes = 'league-' . ($is_nhl ? 'nhl' : 'other');
if ($is_nyr) {
$row_classes .= ' team-nyr';
}
$display = ($is_nhl || $is_nyr) ? '' : 'display: none;';
$html .= '
| '.esc_html($disp_season).' |
'.esc_html($player_age).' |
'.esc_html($s->team_name).' |
'.esc_html($s->league_name).' |
'.esc_html($s->games_played).' |
'.esc_html($games_started).' |
'.esc_html($s->wins).' |
'.esc_html($losses).' |
'.esc_html($tot).' |
'.esc_html($s->time_on_ice).' |
'.esc_html($s->shutouts).' |
'.esc_html($s->goals_against).' |
'.esc_html($sv).' |
'.esc_html($s->shots_against).' |
'.number_format($s->goals_against_avg, 2).' |
'.number_format($s->save_pctg, 3).' |
'.esc_html($s->goals).' |
'.esc_html($s->assists).' |
'.esc_html($s->pim).' |
';
// Aggregation
if ($is_nhl) {
$t = &$totals['NHL'];
$t['GP'] += (int)$s->games_played;
$t['GS'] += $games_started;
$t['W'] += (int)$s->wins;
$t['L'] += $losses;
$t['TOT'] += $tot;
$t['MIN'] += toi_to_seconds_local($s->time_on_ice);
$t['SO'] += (int)$s->shutouts;
$t['GA'] += (float)$s->goals_against;
$t['SA'] += (float)$s->shots_against;
$t['G'] += (int)$s->goals;
$t['A'] += (int)$s->assists;
$t['PIM'] += (int)$s->pim;
}
if ($is_nyr) {
$t = &$totals['NYR'];
$t['GP'] += (int)$s->games_played;
$t['GS'] += $games_started;
$t['W'] += (int)$s->wins;
$t['L'] += $losses;
$t['TOT'] += $tot;
$t['MIN'] += toi_to_seconds_local($s->time_on_ice);
$t['SO'] += (int)$s->shutouts;
$t['GA'] += (float)$s->goals_against;
$t['SA'] += (float)$s->shots_against;
$t['G'] += (int)$s->goals;
$t['A'] += (int)$s->assists;
$t['PIM'] += (int)$s->pim;
}
// Track Highs (NHL Only)
if ($is_nhl) {
$count++;
$current_gaa = ($s->time_on_ice > 0) ? ($s->goals_against / ($s->time_on_ice / 60)) : 0;
$highs['GP'] = max($highs['GP'], (int)$s->games_played);
$highs['GS'] = max($highs['GS'], (int)$games_started);
$highs['W'] = max($highs['W'], (int)$s->wins);
$highs['L'] = max($highs['L'], (int)$losses);
$highs['TOT'] = max($highs['TOT'], (int)($s->ties + $s->ot_losses));
$highs['SO'] = max($highs['SO'], (int)$s->shutouts);
$highs['GA'] = max($highs['GA'], (int)$s->goals_against);
$highs['G'] = max($highs['G'], (int)$s->goals);
$highs['A'] = max($highs['A'], (int)$s->assists);
$highs['PIM'] = max($highs['PIM'], (int)$s->pim);
$highs['SV_PCT'] = max($highs['SV_PCT'], (float)$s->save_pctg);
$highs['MIN'] = max($highs['MIN'], function_exists('toi_to_seconds') ? toi_to_seconds($s->time_on_ice) : 0);
$highs['SV'] = max($highs['SV'], (int)$sv);
$highs['SA'] = max($highs['SA'], (int)$s->shots_against);
if ($current_gaa > 0) {
$highs['GAA'] = ($highs['GAA'] === 99.00) ? $current_gaa : min($highs['GAA'], $current_gaa);
}
}
}
// 3. Summary Rows with Separator for Goaltenders
$f = 'padding: 7px 4px; font-weight: bold; text-align: center;';
$fl = 'padding: 7px 4px; font-weight: bold; text-align: left;';
$html .= ' |
';
$labels_map = [
'NHL' => 'NHL Career Totals',
'NYR' => 'NYR Career Totals'
];
foreach (['NHL', 'NYR'] as $scope) {
if (!empty($totals[$scope]) && $totals[$scope]['GP'] > 0) {
$t = $totals[$scope];
$row_class = ($scope === 'NYR') ? 'summary-row-nyr' : 'summary-row-nhl';
$sv = $t['SA'] - $t['GA'];
$total_minutes = $t['MIN'] / 60;
$gaa = ($total_minutes > 0) ? ($t['GA'] / ($total_minutes / 60)) : 0;
$svp = ($t['SA'] > 0) ? ($sv / $t['SA']) : 0;
$html .= '';
$html .= '| '.$labels_map[$scope].' | '.($scope === 'NYR' ? 'NHL' : 'NHL').' | ';
$html .= ''.$t['GP'].' | '.$t['GS'].' | '.$t['W'].' | '.$t['L'].' | '.$t['TOT'].' | ';
$html .= ''.(function_exists('format_seconds_to_toi') ? esc_html(format_seconds_to_toi($t['MIN'])) : $t['MIN']).' | ';
$html .= ''.$t['SO'].' | '.$t['GA'].' | ';
$html .= ''.$sv.' | '.$t['SA'].' | ';
$html .= ''.number_format($gaa, 2).' | ';
$html .= ''.number_format($svp, 3).' | ';
$html .= ''.$t['G'].' | '.$t['A'].' | '.$t['PIM'].' | ';
$html .= '
';
}
}
// Career Highs & Averages for Goaltenders
$html .= '
| NHL Career Highs |
NHL |
'.$highs['GP'].' |
'.$highs['GS'].' |
'.$highs['W'].' |
'.$highs['L'].' |
'.$highs['TOT'].' |
'.(function_exists('format_seconds_to_toi') ? format_seconds_to_toi($highs['MIN']) : $highs['MIN']).' |
'.$highs['SO'].' |
'.$highs['GA'].' |
'.$highs['SV'].' |
'.$highs['SA'].' |
'.number_format($highs['GAA'], 2).' |
'.number_format($highs['SV_PCT'], 3).' |
'.$highs['G'].' |
'.$highs['A'].' |
'.$highs['PIM'].' |
';
if ($count > 0 && !empty($totals['NHL'])) {
$t = $totals['NHL'];
$avg_gp = round($t['GP'] / $count);
$avg_gs = round($t['GS'] / $count);
$avg_w = round($t['W'] / $count);
$avg_l = round($t['L'] / $count);
$avg_tot = round($t['TOT'] / $count);
$avg_min_sec = function_exists('format_seconds_to_toi') ? format_seconds_to_toi(floor($t['MIN'] / $count)) : floor($t['MIN'] / $count);
$avg_so = round($t['SO'] / $count);
$avg_ga = round($t['GA'] / $count);
$avg_sv = round(($t['SA'] - $t['GA']) / $count);
$avg_sa = round($t['SA'] / $count);
$total_minutes = $t['MIN'] / 60;
$gaa = ($total_minutes > 0) ? ($t['GA'] / ($total_minutes / 60)) : 0;
$svp = ($t['SA'] > 0) ? (($t['SA'] - $t['GA']) / $t['SA']) : 0;
$html .= '';
$html .= '| NHL Career Averages | NHL | ';
$html .= ''.$avg_gp.' | '.$avg_gs.' | '.$avg_w.' | '.$avg_l.' | '.$avg_tot.' | ';
$html .= ''.$avg_min_sec.' | ';
$html .= ''.$avg_so.' | '.$avg_ga.' | ';
$html .= ''.$avg_sv.' | '.$avg_sa.' | ';
$html .= ''.number_format($gaa, 2).' | ';
$html .= ''.number_format($svp, 3).' | ';
$html .= ''.round($t['G'] / $count).' | ';
$html .= ''.round($t['A'] / $count).' | ';
$html .= ''.round($t['PIM'] / $count).' | ';
$html .= '
';
}
} else {
$html .= '| Season | Age | Team | League | GP | G | A | P | PIM | +/- | PPG | PPP | SHG | SHP | OTG | GWG | S | S% | FO% | TOI |
';
foreach ($stats as $s) {
$y1 = substr($s->season, 0, 4); $y2 = str_pad((int)substr($s->season, 0, 4) + 1, 4, '0', STR_PAD_LEFT); $disp_season = $y1 . '-' . substr($y2, 2, 2);
$player_age = $calc_age($s->season, $p->Birthday);
$is_nhl = ($s->league_name === 'NHL');
$is_nyr = ($s->team_name === 'New York Rangers');
$row_classes = 'league-' . ($is_nhl ? 'nhl' : 'other');
if ($is_nyr) {
$row_classes .= ' team-nyr';
}
$display = ($is_nhl || $is_nyr) ? '' : 'display: none;';
$pm = ($s->plus_minus > 0) ? '+' . $s->plus_minus : $s->plus_minus;
$html .= '| '.esc_html($disp_season).' | '.esc_html($player_age).' | '.esc_html($s->team_name).' | '.esc_html($s->league_name).' | '.esc_html($s->games_played).' | '.esc_html($s->goals).' | '.esc_html($s->assists).' | '.esc_html($s->points).' | '.esc_html($s->pim).' | '.$pm.' | '.esc_html($s->power_play_goals).' | '.esc_html($s->power_play_points).' | '.esc_html($s->shorthanded_goals).' | '.esc_html($s->shorthanded_points).' | '.esc_html($s->ot_goals).' | '.esc_html($s->game_winning_goals).' | '.esc_html($s->shots).' | '.number_format((float)$s->shooting_pctg * 100, 1).'% | '.number_format((float)$s->faceoff_winning_pctg * 100, 1).'% | '.esc_html($s->avg_toi).' |
';
}
$nhl_stats = array_filter($stats, function($s) { return ($s->league_name === 'NHL'); });
$nyr_stats = array_filter($stats, function($s) { return ($s->team_name === 'New York Rangers' && $s->league_name === 'NHL'); });
function get_stats_data($data_set) {
$res = ['GP' => 0, 'G' => 0, 'A' => 0, 'P' => 0, 'PIM' => 0, '+/-' => 0, 'PPG' => 0, 'PPP' => 0, 'SHG' => 0, 'SHP' => 0, 'OTG' => 0, 'GWG' => 0, 'S' => 0, 'TOI_SEC' => 0];
$highs = ['G' => 0, 'A' => 0, 'P' => 0, 'PIM' => 0, 'plus_minus' => -100, 'PPG' => 0, 'PPP' => 0, 'SHG' => 0, 'SHP' => 0, 'OTG' => 0, 'GWG' => 0, 'S' => 0, 'TOI_SEC' => 0];
foreach ($data_set as $s) {
$res['GP'] += $s->games_played; $res['G'] += $s->goals; $res['A'] += $s->assists; $res['P'] += $s->points; $res['PIM'] += $s->pim; $res['+/-'] += $s->plus_minus; $res['PPG'] += $s->power_play_goals; $res['PPP'] += $s->power_play_points; $res['SHG'] += $s->shorthanded_goals; $res['SHP'] += $s->shorthanded_points; $res['OTG'] += $s->ot_goals; $res['GWG'] += $s->game_winning_goals; $res['S'] += $s->shots;
list($m, $ss) = explode(':', $s->avg_toi); $res['TOI_SEC'] += ($m * 60) + $ss;
if ($s->goals > $highs['G']) $highs['G'] = $s->goals;
if ($s->assists > $highs['A']) $highs['A'] = $s->assists;
if ($s->points > $highs['P']) $highs['P'] = $s->points;
if ($s->pim > $highs['PIM']) $highs['PIM'] = $s->pim;
if ($s->plus_minus > $highs['plus_minus']) $highs['plus_minus'] = $s->plus_minus;
if ($s->power_play_goals > $highs['PPG']) $highs['PPG'] = $s->power_play_goals;
if ($s->power_play_points > $highs['PPP']) $highs['PPP'] = $s->power_play_points;
if ($s->shorthanded_goals > $highs['SHG']) $highs['SHG'] = $s->shorthanded_goals;
if ($s->shorthanded_points > $highs['SHP']) $highs['SHP'] = $s->shorthanded_points;
if ($s->ot_goals > $highs['OTG']) $highs['OTG'] = $s->ot_goals;
if ($s->game_winning_goals > $highs['GWG']) $highs['GWG'] = $s->game_winning_goals;
if ($s->shots > $highs['S']) $highs['S'] = $s->shots;
$toi_total = ($m * 60) + $ss;
if ($toi_total > $highs['TOI_SEC']) $highs['TOI_SEC'] = $toi_total;
}
return [$res, $highs];
}
if (!empty($nhl_stats)) {
list($nhl_tot, $nhl_high) = get_stats_data($nhl_stats);
list($nyr_tot, $nyr_high) = get_stats_data($nyr_stats);
$count = count($nhl_stats);
$f = 'padding: 7px 4px; font-weight: bold; vertical-align: middle; text-align: center;';
$fl = 'padding: 7px 4px; font-weight: bold; vertical-align: middle; text-align: left;';
$html .= ' |
';
$html .= '| NHL Career Totals | NHL | '.$nhl_tot['GP'].' | '.$nhl_tot['G'].' | '.$nhl_tot['A'].' | '.$nhl_tot['P'].' | '.$nhl_tot['PIM'].' | '.(($nhl_tot['+/-'] > 0) ? '+' . $nhl_tot['+/-'] : $nhl_tot['+/-']).' | '.$nhl_tot['PPG'].' | '.$nhl_tot['PPP'].' | '.$nhl_tot['SHG'].' | '.$nhl_tot['SHP'].' | '.$nhl_tot['OTG'].' | '.$nhl_tot['GWG'].' | '.$nhl_tot['S'].' | | | |
';
if (!empty($nyr_stats)) {
$html .= '| NYR Career Totals | NHL | '.$nyr_tot['GP'].' | '.$nyr_tot['G'].' | '.$nyr_tot['A'].' | '.$nyr_tot['P'].' | '.$nyr_tot['PIM'].' | '.(($nyr_tot['+/-'] > 0) ? '+' . $nyr_tot['+/-'] : $nyr_tot['+/-']).' | '.$nyr_tot['PPG'].' | '.$nyr_tot['PPP'].' | '.$nyr_tot['SHG'].' | '.$nyr_tot['SHP'].' | '.$nyr_tot['OTG'].' | '.$nyr_tot['GWG'].' | '.$nyr_tot['S'].' | | | |
';
}
$avg_m = floor(($nhl_tot['TOI_SEC'] / $count) / 60); $avg_s = str_pad(round(fmod(($nhl_tot['TOI_SEC'] / $count), 60)), 2, '0', STR_PAD_LEFT);
$html .= '| NHL Career Averages | NHL | '.round($nhl_tot['GP']/$count).' | '.round($nhl_tot['G']/$count).' | '.round($nhl_tot['A']/$count).' | '.round($nhl_tot['P']/$count).' | '.round($nhl_tot['PIM']/$count).' | '.(($nhl_tot['+/-'] > 0) ? '+' . round($nhl_tot['+/-']/$count) : round($nhl_tot['+/-']/$count)).' | '.round($nhl_tot['PPG']/$count).' | '.round($nhl_tot['PPP']/$count).' | '.round($nhl_tot['SHG']/$count).' | '.round($nhl_tot['SHP']/$count).' | '.round($nhl_tot['OTG']/$count).' | '.round($nhl_tot['GWG']/$count).' | '.round($nhl_tot['S']/$count).' | | | '.$avg_m.':'.$avg_s.' |
';
$high_m = floor(($nhl_high['TOI_SEC']) / 60); $high_s = str_pad(round(fmod($nhl_high['TOI_SEC'], 60)), 2, '0', STR_PAD_LEFT);
$html .= '| NHL Career Highs | NHL | | '.$nhl_high['G'].' | '.$nhl_high['A'].' | '.$nhl_high['P'].' | '.$nhl_high['PIM'].' | '.(($nhl_high['plus_minus'] > 0) ? '+' . $nhl_high['plus_minus'] : $nhl_high['plus_minus']).' | '.$nhl_high['PPG'].' | '.$nhl_high['PPP'].' | '.$nhl_high['SHG'].' | '.$nhl_high['SHP'].' | '.$nhl_high['OTG'].' | '.$nhl_high['GWG'].' | '.$nhl_high['S'].' | | | '.$high_m.':'.$high_s.' |
';
}
}
$html .= '