/**
  * If not explicitly specified by the user, infer the player type from the teams involved
  * @param Match $match
  * @return int
  */
 private function WorkOutPlayerType(Match $match)
 {
     require_once 'stoolball/player-type.enum.php';
     /* @var $match Match */
     # If player type is already specified, leave it alone. That should be the case for a tournament.
     if (!is_null($match->GetPlayerType())) {
         return $match->GetPlayerType();
     }
     # Second strategy, look at the teams playing the match
     $teams = $match->GetAwayTeams();
     if ($match->GetHomeTeamId()) {
         $teams[] = $match->GetHomeTeam();
     }
     if (count($teams)) {
         # Get the team ids...
         $team_ids = array();
         foreach ($teams as $team) {
             $team_ids[] = $team->GetId();
         }
         # And use them to get the team player types...
         $sql = "SELECT DISTINCT player_type_id FROM nsa_team WHERE team_id IN (" . implode(',', $team_ids) . ")";
         $result = $this->GetDataConnection()->query($sql);
         $player_types = array();
         while ($row = $result->fetch()) {
             $player_types[] = $row->player_type_id;
         }
         $result->closeCursor();
         return $this->WorkOutPlayerTypeHelper($player_types);
     }
     # Third strategy, if no teams it could be a cup match where the teams will be known later?
     # Look at the player types of the seasons it's involved in.
     if ($match->Seasons()->GetCount()) {
         # Get the season ids...
         $season_ids = array();
         foreach ($match->Seasons() as $season) {
             $season_ids[] = $season->GetId();
         }
         # And use them to get the season player types...
         $season = $this->GetSettings()->GetTable('Season');
         $comp = $this->GetSettings()->GetTable('Competition');
         $sql = "SELECT DISTINCT player_type_id FROM {$season} INNER JOIN {$comp} ON {$season}.competition_id = {$comp}.competition_id " . "WHERE season_id IN (" . implode(',', $season_ids) . ")";
         $result = $this->GetDataConnection()->query($sql);
         $player_types = array();
         while ($row = $result->fetch()) {
             $player_types[] = $row->player_type_id;
         }
         $result->closeCursor();
         return $this->WorkOutPlayerTypeHelper($player_types);
     }
     # Seems a bit unlikely you could have a match without any seasons or any teams, but just in case...
     return null;
 }
 /**
  * Sets up controls for page 4 of the wizard
  * @param Match $match
  * @return void
  */
 private function CreateHighlightsControls(Match $match)
 {
     $b_got_teams = !(is_null($match->GetHomeTeam()) || is_null($match->GetAwayTeam()));
     // Move CSS class to div element
     $match_outer_1 = new XhtmlElement('div');
     $match_outer_1->SetCssClass('matchResultEdit panel');
     $match_outer_2 = new XhtmlElement('div');
     $match_box = new XhtmlElement('div');
     $this->AddControl($match_outer_1);
     $match_outer_1->AddControl($match_outer_2);
     $match_outer_2->AddControl($match_box);
     $o_title_inner_1 = new XhtmlElement('span', "Match highlights");
     $o_title_inner_2 = new XhtmlElement('span', $o_title_inner_1);
     $o_title_inner_3 = new XhtmlElement('span', $o_title_inner_2);
     $o_heading = new XhtmlElement('h2', $o_title_inner_3);
     $match_box->AddControl($o_heading);
     # Who's playing?
     $o_home_name = new TextBox($this->GetNamingPrefix() . 'Home');
     $o_away_name = new TextBox($this->GetNamingPrefix() . 'Away');
     $o_home_name->SetMode(TextBoxMode::Hidden());
     $o_away_name->SetMode(TextBoxMode::Hidden());
     if (!is_null($match->GetHomeTeam())) {
         $o_home_name->SetText($match->GetHomeTeam()->GetId() . MatchHighlightsEditControl::DATA_SEPARATOR . $match->GetHomeTeam()->GetName());
     }
     if (!is_null($match->GetAwayTeam())) {
         $o_away_name->SetText($match->GetAwayTeam()->GetId() . MatchHighlightsEditControl::DATA_SEPARATOR . $match->GetAwayTeam()->GetName());
     }
     $this->AddControl($o_home_name);
     $this->AddControl($o_away_name);
     # When? (for validator message only)
     $when = new TextBox($this->GetNamingPrefix() . 'Date', $match->GetStartTime());
     $when->SetMode(TextBoxMode::Hidden());
     $this->AddControl($when);
     # Who won?
     $o_winner = new XhtmlSelect($this->GetNamingPrefix() . 'Result');
     $o_winner->AddControl(new XhtmlOption("Don't know", ''));
     $result_types = array(MatchResult::HOME_WIN, MatchResult::AWAY_WIN, MatchResult::TIE, MatchResult::ABANDONED);
     foreach ($result_types as $result_type) {
         if ($b_got_teams) {
             $o_winner->AddControl(new XhtmlOption($this->NameTeams(MatchResult::Text($result_type), $match->GetHomeTeam(), $match->GetAwayTeam()), $result_type));
         } else {
             $o_winner->AddControl(new XhtmlOption(MatchResult::Text($result_type), $result_type));
         }
     }
     if ($this->IsValidSubmit()) {
         if ($match->Result()->GetResultType() == MatchResult::UNKNOWN and !is_null($match->Result()->GetHomeRuns()) and !is_null($match->Result()->GetAwayRuns())) {
             # If match result is not known but we can guess from the entered scores, select it
             if ($match->Result()->GetHomeRuns() > $match->Result()->GetAwayRuns()) {
                 $o_winner->SelectOption(MatchResult::HOME_WIN);
             } else {
                 if ($match->Result()->GetHomeRuns() < $match->Result()->GetAwayRuns()) {
                     $o_winner->SelectOption(MatchResult::AWAY_WIN);
                 } else {
                     if ($match->Result()->GetHomeRuns() == $match->Result()->GetAwayRuns()) {
                         $o_winner->SelectOption(MatchResult::TIE);
                     }
                 }
             }
         } else {
             $o_winner->SelectOption($match->Result()->GetResultType());
         }
     }
     $o_win_part = new FormPart('Who won?', $o_winner);
     $match_box->AddControl($o_win_part);
     # Get current player of match
     $player = $match->Result()->GetPlayerOfTheMatch();
     $home_player = $match->Result()->GetPlayerOfTheMatchHome();
     $away_player = $match->Result()->GetPlayerOfTheMatchAway();
     $current_pom = MatchHighlightsEditControl::PLAYER_OF_THE_MATCH_NONE;
     if ($player instanceof Player) {
         $current_pom = MatchHighlightsEditControl::PLAYER_OF_THE_MATCH_OVERALL;
     } else {
         if ($home_player instanceof Player or $away_player instanceof Player) {
             $current_pom = MatchHighlightsEditControl::PLAYER_OF_THE_MATCH_HOME_AND_AWAY;
         }
     }
     # Choose from different types of player of the match
     require_once 'xhtml/forms/radio-button.class.php';
     $pom_container = new XhtmlElement('fieldset', new XhtmlElement('legend', 'Player of the match', 'formLabel'));
     $pom_container->SetCssClass('formPart');
     $pom_options = new XhtmlElement('div', null, 'formControl radioButtonList');
     $pom_options->SetXhtmlId($this->GetNamingPrefix() . "PlayerOptions");
     $pom_container->AddControl($pom_options);
     $match_box->AddControl($pom_container);
     $pom_options->AddControl(new RadioButton($this->GetNamingPrefix() . 'POM' . MatchHighlightsEditControl::PLAYER_OF_THE_MATCH_NONE, $this->GetNamingPrefix() . 'POM', "none chosen", MatchHighlightsEditControl::PLAYER_OF_THE_MATCH_NONE, $current_pom == MatchHighlightsEditControl::PLAYER_OF_THE_MATCH_NONE, $this->IsValidSubmit()));
     $pom_options->AddControl(new RadioButton($this->GetNamingPrefix() . 'POM' . MatchHighlightsEditControl::PLAYER_OF_THE_MATCH_OVERALL, $this->GetNamingPrefix() . 'POM', "yes, one chosen", MatchHighlightsEditControl::PLAYER_OF_THE_MATCH_OVERALL, $current_pom == MatchHighlightsEditControl::PLAYER_OF_THE_MATCH_OVERALL, $this->IsValidSubmit()));
     $pom_options->AddControl(new RadioButton($this->GetNamingPrefix() . 'POM' . MatchHighlightsEditControl::PLAYER_OF_THE_MATCH_HOME_AND_AWAY, $this->GetNamingPrefix() . 'POM', "yes, one from each team", MatchHighlightsEditControl::PLAYER_OF_THE_MATCH_HOME_AND_AWAY, $current_pom == MatchHighlightsEditControl::PLAYER_OF_THE_MATCH_HOME_AND_AWAY, $this->IsValidSubmit()));
     # Controls for entering a single player of the match
     $player_name = new TextBox($this->GetNamingPrefix() . 'Player', $player instanceof Player ? $player->GetName() : '', $this->IsValidSubmit());
     $player_name->SetMaxLength(100);
     $player_name->AddCssClass("player");
     $player_name->AddCssClass("team" . $match->GetHomeTeamId());
     $player_name->AddCssClass("team" . $match->GetAwayTeamId());
     $player_name->AddAttribute("autocomplete", "off");
     $player_box = new XhtmlElement("div", $player_name);
     $player_team = new XhtmlSelect($this->GetNamingPrefix() . "PlayerTeam", " playing for", $this->IsValidSubmit());
     $player_team->SetCssClass("playerTeam");
     # for JS
     $player_team->AddControl(new XhtmlOption("Don't know", ""));
     $player_team->AddControl(new XhtmlOption($match->GetHomeTeam()->GetName(), $match->GetHomeTeamId()));
     $player_team->AddControl(new XhtmlOption($match->GetAwayTeam()->GetName(), $match->GetAwayTeamId()));
     if ($player instanceof Player) {
         $player_team->SelectOption($player->Team()->GetId());
     }
     $player_box->AddControl($player_team);
     $player_part = new FormPart("Player's name", $player_box);
     $player_part->SetXhtmlId($this->GetNamingPrefix() . "OnePlayer");
     $player_part->GetLabel()->AddAttribute("for", $player_name->GetXhtmlId());
     $match_box->AddControl($player_part);
     # Controls for entering home and away players of the match
     $home_box = new TextBox($this->GetNamingPrefix() . 'PlayerHome', $home_player instanceof Player ? $home_player->GetName() : '', $this->IsValidSubmit());
     $home_box->SetMaxLength(100);
     $home_box->AddCssClass("player");
     $home_box->AddCssClass("team" . $match->GetHomeTeamId());
     $home_box->AddAttribute("autocomplete", "off");
     $home_part = new FormPart($this->NameTeams('Home player', $match->GetHomeTeam(), $match->GetAwayTeam()), $home_box);
     $home_part->SetCssClass("formPart multiPlayer");
     $match_box->AddControl($home_part);
     $away_box = new TextBox($this->GetNamingPrefix() . 'PlayerAway', $away_player instanceof Player ? $away_player->GetName() : '', $this->IsValidSubmit());
     $away_box->SetMaxLength(100);
     $away_box->AddCssClass("player");
     $away_box->AddCssClass("team" . $match->GetAwayTeamId());
     $away_box->AddAttribute("autocomplete", "off");
     $away_part = new FormPart($this->NameTeams('Away player', $match->GetHomeTeam(), $match->GetAwayTeam()), $away_box);
     $away_part->SetCssClass("formPart multiPlayer");
     $match_box->AddControl($away_part);
     # Any comments?
     $comments = new TextBox($this->GetNamingPrefix() . 'Comments', '', $this->IsValidSubmit());
     $comments->SetMode(TextBoxMode::MultiLine());
     $comments->AddAttribute('class', 'matchReport');
     $comments_label = new XhtmlElement('label');
     $comments_label->AddAttribute('for', $comments->GetXhtmlId());
     $comments_label->AddCssClass('matchReport');
     $comments_label->AddControl('Add a match report:');
     $match_box->AddControl($comments_label);
     $match_box->AddControl($comments);
     if ($match->GetLastAudit() != null) {
         require_once "data/audit-control.class.php";
         $match_box->AddControl(new AuditControl($match->GetLastAudit(), "match"));
     }
     $this->SetButtonText('Save match');
 }
 /**
  * Creates a dropdown list to select either "don't know" or one of the two playing teams
  */
 private function SelectOneOfTwoTeams($list_id, Match $match, $select_home_if, $select_away_if)
 {
     $list = new XhtmlSelect($list_id);
     $list->AddControl(new XhtmlOption("Don't know", ''));
     $list->AddControl(new XhtmlOption(!is_null($match->GetHomeTeam()) ? $match->GetHomeTeam()->GetName() : 'Home team', TeamRole::Home(), $select_home_if));
     $list->AddControl(new XhtmlOption(!is_null($match->GetAwayTeam()) ? $match->GetAwayTeam()->GetName() : 'Away team', TeamRole::Away(), $select_away_if));
     return $list;
 }
 protected function CreateControls()
 {
     $o_match = $this->GetDataObject();
     if (is_null($o_match)) {
         $o_match = new Match($this->GetSettings());
     }
     /* @var $o_match Match */
     /* @var $o_team Team */
     $b_got_home = !is_null($o_match->GetHomeTeam());
     $b_got_away = !is_null($o_match->GetAwayTeam());
     $b_is_new_match = !(bool) $o_match->GetId();
     $b_is_tournament_match = false;
     if ($this->i_match_type == MatchType::TOURNAMENT_MATCH) {
         $b_is_tournament_match = $this->tournament instanceof Match;
     } else {
         if ($o_match->GetMatchType() == MatchType::TOURNAMENT_MATCH and $o_match->GetTournament() instanceof Match) {
             $this->SetTournament($o_match->GetTournament());
             $this->SetMatchType($o_match->GetMatchType());
             $b_is_tournament_match = true;
         }
     }
     $o_match_outer_1 = new XhtmlElement('div');
     $o_match_outer_1->SetCssClass('MatchFixtureEdit');
     $o_match_outer_1->AddCssClass($this->GetCssClass());
     $this->SetCssClass('');
     $o_match_outer_1->SetXhtmlId($this->GetNamingPrefix());
     $o_match_outer_2 = new XhtmlElement('div');
     $o_match_box = new XhtmlElement('div');
     $this->AddControl($o_match_outer_1);
     $o_match_outer_1->AddControl($o_match_outer_2);
     $o_match_outer_2->AddControl($o_match_box);
     if ($this->GetShowHeading()) {
         $s_heading = str_replace('{0}', MatchType::Text($this->i_match_type), $this->GetHeading());
         # Add match type if required
         $o_title_inner_1 = new XhtmlElement('span', htmlentities($s_heading, ENT_QUOTES, "UTF-8", false));
         $o_title_inner_2 = new XhtmlElement('span', $o_title_inner_1);
         $o_title_inner_3 = new XhtmlElement('span', $o_title_inner_2);
         $o_match_box->AddControl(new XhtmlElement('h2', $o_title_inner_3, "medium large"));
     }
     # Offer choice of season if appropriate
     $season_count = $this->seasons->GetCount();
     if ($season_count == 1 and $this->i_match_type != MatchType::PRACTICE) {
         $o_season_id = new TextBox($this->GetNamingPrefix() . 'Season', $this->seasons->GetFirst()->GetId());
         $o_season_id->SetMode(TextBoxMode::Hidden());
         $o_match_box->AddControl($o_season_id);
     } elseif ($season_count > 1 and $this->i_match_type != MatchType::PRACTICE) {
         $o_season_id = new XhtmlSelect($this->GetNamingPrefix() . 'Season', '', $this->IsValidSubmit());
         foreach ($this->Seasons()->GetItems() as $season) {
             $o_season_id->AddControl(new XhtmlOption($season->GetCompetitionName(), $season->GetId()));
         }
         $o_match_box->AddControl(new FormPart('Competition', $o_season_id));
     }
     # Start date and time
     $match_time_known = (bool) $o_match->GetStartTime();
     if (!$match_time_known) {
         # if no date set, use specified default
         if ($this->i_default_time) {
             $o_match->SetStartTime($this->i_default_time);
             if ($b_is_tournament_match) {
                 $o_match->SetIsStartTimeKnown(false);
             }
         } else {
             # if no date set and no default, default to today at 6.30pm BST
             $i_now = gmdate('U');
             $o_match->SetStartTime(gmmktime(17, 30, 00, (int) gmdate('n', $i_now), (int) gmdate('d', $i_now), (int) gmdate('Y', $i_now)));
         }
     }
     $o_date = new DateControl($this->GetNamingPrefix() . 'Start', $o_match->GetStartTime(), $o_match->GetIsStartTimeKnown(), $this->IsValidSubmit());
     $o_date->SetShowTime(true);
     $o_date->SetRequireTime(false);
     $o_date->SetMinuteInterval(5);
     # if no date set and only one season to choose from, limit available dates to the length of that season
     if (!$match_time_known and $season_count == 1) {
         if ($this->Seasons()->GetFirst()->GetStartYear() == $this->Seasons()->GetFirst()->GetEndYear()) {
             $i_mid_season = gmmktime(0, 0, 0, 6, 30, $this->Seasons()->GetFirst()->GetStartYear());
         } else {
             $i_mid_season = gmmktime(0, 0, 0, 12, 31, $this->Seasons()->GetFirst()->GetStartYear());
         }
         $season_dates = Season::SeasonDates($i_mid_season);
         $season_start_month = gmdate('n', $season_dates[0]);
         $season_end_month = gmdate('n', $season_dates[1]);
         if ($season_start_month) {
             $o_date->SetMonthStart($season_start_month);
         }
         if ($season_end_month) {
             $o_date->SetMonthEnd($season_end_month + 1);
         }
         // TODO: need a better way to handle this, allowing overlap. Shirley has indoor matches until early April.
         $season_start_year = $this->Seasons()->GetFirst()->GetStartYear();
         $season_end_year = $this->Seasons()->GetFirst()->GetEndYear();
         if ($season_start_year) {
             $o_date->SetYearStart($season_start_year);
         }
         if ($season_end_year) {
             $o_date->SetYearEnd($season_end_year);
         }
     }
     if ($b_is_tournament_match) {
         $o_date->SetShowDate(false);
         $o_date->SetShowTime(false);
         $o_match_box->AddControl($o_date);
     } else {
         $o_date_part = new FormPart('When?', $o_date);
         $o_date_part->SetIsFieldset(true);
         $o_match_box->AddControl($o_date_part);
     }
     # Who's playing?
     if ($this->i_match_type == MatchType::PRACTICE and isset($this->context_team)) {
         $home_id = new TextBox($this->GetNamingPrefix() . 'Home', $this->context_team->GetId());
         $home_id->SetMode(TextBoxMode::Hidden());
         $away_id = new TextBox($this->GetNamingPrefix() . 'Away', $this->context_team->GetId());
         $away_id->SetMode(TextBoxMode::Hidden());
         $o_match_box->AddControl($home_id);
         $o_match_box->AddControl($away_id);
     } else {
         $o_home_list = new XhtmlSelect($this->GetNamingPrefix() . 'Home');
         $o_away_list = new XhtmlSelect($this->GetNamingPrefix() . 'Away');
         $first_real_team_index = 0;
         if ($this->b_user_is_admin) {
             # Option of not specifying teams is currently admin-only
             # Value of 0 is important because PHP sees it as boolean negative, but it can be used as the indexer of an array in JavaScript
             $o_home_list->AddControl(new XhtmlOption("Don't know yet", '0'));
             $o_away_list->AddControl(new XhtmlOption("Don't know yet", '0'));
             $first_real_team_index = 1;
         }
         foreach ($this->a_teams as $group_name => $teams) {
             foreach ($teams as $o_team) {
                 $home_option = new XhtmlOption($o_team->GetName(), $o_team->GetId());
                 if (is_string($group_name) and $group_name) {
                     $home_option->SetGroupName($group_name);
                 }
                 $o_home_list->AddControl($home_option);
                 $away_option = new XhtmlOption($o_team->GetName(), $o_team->GetId());
                 if (is_string($group_name) and $group_name) {
                     $away_option->SetGroupName($group_name);
                 }
                 $o_away_list->AddControl($away_option);
             }
         }
         $o_home_part = new FormPart('Home team', $o_home_list);
         $o_away_part = new FormPart('Away team', $o_away_list);
         $o_match_box->AddControl($o_home_part);
         $o_match_box->AddControl($o_away_part);
         if ($b_got_home) {
             $o_home_list->SelectOption($o_match->GetHomeTeamId());
         }
         if (!$b_got_home and $b_is_new_match) {
             // if no home team data, select the first team by default
             // unless editing a match, in which case it may be correct to have no teams (eg cup final)
             $o_home_list->SelectIndex($first_real_team_index);
         }
         if (!$b_got_away and $b_is_new_match) {
             // if no away team data, select the second team as the away team so that it's not the same as the first
             // unless editing a match, in which case it may be correct to have no teams (eg cup final).
             $o_away_list->SelectIndex($first_real_team_index + 1);
             // if there was a home team but not an away team, make sure we don't select the home team against itself
             if ($b_got_home and $o_away_list->GetSelectedValue() == (string) $o_match->GetHomeTeamId()) {
                 $o_away_list->SelectIndex($first_real_team_index);
             }
         } else {
             if ($b_got_away) {
                 $o_away_list->SelectOption($o_match->GetAwayTeamId());
             }
             if (!$b_is_new_match) {
                 # Note which away team was previously saved, even if it's "not known" - this is for JavaScript to know it shouldn't auto-change the away team
                 $away_saved = new TextBox($this->GetNamingPrefix() . 'SavedAway', $o_match->GetAwayTeamId());
                 $away_saved->SetMode(TextBoxMode::Hidden());
                 $o_match_box->AddControl($away_saved);
                 unset($away_saved);
             }
         }
     }
     # Where?
     # If tournament match, assume same ground as tournament. Otherwise ask the user for ground.
     if ($b_is_tournament_match) {
         $ground = new TextBox($this->GetNamingPrefix() . 'Ground', $this->tournament->GetGroundId() ? $this->tournament->GetGroundId() : $o_match->GetGroundId());
         $ground->SetMode(TextBoxMode::Hidden());
         $o_match_box->AddControl($ground);
     } else {
         $o_ground_list = new XhtmlSelect($this->GetNamingPrefix() . 'Ground');
         $o_ground_list->AddControl(new XhtmlOption("Don't know", -1));
         $o_ground_list->AddControl(new XhtmlOption('Not listed (type the address in the notes field)', -2));
         # Promote home grounds for this season to the top of the list
         $a_home_ground_ids = array();
         foreach ($this->a_teams as $teams) {
             foreach ($teams as $o_team) {
                 $a_home_ground_ids[$o_team->GetId()] = $o_team->GetGround()->GetId();
             }
         }
         $a_home_grounds = array();
         $a_other_grounds = array();
         /* @var $o_ground Ground */
         foreach ($this->a_grounds as $o_ground) {
             if (array_search($o_ground->GetId(), $a_home_ground_ids) > -1) {
                 $a_home_grounds[] = $o_ground;
             } else {
                 $a_other_grounds[] = $o_ground;
             }
         }
         # Add home grounds
         foreach ($a_home_grounds as $o_ground) {
             $option = new XhtmlOption($o_ground->GetNameAndTown(), $o_ground->GetId());
             $option->SetGroupName('Home grounds');
             $o_ground_list->AddControl($option);
         }
         # Add away grounds
         foreach ($a_other_grounds as $o_ground) {
             $option = new XhtmlOption($o_ground->GetNameAndTown(), $o_ground->GetId());
             $option->SetGroupName('Away grounds');
             $o_ground_list->AddControl($option);
         }
         # Select ground
         if ($o_match->GetGroundId()) {
             $o_ground_list->SelectOption($o_match->GetGroundId());
         } elseif ($this->i_match_type == MatchType::PRACTICE and isset($this->context_team)) {
             $o_ground_list->SelectOption($this->context_team->GetGround()->GetId());
         }
         $o_ground_part = new FormPart('Where?', $o_ground_list);
         $o_match_box->AddControl($o_ground_part);
         # Note which grounds belong to which teams, for use by match-fixture-edit-control.js to select a ground when the home team is changed
         # Format is 1,2;2,3;4,5
         # where ; separates each team, and for each team the first number identifies the team and the second is the ground
         $s_team_ground = '';
         foreach ($a_home_ground_ids as $i_team => $i_ground) {
             if ($s_team_ground) {
                 $s_team_ground .= ';';
             }
             $s_team_ground .= $i_team . ',' . $i_ground;
         }
         $o_hidden = new TextBox($this->GetNamingPrefix() . 'TeamGround', $s_team_ground);
         $o_hidden->SetMode(TextBoxMode::Hidden());
         $o_match_box->AddControl($o_hidden);
         unset($o_hidden);
         # Note which ground was previously saved - this is for JavaScript to know it shouldn't auto-change the ground
         if (!$b_is_new_match) {
             $o_hidden = new TextBox($this->GetNamingPrefix() . 'SavedGround', $o_match->GetGroundId());
             $o_hidden->SetMode(TextBoxMode::Hidden());
             $o_match_box->AddControl($o_hidden);
             unset($o_hidden);
         }
     }
     # Notes
     $o_notes = new TextBox($this->GetNamingPrefix() . 'Notes', $o_match->GetNotes());
     $o_notes->SetMode(TextBoxMode::MultiLine());
     $o_notes_part = new FormPart('Notes', $o_notes);
     $o_match_box->AddControl($o_notes_part);
     # Remember match type, tournament and short URL
     $o_type = new TextBox($this->GetNamingPrefix() . 'MatchType', $this->GetMatchType());
     $o_type->SetMode(TextBoxMode::Hidden());
     $o_match_box->AddControl($o_type);
     if ($b_is_tournament_match) {
         $tourn_box = new TextBox($this->GetNamingPrefix() . 'Tournament', $this->tournament->GetId());
         $tourn_box->SetMode(TextBoxMode::Hidden());
         $o_match_box->AddControl($tourn_box);
     }
     $o_short_url = new TextBox($this->GetNamingPrefix() . 'ShortUrl', $o_match->GetShortUrl());
     $o_short_url->SetMode(TextBoxMode::Hidden());
     $o_match_box->AddControl($o_short_url);
     # Note the context team - to be picked up by JavaScript to enable auto-changing of away team if
     # context team is not selected as home team
     if (isset($this->context_team)) {
         $context_team_box = new TextBox($this->GetNamingPrefix() . 'ContextTeam', $this->context_team->GetId());
         $context_team_box->SetMode(TextBoxMode::Hidden());
         $o_match_box->AddControl($context_team_box);
     }
 }
    /**
     * Helper to build and send the email when a match has been added by a public user
     *
     * @param Match $o_match
     * @param User $o_user
     * @param bool $b_is_new_match
     * @param bool $b_is_deleted_match
     * @param string $s_email
     * @param Season[] $seasons
     */
    private function SendMatchUpdatedEmail(Match $o_match, User $o_user, $b_is_new_match, $b_is_deleted_match, $s_email, $seasons = null)
    {
        # text of email
        $s_season_list = '';
        if (is_array($seasons)) {
            $i_total_seasons = count($seasons);
            for ($i = 0; $i < $i_total_seasons; $i++) {
                if ($i == 0) {
                    $s_season_list = "'" . $seasons[$i]->GetCompetitionName() . "'";
                } else {
                    if ($i == $i_total_seasons - 1) {
                        $s_season_list .= " and '" . $seasons[$i]->GetCompetitionName() . "'";
                    } else {
                        $s_season_list .= ", '" . $seasons[$i]->GetCompetitionName() . "'";
                    }
                }
            }
        }
        $s_season = $s_season_list ? " in the {$s_season_list}" : '';
        $s_why = $s_season_list ? $s_season_list : 'matches';
        $new = $b_is_new_match ? 'new ' : '';
        $verb = $b_is_new_match ? 'added' : 'updated';
        if ($b_is_deleted_match) {
            $verb = 'deleted';
        }
        $match_text = $o_match->GetMatchType() == MatchType::TOURNAMENT ? 'tournament' : 'match';
        $s_title = html_entity_decode($o_match->GetTitle());
        $s_date = ucfirst($o_match->GetStartTimeFormatted());
        $s_ground = is_object($o_match->GetGround()) ? $o_match->GetGround()->GetNameAndTown() : '';
        $s_notes = $o_match->GetNotes();
        $s_domain = $this->settings->GetDomain();
        $s_url = 'https://' . $s_domain . $o_match->GetNavigateUrl();
        $s_contact_url = 'https://' . $s_domain . $this->settings->GetFolder('Contact');
        $s_home_name = $o_match->GetMatchType() == MatchType::TOURNAMENT ? '' : html_entity_decode($o_match->GetHomeTeam()->GetName());
        $s_away_name = $o_match->GetMatchType() == MatchType::TOURNAMENT ? '' : html_entity_decode($o_match->GetAwayTeam()->GetName());
        $s_bat_first = is_null($o_match->Result()->GetHomeBattedFirst()) ? 'Not known which team batted first' : ($o_match->Result()->GetHomeBattedFirst() ? $s_home_name : $s_away_name) . ' batted first';
        $s_home_runs = is_null($o_match->Result()->GetHomeRuns()) ? '(not known)' : $o_match->Result()->GetHomeRuns();
        $s_home_wickets = is_null($o_match->Result()->GetHomeWickets()) ? '(not known)' : $o_match->Result()->GetHomeWickets();
        if ($s_home_wickets == -1) {
            $s_home_wickets = 'all out';
        } else {
            $s_home_wickets = 'for ' . $s_home_wickets . ' wickets';
        }
        $s_away_runs = is_null($o_match->Result()->GetAwayRuns()) ? '(not known)' : $o_match->Result()->GetAwayRuns();
        $s_away_wickets = is_null($o_match->Result()->GetAwayWickets()) ? '(not known)' : $o_match->Result()->GetAwayWickets();
        if ($s_away_wickets == -1) {
            $s_away_wickets = 'all out';
        } else {
            $s_away_wickets = 'for ' . $s_away_wickets . ' wickets';
        }
        $s_user = $o_user->GetName();
        $s_body = wordwrap("A {$new}{$match_text} has been {$verb} on the Stoolball England website at {$s_domain}{$s_season}.\n\n" . "The {$match_text} was {$verb} by {$s_user}.\n\n" . "The {$match_text} details are as follows:\n\n" . "    {$s_title}\n" . "    {$s_date}\n" . "    {$s_ground}");
        if ($s_notes) {
            $s_notes = "\n\n" . wordwrap($s_notes, 70);
            $s_notes = str_replace("\n", "\n    ", $s_notes);
            $s_body .= $s_notes;
        }
        if ($o_match->GetStartTime() <= gmdate('U') and !$b_is_new_match and $o_match->GetMatchType() != MatchType::TOURNAMENT) {
            $s_body .= <<<EMAILBODY


\t{$s_bat_first}
EMAILBODY;
            if ($o_match->Result()->GetHomeBattedFirst() === false) {
                $s_body .= <<<EMAILBODY

\t{$s_away_name} score: {$s_away_runs} runs {$s_away_wickets}
\t{$s_home_name} score: {$s_home_runs} runs {$s_home_wickets}
EMAILBODY;
            } else {
                $s_body .= <<<EMAILBODY

\t{$s_home_name} score: {$s_home_runs} runs {$s_home_wickets}
\t{$s_away_name} score: {$s_away_runs} runs {$s_away_wickets}
EMAILBODY;
            }
        }
        $s_body .= "\n\n";
        if (!$b_is_deleted_match) {
            $s_body .= wordwrap("You can view the {$match_text} at {$s_url}\n\n");
        }
        $s_body .= wordwrap("You have received this email because you are the administrative contact for {$s_why} on {$s_domain}.\n\n" . "We let you know when a {$match_text} is {$verb} by a member of the public, so that you can check there's nothing wrong.\n\n" . "If this email has been sent to the wrong address, or if the {$match_text} details are wrong, please let us know using the contact form at {$s_contact_url}.\n\n");
        # send email, copy to me
        require_once 'Zend/Mail.php';
        $o_email = new Zend_Mail('UTF-8');
        $o_email->addTo($s_email);
        $o_email->setFrom('*****@*****.**', 'Stoolball England alerts');
        $o_email->setSubject(ucfirst($match_text) . " {$verb}: {$s_title}, {$s_date}");
        $o_email->setBodyText($s_body);
        try {
            $o_email->send();
        } catch (Zend_Mail_Transport_Exception $e) {
            # Do nothing - failure to send this email should not be a fatal error
        }
    }
    public function OnLoadPageData()
    {
        $match_manager = new MatchManager($this->GetSettings(), $this->GetDataConnection());
        $match_manager->ReadByMatchId(array($_GET['match']));
        $match_manager->ExpandMatchScorecards();
        $this->match = $match_manager->GetFirst();
        unset($match_manager);
        if ($this->match->GetHomeTeam() instanceof Team and $this->match->GetAwayTeam() instanceof Team) {
            ?>
{
    "worm": {
        "labels": [
            <?php 
            $overs = $this->HowManyOversInTheMatch();
            echo $this->BuildOversLabels(0, $overs);
            ?>
        
        ],
        "datasets": [
        <?php 
            $home_batted_first = $this->match->Result()->GetHomeBattedFirst();
            if ($home_batted_first === true || is_null($home_batted_first)) {
                ?>
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetHomeTeam()->GetName(), $home_batted_first === true);
                ?>
",
                "data": [0<?php 
                echo $this->BuildCumulativeOverTotals($this->match->Result()->AwayOvers()->GetItems());
                ?>
]
            },
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetAwayTeam()->GetName(), $home_batted_first === false);
                ?>
",
                "data": [0<?php 
                echo $this->BuildCumulativeOverTotals($this->match->Result()->HomeOvers()->GetItems());
                ?>
]
            }      
            <?php 
            } else {
                ?>
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetAwayTeam()->GetName(), $home_batted_first === false);
                ?>
",
                "data": [0<?php 
                echo $this->BuildCumulativeOverTotals($this->match->Result()->HomeOvers()->GetItems());
                ?>
]
            },      
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetHomeTeam()->GetName(), $home_batted_first === true);
                ?>
