function OnLoadPageData()
 {
     require_once "data/process-manager.class.php";
     $this->process = new ProcessManager();
     if ($this->process->ReadyToDeleteAll()) {
         $stats = $this->GetSettings()->GetTable("PlayerMatch");
         $sql = "TRUNCATE TABLE {$stats}";
         $this->GetDataConnection()->query($sql);
     }
     $matches = $this->GetSettings()->GetTable("MatchTeam");
     $mt = $this->GetSettings()->GetTable('MatchTeam');
     $sql = "SELECT match_id, match_team_id FROM {$matches} ORDER BY match_team_id " . $this->process->GetQueryLimit();
     $result = $this->GetDataConnection()->query($sql);
     require_once "stoolball/player-manager.class.php";
     $player_manager = new PlayerManager($this->GetSettings(), $this->GetDataConnection());
     require_once 'stoolball/statistics/statistics-manager.class.php';
     $statistics_manager = new StatisticsManager($this->GetSettings(), $this->GetDataConnection());
     while ($row = $result->fetch()) {
         $affected_players = $player_manager->ReadPlayersInMatch(array($row->match_id));
         # generate player statistics from the data entered
         if (count($affected_players)) {
             $statistics_manager->UpdateBattingStatistics($affected_players, array($row->match_team_id));
             # get the match_team_id for the bowling that goes with this batting
             $sql = "SELECT match_team_id FROM {$mt}\n\t\t\t\t\t\tWHERE match_id = (SELECT match_id FROM {$mt} WHERE match_team_id = {$row->match_team_id})\n\t\t\t\t\t\tAND match_team_id != {$row->match_team_id}\n\t\t\t\t\t\tAND team_role IN (" . TeamRole::Home() . ", " . TeamRole::Away() . ")";
             $result2 = $this->GetDataConnection()->query($sql);
             $row2 = $result2->fetch();
             $bowling_match_team_id = $row2->match_team_id;
             $statistics_manager->UpdateFieldingStatistics($affected_players, array($bowling_match_team_id));
             $statistics_manager->UpdateBowlingStatistics($affected_players, array($bowling_match_team_id));
             $statistics_manager->UpdatePlayerOfTheMatchStatistics($row->match_id);
             $statistics_manager->DeleteObsoleteStatistics($row->match_id);
         }
         $this->process->OneMoreDone();
     }
 }
 /**
  * @return void
  * @param Match $match
  * @param bool $is_first_innings
  * @desc Saves the batting and bowling scorecards for one innings
  */
 public function SaveScorecard(Match $match, $is_first_innings, ISearchIndexProvider $search)
 {
     # To add a scorecard there must always already be a match to update
     if (!$match->GetId()) {
         return;
     }
     # This isn't for tournaments
     if ($match->GetMatchType() == MatchType::TOURNAMENT) {
         return;
     }
     # Get tables
     $batting_table = $this->GetSettings()->GetTable("Batting");
     $bowling_table = $this->GetSettings()->GetTable("Bowling");
     $match_table = $this->GetSettings()->GetTable('Match');
     $mt = $this->GetSettings()->GetTable('MatchTeam');
     # Is this scorecard for the home or the away innings?
     $sql = "SELECT home_bat_first FROM {$match_table} WHERE match_id = " . Sql::ProtectNumeric($match->GetId());
     $result = $this->GetDataConnection()->query($sql);
     $row = $result->fetch();
     if (is_null($row->home_bat_first) or (bool) $row->home_bat_first === true) {
         $is_home_innings = $is_first_innings;
     } else {
         $is_home_innings = !$is_first_innings;
     }
     $result->closeCursor();
     # Prepare data for query
     if ($is_home_innings) {
         $bowling_team_id = $match->GetAwayTeamId();
         $batting_team_id = $match->GetHomeTeamId();
         $team_bowling = $match->Result()->AwayOvers();
         $team_batting = $match->Result()->HomeBatting();
     } else {
         $bowling_team_id = $match->GetHomeTeamId();
         $batting_team_id = $match->GetAwayTeamId();
         $team_bowling = $match->Result()->HomeOvers();
         $team_batting = $match->Result()->AwayBatting();
     }
     # Find the match_team_id for the bowling
     $sql = "SELECT match_team_id FROM {$mt}\r\n\t\t\t\tWHERE match_id " . Sql::ProtectNumeric($match->GetId(), false, true) . "\r\n\t\t\t\tAND team_id " . Sql::ProtectNumeric($bowling_team_id, false, true) . "\r\n\t\t\t\tAND team_role = " . ($is_home_innings ? TeamRole::Away() : TeamRole::Home());
     $result = $this->GetDataConnection()->query($sql);
     $row = $result->fetch();
     $bowling_match_team_id = $row->match_team_id;
     $result->closeCursor();
     # Find the match_team_id for the batting
     $sql = "SELECT match_team_id FROM {$mt}\r\n\t\t\t\tWHERE match_id " . Sql::ProtectNumeric($match->GetId(), false, true) . "\r\n\t\t\t\tAND team_id " . Sql::ProtectNumeric($batting_team_id, false, true) . "\r\n\t\t\t\tAND team_role = " . ($is_home_innings ? TeamRole::Home() : TeamRole::Away());
     $result = $this->GetDataConnection()->query($sql);
     $row = $result->fetch();
     $batting_match_team_id = $row->match_team_id;
     $result->closeCursor();
     $affected_players = $this->SaveBattingScorecard($match, $is_home_innings, $batting_match_team_id, $team_batting);
     $affected_bowlers = $this->SaveBowlingScorecard($match, $is_home_innings, $batting_match_team_id, $bowling_match_team_id, $team_bowling);
     $affected_players = array_merge($affected_players, $affected_bowlers);
     $affected_players = array_unique($affected_players);
     if (count($affected_players)) {
         require_once 'stoolball/statistics/statistics-manager.class.php';
         $statistics_manager = new StatisticsManager($this->GetSettings(), $this->GetDataConnection());
         # generate player statistics from the data entered
         $statistics_manager->UpdateBattingStatistics($affected_players, array($batting_match_team_id));
         $statistics_manager->UpdateFieldingStatistics($affected_players, array($bowling_match_team_id));
         $statistics_manager->UpdateBowlingStatistics($affected_players, array($bowling_match_team_id));
         $statistics_manager->DeleteObsoleteStatistics($match->GetId());
         # update overall stats for players
         $statistics_manager->UpdatePlayerStatistics($affected_players);
         unset($statistics_manager);
         # update search engine
         require_once "stoolball/player-manager.class.php";
         require_once "search/player-search-adapter.class.php";
         $player_manager = new PlayerManager($this->GetSettings(), $this->GetDataConnection());
         foreach ($affected_players as $player_id) {
             $player_manager->ReadPlayerById($player_id);
             $player = $player_manager->GetFirst();
             $search->DeleteFromIndexById("player" . $player_id);
             if ($player instanceof Player) {
                 $adapter = new PlayerSearchAdapter($player);
                 $search->Index($adapter->GetSearchableItem());
             }
         }
         $search->CommitChanges();
         unset($player_manager);
     }
 }
 /**
  * @return 1 for a win, 0 for a tie, -1 for a loss and null for any other result
  */
 private function DidThePlayerWinTheMatch($match_result, $team_role)
 {
     $won_match = null;
     if ($match_result == MatchResult::AWAY_WIN) {
         $won_match = $team_role == TeamRole::Away() ? 1 : -1;
     } else {
         if ($match_result == MatchResult::TIE) {
             $won_match = 0;
         } else {
             if ($match_result == MatchResult::HOME_WIN) {
                 $won_match = $team_role == TeamRole::Home() ? 1 : -1;
             }
         }
     }
     return $won_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 OnPreRender()
 {
     /* @var $o_home Team */
     /* @var $o_away Team */
     /* @var $o_tourney Match */
     # Date and tournament
     $o_date_para = new XhtmlElement('p');
     $o_date = new XhtmlElement('abbr', htmlentities($this->o_match->GetStartTimeFormatted(), ENT_QUOTES, "UTF-8", false));
     $o_date->SetTitle(Date::Microformat($this->o_match->GetStartTime()));
     # hCalendar
     $o_date->SetCssClass('dtstart');
     # hCalendar
     $o_date->AddAttribute("property", "schema:startDate");
     $o_date->AddAttribute("datatype", "xsd:date");
     $o_date->AddAttribute("content", Date::Microformat($this->o_match->GetStartTime()));
     $o_date_para->AddControl('When: ');
     $o_date_para->AddControl($o_date);
     # hCalendar end date
     if ($this->o_match->GetIsStartTimeKnown()) {
         $i_end_time = $this->o_match->GetStartTime() + 60 * 90;
         $o_hcal_end = new XhtmlElement('abbr', ' until around ' . htmlentities(Date::Time($i_end_time), ENT_QUOTES, "UTF-8", false));
         $o_hcal_end->SetTitle(Date::Microformat($i_end_time));
         $o_hcal_end->SetCssClass('metadata dtend');
         $o_date_para->AddControl($o_hcal_end);
     }
     # If we know the time and place, show when the sun sets
     # TODO: Assumes UK
     if ($this->o_match->GetGround() instanceof Ground and $this->o_match->GetGround()->GetAddress()->GetLatitude() and $this->o_match->GetGround()->GetAddress()->GetLongitude()) {
         $o_date_para->AddControl(' <span class="sunset">sunset ' . htmlentities(Date::Time(date_sunset($this->o_match->GetStartTime(), SUNFUNCS_RET_TIMESTAMP, $this->o_match->GetGround()->GetAddress()->GetLatitude(), $this->o_match->GetGround()->GetAddress()->GetLongitude())), ENT_QUOTES, "UTF-8", false) . '</span>');
     }
     # Display match type/season/tournament
     if ($this->o_match->GetMatchType() == MatchType::TOURNAMENT_MATCH) {
         $o_date_para->SetCssClass('description');
         # hCal
         $o_tourney = $this->o_match->GetTournament();
         if (is_object($o_tourney)) {
             $tournament_link = new XhtmlAnchor(htmlentities($o_tourney->GetTitle(), ENT_QUOTES, "UTF-8", false), $o_tourney->GetNavigateUrl());
             $tournament_link->AddAttribute("typeof", "schema:SportsEvent");
             $tournament_link->AddAttribute("about", $o_tourney->GetLinkedDataUri());
             $tournament_link->AddAttribute("rel", "schema:url");
             $tournament_link->AddAttribute("property", "schema:name");
             $tournament_container = new XhtmlElement("span", $tournament_link);
             $tournament_container->AddAttribute("rel", "schema:superEvent");
             # Check for 'the' to get the grammar right
             $s_title = strtolower($o_tourney->GetTitle());
             if (strlen($s_title) >= 4 and substr($s_title, 0, 4) == 'the ') {
                 $o_date_para->AddControl(', in ');
             } else {
                 $o_date_para->AddControl(', in the ');
             }
             $o_date_para->AddControl($tournament_container);
             $o_date_para->AddControl('.');
         } else {
             $o_date_para->AddControl(', in a tournament.');
         }
     } else {
         # hCalendar desc, built up at the same time as the date and league/tournament
         $hcal_desc = new XhtmlElement('div', null, 'description');
         $this->AddControl($hcal_desc);
         $s_detail_xhtml = ucfirst(MatchType::Text($this->o_match->GetMatchType()));
         $season_list_xhtml = null;
         if ($this->o_match->Seasons()->GetCount() == 1) {
             $season = $this->o_match->Seasons()->GetFirst();
             $season_name = new XhtmlAnchor(htmlentities($season->GetCompetitionName(), ENT_QUOTES, "UTF-8", false), $season->GetNavigateUrl());
             $b_the = !(stristr($season->GetCompetitionName(), 'the ') === 0);
             $s_detail_xhtml .= ' in ' . ($b_the ? 'the ' : '') . $season_name->__toString() . '.';
         } elseif ($this->o_match->Seasons()->GetCount() > 1) {
             $s_detail_xhtml .= ' in the following seasons: ';
             $season_list_xhtml = new XhtmlElement('ul');
             $seasons = $this->o_match->Seasons()->GetItems();
             $total_seasons = count($seasons);
             for ($i = 0; $i < $total_seasons; $i++) {
                 $season = $seasons[$i];
                 /* @var $season Season */
                 $season_name = new XhtmlAnchor(htmlentities($season->GetCompetitionName(), ENT_QUOTES, "UTF-8", false), $season->GetNavigateUrl());
                 $li = new XhtmlElement('li', $season_name);
                 if ($i < $total_seasons - 2) {
                     $li->AddControl(new XhtmlElement('span', ', ', 'metadata'));
                 } else {
                     if ($i < $total_seasons - 1) {
                         $li->AddControl(new XhtmlElement('span', ' and ', 'metadata'));
                     }
                 }
                 $season_list_xhtml->AddControl($li);
             }
         } else {
             $s_detail_xhtml .= '.';
         }
         $hcal_desc->AddControl(new XhtmlElement('p', $s_detail_xhtml));
         if (!is_null($season_list_xhtml)) {
             $hcal_desc->AddControl($season_list_xhtml);
         }
     }
     # Who
     $o_home = $this->o_match->GetHomeTeam();
     $o_away = $this->o_match->GetAwayTeam();
     $has_home = $o_home instanceof Team;
     $has_away = $o_away instanceof Team;
     if ($has_home or $has_away) {
         $who = new XhtmlElement("p", "Who: ");
         if ($has_home) {
             $who->AddControl($this->CreateTeamLink($o_home));
         }
         if ($has_home and $has_away) {
             $who->AddControl(" and ");
         }
         if ($has_away) {
             $who->AddControl($this->CreateTeamLink($o_away));
         }
         $this->AddControl($who);
     }
     # When
     $this->AddControl($o_date_para);
     # Ground
     $o_ground = $this->o_match->GetGround();
     if (is_object($o_ground)) {
         $o_ground_link = new XhtmlElement('a', htmlentities($o_ground->GetNameAndTown(), ENT_QUOTES, "UTF-8", false));
         $o_ground_link->AddAttribute('href', $o_ground->GetNavigateUrl());
         $o_ground_link->SetCssClass('location');
         # hCalendar
         $o_ground_link->AddAttribute("typeof", "schema:Place");
         $o_ground_link->AddAttribute("about", $o_ground->GetLinkedDataUri());
         $o_ground_link->AddAttribute("rel", "schema:url");
         $o_ground_link->AddAttribute("property", "schema:name");
         $o_ground_control = new XhtmlElement('p', 'Where: ');
         $o_ground_control->AddAttribute("rel", "schema:location");
         $o_ground_control->AddControl($o_ground_link);
         $this->AddControl($o_ground_control);
     }
     # Add result
     $o_result = $this->o_match->Result();
     $b_result_known = !$o_result->GetResultType() == MatchResult::UNKNOWN;
     $toss_known = !is_null($this->o_match->Result()->GetTossWonBy());
     $b_batting_order_known = !is_null($this->o_match->Result()->GetHomeBattedFirst());
     $has_scorecard_data = ($o_result->HomeBatting()->GetCount() or $o_result->HomeBowling()->GetCount() or $o_result->AwayBatting()->GetCount() or $o_result->AwayBowling()->GetCount() or $o_result->GetHomeRuns() or $o_result->GetHomeWickets() or $o_result->GetAwayRuns() or $o_result->GetAwayWickets());
     $has_player_of_match = $this->o_match->Result()->GetPlayerOfTheMatch() instanceof Player and $this->o_match->Result()->GetPlayerOfTheMatch()->GetName();
     $has_player_of_match_home = $this->o_match->Result()->GetPlayerOfTheMatchHome() instanceof Player and $this->o_match->Result()->GetPlayerOfTheMatchHome()->GetName();
     $has_player_of_match_away = $this->o_match->Result()->GetPlayerOfTheMatchAway() instanceof Player and $this->o_match->Result()->GetPlayerOfTheMatchAway()->GetName();
     if ($b_result_known or $b_batting_order_known or $has_scorecard_data) {
         # Put result in header, so long as we have something to put after it. Otherwise put the result after it.
         $result_header = "Result";
         if ($b_result_known and ($b_batting_order_known or $has_scorecard_data)) {
             $result_header .= ": " . $this->o_match->GetResultDescription();
         }
         $result_header = new XhtmlElement('h2', htmlentities($result_header, ENT_QUOTES, "UTF-8", false));
         if ($has_scorecard_data) {
             $result_header->AddCssClass("hasScorecard");
         }
         $this->AddControl($result_header);
     }
     if ($toss_known) {
         $toss_team = $this->o_match->Result()->GetTossWonBy() === TeamRole::Home() ? $this->o_match->GetHomeTeam() : $this->o_match->GetAwayTeam();
         if ($toss_team instanceof Team) {
             $toss_text = $toss_team->GetName() . " won the toss";
             if ($b_batting_order_known) {
                 $chose_to = ($this->o_match->Result()->GetTossWonBy() === TeamRole::Home()) == $this->o_match->Result()->GetHomeBattedFirst() ? "bat" : "bowl";
                 $toss_text .= " and chose to " . $chose_to;
             }
             $this->AddControl("<p>" . Html::Encode($toss_text) . '.</p>');
         }
     }
     # If at least one player recorded, create a container for the schema.org metadata
     if ($has_scorecard_data or $has_player_of_match or $has_player_of_match_home or $has_player_of_match_away) {
         $this->AddControl('<div rel="schema:performers">');
     }
     if ($has_scorecard_data) {
         $this->CreateScorecard($this->o_match);
     } else {
         # Got to be just result and batting order now. Only include result if batting order's not there, otherwise result will already be in header.
         if ($b_result_known and !$b_batting_order_known) {
             $this->AddControl(new XhtmlElement('p', htmlentities($this->o_match->GetResultDescription(), ENT_QUOTES, "UTF-8", false) . '.'));
         }
         if ($b_batting_order_known) {
             $this->AddControl(new XhtmlElement('p', htmlentities(($this->o_match->Result()->GetHomeBattedFirst() ? $o_home->GetName() : $o_away->GetName()) . ' batted first.'), ENT_QUOTES, "UTF-8", false));
         }
     }
     # Player of the match
     if ($has_player_of_match) {
         $player = $this->o_match->Result()->GetPlayerOfTheMatch();
         $team = $player->Team()->GetId() == $o_home->GetId() ? $o_home->GetName() : $o_away->GetName();
         $player_of_match = new XhtmlElement('p', 'Player of the match: <a property="schema:name" rel="schema:url" href="' . htmlentities($player->GetPlayerUrl(), ENT_QUOTES, "UTF-8", false) . '">' . htmlentities($player->GetName(), ENT_QUOTES, "UTF-8", false) . "</a> ({$team})");
         $player_of_match->AddAttribute("typeof", "schema:Person");
         $player_of_match->AddAttribute("about", $player->GetLinkedDataUri());
         $this->AddControl($player_of_match);
     }
     if ($has_player_of_match_home) {
         $player = $this->o_match->Result()->GetPlayerOfTheMatchHome();
         $player_of_match = new XhtmlElement('p', $o_home->GetName() . ' player of the match: <a property="schema:name" rel="schema:url" href="' . htmlentities($player->GetPlayerUrl(), ENT_QUOTES, "UTF-8", false) . '">' . htmlentities($player->GetName(), ENT_QUOTES, "UTF-8", false) . "</a>");
         $player_of_match->AddAttribute("typeof", "schema:Person");
         $player_of_match->AddAttribute("about", $player->GetLinkedDataUri());
         $this->AddControl($player_of_match);
     }
     if ($has_player_of_match_away) {
         $player = $this->o_match->Result()->GetPlayerOfTheMatchAway();
         $player_of_match = new XhtmlElement('p', $o_away->GetName() . ' player of the match: <a property="schema:name" rel="schema:url" href="' . htmlentities($player->GetPlayerUrl(), ENT_QUOTES, "UTF-8", false) . '">' . htmlentities($player->GetName(), ENT_QUOTES, "UTF-8", false) . "</a>");
         $player_of_match->AddAttribute("typeof", "schema:Person");
         $player_of_match->AddAttribute("about", $player->GetLinkedDataUri());
         $this->AddControl($player_of_match);
     }
     # End container for the schema.org metadata
     if ($has_scorecard_data or $has_player_of_match or $has_player_of_match_home or $has_player_of_match_away) {
         $this->AddControl('</div>');
     }
     # Add notes
     if ($this->o_match->GetNotes()) {
         $this->AddControl(new XhtmlElement('h2', 'Notes'));
         $s_notes = htmlentities($this->o_match->GetNotes(), ENT_QUOTES, "UTF-8", false);
         $s_notes = XhtmlMarkup::ApplyCharacterEntities($s_notes);
         require_once 'email/email-address-protector.class.php';
         $protector = new EmailAddressProtector($this->o_settings);
         $s_notes = $protector->ApplyEmailProtection($s_notes, AuthenticationManager::GetUser()->IsSignedIn());
         $s_notes = XhtmlMarkup::ApplyHeadings($s_notes);
         $s_notes = XhtmlMarkup::ApplyParagraphs($s_notes);
         $s_notes = XhtmlMarkup::ApplyLists($s_notes);
         $s_notes = XhtmlMarkup::ApplySimpleTags($s_notes);
         $s_notes = XhtmlMarkup::ApplyLinks($s_notes);
         if (strpos($s_notes, '<p>') > -1) {
             $this->AddControl($s_notes);
         } else {
             $this->AddControl(new XhtmlElement('p', $s_notes));
         }
     }
     # hCalendar metadata
     $o_hcal_para = new XhtmlElement('p');
     $o_hcal_para->SetCssClass('metadata');
     $this->AddControl($o_hcal_para);
     # hCalendar timestamp
     $o_hcal_para->AddControl('Status: At ');
     $o_hcal_stamp = new XhtmlElement('abbr', htmlentities(Date::Time(gmdate('U')), ENT_QUOTES, "UTF-8", false));
     $o_hcal_stamp->SetTitle(Date::Microformat());
     $o_hcal_stamp->SetCssClass('dtstamp');
     $o_hcal_para->AddControl($o_hcal_stamp);
     # hCalendar GUID
     $o_hcal_para->AddControl(' match ');
     $o_hcal_guid = new XhtmlElement('span', htmlentities($this->o_match->GetLinkedDataUri(), ENT_QUOTES, "UTF-8", false));
     $o_hcal_guid->SetCssClass('uid');
     $o_hcal_para->AddControl($o_hcal_guid);
     # work out hCalendar status
     $s_status = 'CONFIRMED';
     switch ($this->o_match->Result()->GetResultType()) {
         case MatchResult::CANCELLED:
         case MatchResult::POSTPONED:
         case MatchResult::AWAY_WIN_BY_FORFEIT:
         case MatchResult::HOME_WIN_BY_FORFEIT:
             $s_status = 'CANCELLED';
     }
     # hCalendar URL and status
     $o_hcal_para->AddControl(' is ');
     $o_hcal_url = new XhtmlAnchor($s_status, 'http://' . $_SERVER['HTTP_HOST'] . $this->o_match->GetNavigateUrl());
     $o_hcal_url->SetCssClass('url status');
     $o_hcal_para->AddControl($o_hcal_url);
 }