function CreateControls()
 {
     $match = $this->GetDataObject();
     /* @var $match Match */
     $this->b_user_is_match_owner = ($match->GetAddedBy() instanceof User and AuthenticationManager::GetUser()->GetId() == $match->GetAddedBy()->GetId());
     $this->AddCssClass('legacy-form');
     if ($this->b_user_is_match_admin) {
         # Add match title editing
         $b_new = !$match->GetId();
         $title = new TextBox('title', $b_new ? '' : $match->GetTitle());
         $title->SetMaxLength(100);
         $this->AddControl(new FormPart('Match title', $title));
         $o_generate = new CheckBox('defaultTitle', 'Use default title', 1);
         if ($b_new) {
             $o_generate->SetChecked(true);
         } else {
             $o_generate->SetChecked(!$match->GetUseCustomTitle());
         }
         $this->AddControl($o_generate);
         # Add match type
         if ($match->GetMatchType() != MatchType::TOURNAMENT_MATCH) {
             $o_type_list = new XhtmlSelect('type');
             $o_type_list->AddControl(new XhtmlOption(MatchType::Text(MatchType::LEAGUE), MatchType::LEAGUE));
             $o_type_list->AddControl(new XhtmlOption(MatchType::Text(MatchType::PRACTICE), MatchType::PRACTICE));
             $o_type_list->AddControl(new XhtmlOption(MatchType::Text(MatchType::FRIENDLY), MatchType::FRIENDLY));
             $o_type_list->AddControl(new XhtmlOption(MatchType::Text(MatchType::CUP), MatchType::CUP));
             $o_type_list->SelectOption($match->GetMatchType());
             $this->AddControl(new FormPart('Type of match', $o_type_list));
         }
     }
     if ($this->b_user_is_match_owner or $this->b_user_is_match_admin) {
         $this->EnsureAggregatedEditors();
         $this->fixture_editor->SetDataObject($match);
         $this->AddControl($this->fixture_editor);
     }
     if ($this->b_user_is_match_admin) {
         # add season
         if (!$this->IsPostback()) {
             $this->season_editor->DataObjects()->SetItems($match->Seasons()->GetItems());
         }
         $this->AddControl($this->season_editor);
         # Hidden data on teams, for use by match-fixture-edit-control.js to re-sort teams when the season is changed
         # Format is 1,2,3,4,5;2,3,4,5,6
         # where ; separates each team, and for each team the first number identifies the team and subsequent numbers identify the season
         /* @var $o_team Team */
         /* @var $o_comp Competition */
         $s_team_season = '';
         # Build a list of all seasons, so that the "Not known yet" option can be added to all seasons
         $all_seasons = array();
         foreach ($this->fixture_editor->GetTeams() as $group) {
             foreach ($group as $o_team) {
                 if (!$o_team instanceof Team) {
                     continue;
                 }
                 # Add team id
                 if ($s_team_season) {
                     $s_team_season .= ';';
                 }
                 $s_team_season .= $o_team->GetId();
                 # add team seasons
                 foreach ($o_team->Seasons() as $team_in_season) {
                     $s_team_season .= ',' . $team_in_season->GetSeasonId();
                     $all_seasons[] = $team_in_season->GetSeasonId();
                 }
             }
         }
         # Add the "Don't know yet" option with all seasons
         $all_seasons = array_unique($all_seasons);
         $s_team_season = "0," . implode(",", $all_seasons) . ";{$s_team_season}";
         # Put it in a hidden field accessible to JavaScript.
         $o_ts = new TextBox($this->GetNamingPrefix() . 'TeamSeason', $s_team_season);
         $o_ts->SetMode(TextBoxMode::Hidden());
         $this->AddControl($o_ts);
     }
     $got_home_team = !is_null($match->GetHomeTeam());
     $got_away_team = !is_null($match->GetAwayTeam());
     $b_got_teams = ($got_home_team and $got_away_team);
     $b_future = ($match->GetId() and $match->GetStartTime() > gmdate('U'));
     // 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', "Result of this match");
     $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 batted first?
     if (!$b_future) {
         $match_box->AddControl('<h3>If the match went ahead:</h3>');
         $toss = $this->SelectOneOfTwoTeams($this->GetNamingPrefix() . 'Toss', $match, $match->Result()->GetTossWonBy() === TeamRole::Home(), $match->Result()->GetTossWonBy() === TeamRole::Away());
         $toss_part = new FormPart('Who won the toss?', $toss);
         $match_box->AddControl($toss_part);
         $bat_first = $this->SelectOneOfTwoTeams($this->GetNamingPrefix() . 'BatFirst', $match, $match->Result()->GetHomeBattedFirst() === true, $match->Result()->GetHomeBattedFirst() === false);
         $bat_part = new FormPart('Who batted first?', $bat_first);
         $match_box->AddControl($bat_part);
     }
     # Who won?
     $o_winner = new XhtmlSelect($this->GetNamingPrefix() . 'Result');
     if ($b_future) {
         $o_winner->AddControl(new XhtmlOption('The match will go ahead', ''));
     } else {
         # This option means "no change", therefore it has to have the current value for the match result even though that's
         # a different value from match to match. If it's not there the submitted match doesn't have result info, so when admin
         # saves fixture it regenerates its title as "Team A v Team B", which doesn't match the existing title so gets saved to db.
         # Can't be exactly the current value though, because otherwise a cancelled match has two options with the same value,
         # so re-selecting the option doesn't work. Instead change it to a negative number, which can be converted back when submitted.
         $o_winner->AddControl(new XhtmlOption('Not applicable &#8211; match went ahead', $match->Result()->GetResultType() * -1));
     }
     $result_types = array(MatchResult::HOME_WIN_BY_FORFEIT, MatchResult::AWAY_WIN_BY_FORFEIT, MatchResult::POSTPONED, MatchResult::CANCELLED, MatchResult::ABANDONED);
     foreach ($result_types as $result_type) {
         if (!$b_future or MatchResult::PossibleInAdvance($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));
             }
         }
     }
     $o_winner->SelectOption($match->Result()->GetResultType());
     if (!$b_future) {
         $match_box->AddControl('<h3 class="ifNotPlayed">Or, if the match was not played:</h3>');
     }
     $o_win_part = new FormPart($b_future ? 'Will it happen?' : 'Why not?', $o_winner);
     $match_box->AddControl($o_win_part);
     # Show audit data
     if ($match->GetLastAudit() != null) {
         require_once "data/audit-control.class.php";
         $match_box->AddControl(new AuditControl($match->GetLastAudit(), "match"));
     }
     # Remember short URL
     $o_short_url = new TextBox($this->GetNamingPrefix() . 'ShortUrl', $match->GetShortUrl());
     if ($this->b_user_is_match_admin) {
         $o_url_part = new FormPart('Short URL', $o_short_url);
         $this->AddControl($o_url_part);
         $this->AddControl(new CheckBox($this->GetNamingPrefix() . 'RegenerateUrl', 'Regenerate short URL', 1, !$match->GetUseCustomShortUrl(), $this->IsValidSubmit()));
     } else {
         $o_short_url->SetMode(TextBoxMode::Hidden());
         $this->AddControl($o_short_url);
     }
     if ($b_future and !$this->b_user_is_match_admin and !$this->b_user_is_match_owner) {
         $this->SetButtonText("Save result");
     }
 }
 function OnLoadPageData()
 {
     /* @var $o_last_match Match */
     /* @var $season Season */
     /* @var $team Team */
     # new data manager
     $o_match_manager = new MatchManager($this->GetSettings(), $this->GetDataConnection());
     # Collect season to add this match to, starting with the URL
     # get season and teams (was at this stage because editor needed teams to build its
     # posted data object, but that's no longer the case so probably could be later if needed)
     if (isset($this->i_season_id)) {
         $season_manager = new SeasonManager($this->GetSettings(), $this->GetDataConnection());
         $season_manager->ReadById(array($this->i_season_id));
         $this->season = $season_manager->GetFirst();
         unset($season_manager);
         $this->edit->Seasons()->Add($this->season);
         # If there are at least 2 teams in the season, show only those teams, otherwise show all teams of the relevant player type
         if (count($this->season->GetTeams()) > 1) {
             $this->edit->SetTeams(array($this->season->GetTeams()));
         } else {
             require_once 'stoolball/team-manager.class.php';
             $team_manager = new TeamManager($this->GetSettings(), $this->GetDataConnection());
             $team_manager->FilterByPlayerType(array($this->season->GetCompetition()->GetPlayerType()));
             $team_manager->ReadTeamSummaries();
             $this->edit->SetTeams(array($team_manager->GetItems()));
             unset($team_manager);
         }
     }
     # Not elseif, because when you've added a match there's a season, but we still need this to run to populate
     # the choices for the next match to be added
     if ($this->team instanceof Team) {
         # Otherwise it should be a team.
         # Get more information about the team itself
         require_once 'stoolball/team-manager.class.php';
         $team_manager = new TeamManager($this->GetSettings(), $this->GetDataConnection());
         $team_manager->ReadById(array($this->team->GetId()));
         $this->team = $team_manager->GetFirst();
         if (!is_null($this->team)) {
             $this->edit->SetContextTeam($this->team);
             $season_ids = array();
             $team_groups = array();
             $a_exclude_team_ids = array();
             $team_manager->FilterByActive(true);
             # Add the home team first
             $team_groups[] = array($this->team);
             $a_exclude_team_ids[] = $this->team->GetId();
             # Get the seasons this team is in...
             $season_manager = new SeasonManager($this->GetSettings(), $this->GetDataConnection());
             if ($this->i_match_type == MatchType::FRIENDLY) {
                 # For a friendly, any group of teams they play with is fine
                 $season_manager->ReadCurrentSeasonsByTeamId(array($this->team->GetId()));
             } else {
                 # For anything else, get the seasons *for this type of match*
                 $season_manager->ReadCurrentSeasonsByTeamId(array($this->team->GetId()), array($this->i_match_type));
             }
             $seasons = $season_manager->GetItems();
             unset($season_manager);
             $this->edit->Seasons()->Clear();
             # on postback, the season just added is already there, so clear to prevent a duplicate
             foreach ($seasons as $season) {
                 $this->edit->Seasons()->Add($season);
                 $season_ids[] = $season->GetId();
             }
             #... and their opponent teams in those seasons
             if (count($season_ids)) {
                 $team_manager->FilterExceptTeams($a_exclude_team_ids);
                 $team_manager->ReadBySeasonId($season_ids);
                 $season_teams = $team_manager->GetItems();
                 if (count($season_teams)) {
                     $team_groups['This season\'s teams'] = $season_teams;
                 }
                 foreach ($season_teams as $team) {
                     $a_exclude_team_ids[] = $team->GetId();
                 }
             }
             # ...and if this is a friendly it could be any other team
             if ($this->i_match_type == MatchType::FRIENDLY) {
                 # get any other teams they played in the last 2 years, and combine with existing results
                 $team_manager->FilterExceptTeams($a_exclude_team_ids);
                 $team_manager->ReadRecentOpponents(array($this->team->GetId()), 24);
                 $recent_opponents = $team_manager->GetItems();
                 if (count($recent_opponents)) {
                     $team_groups['Recent opponents'] = $recent_opponents;
                 }
                 foreach ($recent_opponents as $team) {
                     $a_exclude_team_ids[] = $team->GetId();
                 }
                 # get any other teams they might play, and combine with existing results
                 $team_manager->FilterExceptTeams($a_exclude_team_ids);
                 $team_manager->ReadAll();
                 $team_groups['Other teams'] = $team_manager->GetItems();
             }
             # What if there are still no opponents to choose from? In that case select all teams.
             if (count($team_groups) == 1) {
                 $team_manager->FilterExceptTeams($a_exclude_team_ids);
                 $team_manager->ReadAll();
                 $team_groups[] = $team_manager->GetItems();
             }
             # Offer those teams to select from
             if ($total_groups = count($team_groups)) {
                 # If only two groups (home team + 1 group), don't group teams. Remove the only key from the array.
                 if ($total_groups == 2) {
                     $keys = array_keys($team_groups);
                     $team_groups = array($team_groups[$keys[0]], $team_groups[$keys[1]]);
                 }
                 $this->edit->SetTeams($team_groups);
             }
         }
         unset($team_manager);
     }
     # Save match
     if ($this->IsPostback() and $this->IsValid()) {
         # Get posted match
         $this->match = $this->edit->GetDataObject();
         if (!$this->IsRefresh()) {
             # Save match
             $o_match_manager->SaveFixture($this->match);
             $o_match_manager->SaveSeasons($this->match, true);
             $o_match_manager->NotifyMatchModerator($this->match->GetId());
             # Update 'next 5 matches'
             $o_match_manager->ReadNext();
             $this->a_next_matches = $o_match_manager->GetItems();
         }
         # Reset control for new match
         $this->edit->SetDataObject(new Match($this->GetSettings()));
     }
     $o_match_manager->FilterByMatchType(array($this->i_match_type));
     if (isset($this->i_season_id)) {
         # If we're adding a match to a season, get last game in season for its date
         $o_match_manager->ReadLastInSeason($this->season->GetId());
     } else {
         if ($this->team instanceof Team) {
             # Get the last game already scheduled for the team to use its date
             $o_match_manager->ReadLastForTeam($this->team->GetId());
         }
     }
     $o_last_match = $o_match_manager->GetFirst();
     if (is_object($o_last_match)) {
         $current_season = Season::SeasonDates();
         if (gmdate('Y', $o_last_match->GetStartTime()) < gmdate('Y', $current_season[0])) {
             # If the last match this team played was last season, use the time but not the date
             $this->edit->SetDefaultTime(gmmktime(gmdate('H', $o_last_match->GetStartTime()), gmdate('i', $o_last_match->GetStartTime()), 0, gmdate('m'), gmdate('d'), gmdate('Y')));
         } else {
             # If the last match was this season and has a time, use it
             if ($o_last_match->GetIsStartTimeKnown()) {
                 $this->edit->SetDefaultTime($o_last_match->GetStartTime());
             } else {
                 # If the last match has no time, use 6.30pm BST
                 $this->edit->SetDefaultTime(gmmktime(17, 30, 0, gmdate('m', $o_last_match->GetStartTime()), gmdate('d', $o_last_match->GetStartTime()), gmdate('Y', $o_last_match->GetStartTime())));
             }
         }
     }
     unset($o_match_manager);
     # Get grounds
     $o_ground_manager = new GroundManager($this->GetSettings(), $this->GetDataConnection());
     $o_ground_manager->ReadAll();
     $a_grounds = $o_ground_manager->GetItems();
     $this->edit->SetGrounds($a_grounds);
     unset($o_ground_manager);
 }