",
                "data": [0<?php 
                echo $this->BuildCumulativeOverTotals($this->match->Result()->AwayOvers()->GetItems());
                ?>
]
            }
            <?php 
            }
            ?>
]    
    },
    "runRate": {
        "labels": [
            <?php 
            echo $this->BuildOversLabels(0, $overs);
            ?>
        
        ],
        "datasets": [
        <?php 
            $home_batted_first = $this->match->Result()->GetHomeBattedFirst();
            if ($home_batted_first === true || is_null($home_batted_first)) {
                ?>
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetHomeTeam()->GetName() . " run rate", $home_batted_first === true);
                ?>
",
                "data": [0<?php 
                echo $this->BuildCumulativeRunRate($this->match->Result()->AwayOvers()->GetItems());
                ?>
]
            },
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetAwayTeam()->GetName() . " run rate", null);
                ?>
",
                "data": [0<?php 
                echo $this->BuildCumulativeRunRate($this->match->Result()->HomeOvers()->GetItems());
                ?>
]
            },
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetAwayTeam()->GetName() . " rate required", null);
                ?>
",
                "data": [<?php 
                echo $this->BuildRunRateRequired($this->match->Result()->AwayOvers()->GetItems(), $this->match->Result()->HomeOvers()->GetItems(), $overs);
                ?>
]
            }      
            <?php 
            } else {
                ?>
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetAwayTeam()->GetName() . " run rate", $home_batted_first === false);
                ?>
",
                "data": [0<?php 
                echo $this->BuildCumulativeRunRate($this->match->Result()->HomeOvers()->GetItems());
                ?>
]
            },      
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetHomeTeam()->GetName() . " run rate", null);
                ?>
",
                "data": [0<?php 
                echo $this->BuildCumulativeRunRate($this->match->Result()->AwayOvers()->GetItems());
                ?>
]
            },      
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetHomeTeam()->GetName() . " rate required", null);
                ?>
",
                "data": [<?php 
                echo $this->BuildRunRateRequired($this->match->Result()->HomeOvers()->GetItems(), $this->match->Result()->AwayOvers()->GetItems(), $overs);
                ?>
]
            }
            <?php 
            }
            ?>
]    
    },
    "manhattanFirstInnings": {
        "labels": [
            <?php 
            $overs = $this->HowManyOversInTheMatch();
            echo $this->BuildOversLabels(1, $overs);
            ?>
        
        ],
        "datasets": [
        <?php 
            if ($home_batted_first === true || is_null($home_batted_first)) {
                ?>
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetHomeTeam()->GetName(), $home_batted_first === true);
                ?>
",
                "data": [<?php 
                echo $this->BuildOverTotals($this->match->Result()->AwayOvers()->GetItems(), $overs);
                ?>
]
            }      
            <?php 
            } else {
                ?>
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetAwayTeam()->GetName(), $home_batted_first === false);
                ?>
",
                "data": [<?php 
                echo $this->BuildOverTotals($this->match->Result()->HomeOvers()->GetItems(), $overs);
                ?>
]
            }      
        <?php 
            }
            ?>
        ]
    },
    "manhattanSecondInnings": {
        "labels": [
            <?php 
            $overs = $this->HowManyOversInTheMatch();
            echo $this->BuildOversLabels(1, $overs);
            ?>
        
        ],
        "datasets": [
        <?php 
            if ($home_batted_first === false) {
                ?>
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetHomeTeam()->GetName(), $home_batted_first === true);
                ?>
",
                "data": [<?php 
                echo $this->BuildOverTotals($this->match->Result()->AwayOvers()->GetItems(), $overs);
                ?>
]
            }      
            <?php 
            } else {
                ?>
            {
                "label": "<?php 
                echo $this->BuildTeamNameLabel($this->match->GetAwayTeam()->GetName(), $home_batted_first === false);
                ?>
",
                "data": [<?php 
                echo $this->BuildOverTotals($this->match->Result()->HomeOvers()->GetItems(), $overs);
                ?>
]
            }      
        <?php 
            }
            ?>
        ]
    }
    <?php 
        }
        ?>
}
        <?php 
        exit;
    }
 /**
  * Creates a bowling scorecard for one innings with as much data as is available
  * @param Match $match
  * @param bool $is_home_innings
  * @return void
  */
 private function CreateBowlingCard(Match $match, $is_home_innings)
 {
     $overs_data = $is_home_innings ? $match->Result()->AwayOvers() : $match->Result()->HomeOvers();
     $bowling_data = $is_home_innings ? $match->Result()->AwayBowling() : $match->Result()->HomeBowling();
     $bowling_team = $is_home_innings ? $match->GetAwayTeam() : $match->GetHomeTeam();
     # First, bowler's figures
     if ($bowling_data->GetCount()) {
         $bowling_table = new XhtmlTable();
         $bowling_table->SetCaption(htmlentities($bowling_team->GetName() . "'s bowlers", ENT_QUOTES, "UTF-8", false));
         $bowling_table->SetCssClass("bowling scorecard");
         $over_header = new XhtmlCell(true, '<abbr title="Overs" class="small">Ov</abbr><span class="large">Overs</span>');
         $over_header->SetCssClass("numeric");
         $maidens_header = new XhtmlCell(true, '<abbr title="Maiden overs" class="small">Md</abbr><abbr title="Maiden overs" class="large">Mdns</abbr>');
         $maidens_header->SetCssClass("numeric");
         $runs_header = new XhtmlCell(true, "Runs");
         $runs_header->SetCssClass("numeric");
         $wickets_header = new XhtmlCell(true, '<abbr title="Wickets" class="small">Wk</abbr><abbr title="Wickets" class="large">Wkts</abbr>');
         $wickets_header->SetCssClass("numeric");
         $economy_header = new XhtmlCell(true, '<abbr title="Economy" class="small">Econ</abbr><span class="large">Economy</span>');
         $economy_header->SetCssClass("numeric");
         $average_header = new XhtmlCell(true, '<abbr title="Average" class="small">Avg</abbr><span class="large">Average</span>');
         $average_header->SetCssClass("numeric");
         $strike_header = new XhtmlCell(true, '<abbr title="Strike rate" class="small">S/R</abbr><span class="large">Strike rate</span>');
         $strike_header->SetCssClass("numeric");
         $bowling_headings = new XhtmlRow(array("Bowler", $over_header, $maidens_header, $runs_header, $wickets_header, $economy_header, $average_header, $strike_header));
         $bowling_headings->SetIsHeader(true);
         $bowling_table->AddRow($bowling_headings);
         $bowling_data->ResetCounter();
         while ($bowling_data->MoveNext()) {
             $bowling = $bowling_data->GetItem();
             /* @var $bowling Bowling */
             $player = new XhtmlCell(false, '<a property="schema:name" rel="schema:url" href="' . htmlentities($bowling->GetPlayer()->GetPlayerUrl(), ENT_QUOTES, "UTF-8", false) . '">' . htmlentities($bowling->GetPlayer()->GetName(), ENT_QUOTES, "UTF-8", false) . '</a>');
             $player->AddCssClass("bowler");
             $player->AddAttribute("typeof", "schema:Person");
             $player->AddAttribute("about", $bowling->GetPlayer()->GetLinkedDataUri());
             $over_data = new XhtmlCell(false, htmlentities($bowling->GetOvers(), ENT_QUOTES, "UTF-8", false));
             $over_data->SetCssClass("numeric");
             $maidens_data = new XhtmlCell(false, htmlentities($bowling->GetMaidens(), ENT_QUOTES, "UTF-8", false));
             $maidens_data->SetCssClass("numeric");
             $runs_data = new XhtmlCell(false, htmlentities($bowling->GetRunsConceded(), ENT_QUOTES, "UTF-8", false));
             $runs_data->SetCssClass("numeric");
             $wickets_data = new XhtmlCell(false, htmlentities($bowling->GetWickets(), ENT_QUOTES, "UTF-8", false));
             $wickets_data->SetCssClass("numeric");
             $economy = StoolballStatistics::BowlingEconomy($bowling->GetOvers(), $bowling->GetRunsConceded());
             $economy_data = new XhtmlCell(false, is_null($economy) ? "&#8211;" : htmlentities($economy, ENT_QUOTES, "UTF-8", false));
             $economy_data->SetCssClass("numeric");
             $average = StoolballStatistics::BowlingAverage($bowling->GetRunsConceded(), $bowling->GetWickets());
             $average_data = new XhtmlCell(false, is_null($average) ? "&#8211;" : htmlentities($average, ENT_QUOTES, "UTF-8", false));
             $average_data->SetCssClass("numeric");
             $strike = StoolballStatistics::BowlingStrikeRate($bowling->GetOvers(), $bowling->GetWickets());
             $strike_data = new XhtmlCell(false, is_null($strike) ? "&#8211;" : htmlentities($strike, ENT_QUOTES, "UTF-8", false));
             $strike_data->SetCssClass("numeric");
             $bowling_row = new XhtmlRow(array($player, $over_data, $maidens_data, $runs_data, $wickets_data, $economy_data, $average_data, $strike_data));
             $bowling_row->GetFirstCell()->SetCssClass("bowler");
             $bowling_table->AddRow($bowling_row);
         }
         $this->AddControl($bowling_table);
     }
     # Now over-by-over
     if ($overs_data->GetCount()) {
         $overs_table = new XhtmlTable();
         $overs_table->SetCaption(htmlentities($bowling_team->GetName() . "'s bowling, over-by-over", ENT_QUOTES, "UTF-8", false));
         $overs_table->SetCssClass("scorecard bowling-scorecard bowling overs");
         $balls_header = new XhtmlCell(true, "Balls");
         $balls_header->SetCssClass("numeric");
         $wides_header = new XhtmlCell(true, "Wides");
         $wides_header->SetCssClass("numeric");
         $no_balls_header = new XhtmlCell(true, "No balls");
         $no_balls_header->SetCssClass("numeric");
         $runs_in_over_header = new XhtmlCell(true, "Runs");
         $runs_in_over_header->SetCssClass("numeric");
         $total_header = new XhtmlCell(true, "Total");
         $total_header->SetCssClass("numeric");
         $overs_headings = new XhtmlRow(array("Bowler", $balls_header, $wides_header, $no_balls_header, $runs_in_over_header, $total_header));
         $overs_headings->SetIsHeader(true);
         $overs_table->AddRow($overs_headings);
         $overs_data->ResetCounter();
         $total = 0;
         while ($overs_data->MoveNext()) {
             $bowling = $overs_data->GetItem();
             /* @var $bowling Over */
             $player = new XhtmlCell(false, '<a property="schema:name" rel="schema:url" href="' . htmlentities($bowling->GetPlayer()->GetPlayerUrl(), ENT_QUOTES, "UTF-8", false) . '">' . htmlentities($bowling->GetPlayer()->GetName(), ENT_QUOTES, "UTF-8", false) . '</a>');
             $player->AddCssClass("bowler");
             $player->AddAttribute("typeof", "schema:Person");
             $player->AddAttribute("about", $bowling->GetPlayer()->GetLinkedDataUri());
             $balls_data = new XhtmlCell(false, htmlentities($bowling->GetBalls(), ENT_QUOTES, "UTF-8", false));
             $balls_data->SetCssClass("numeric");
             $wides_data = new XhtmlCell(false, htmlentities($bowling->GetWides(), ENT_QUOTES, "UTF-8", false));
             $wides_data->SetCssClass("numeric");
             $no_balls_data = new XhtmlCell(false, htmlentities($bowling->GetNoBalls(), ENT_QUOTES, "UTF-8", false));
             $no_balls_data->SetCssClass("numeric");
             $runs_in_over_data = new XhtmlCell(false, htmlentities($bowling->GetRunsInOver(), ENT_QUOTES, "UTF-8", false));
             $runs_in_over_data->SetCssClass("numeric");
             $total += $bowling->GetRunsInOver();
             $total_data = new XhtmlCell(false, htmlentities($total, ENT_QUOTES, "UTF-8", false));
             $total_data->SetCssClass("numeric");
             $bowling_row = new XhtmlRow(array($player, $balls_data, $wides_data, $no_balls_data, $runs_in_over_data, $total_data));
             $bowling_row->GetFirstCell()->SetCssClass("bowler");
             $overs_table->AddRow($bowling_row);
         }
         $this->AddControl($overs_table);
     }
 }