/**
  * Add full scorecard data to the currently selected matches
  */
 public function ExpandMatchScorecards()
 {
     $a_ids = array();
     foreach ($this->GetItems() as $match) {
         $a_ids[] = $match->GetId();
     }
     # Select batting and bowling separately because when selecting it all together they create so many duplicate rows that
     # it would significantly increase the amount of data sent across the wire
     $s_sql = "SELECT mt.match_id, mt.team_role,\r\n\t\tbat.player_id, bat.how_out, bat.dismissed_by_id, bat.bowler_id, bat.runs, bat.balls_faced,\r\n\t\tbatter.player_name AS batter_name, batter.player_role AS batter_role, batter.short_url AS batter_url,\r\n\t\tdismissed_by.player_name AS dismissed_by_name, dismissed_by.player_role AS dismissed_by_role, dismissed_by.short_url AS dismissed_by_url,\r\n\t\tbowler.player_name AS bowler_name, bowler.player_role AS bowler_role, bowler.short_url AS bowler_url\r\n\t\tFROM nsa_match_team mt\r\n\t\tINNER JOIN nsa_batting bat ON mt.match_team_id = bat.match_team_id\r\n\t\tINNER JOIN nsa_player batter ON bat.player_id = batter.player_id\r\n\t\tLEFT JOIN nsa_player dismissed_by ON bat.dismissed_by_id = dismissed_by.player_id\r\n\t\tLEFT JOIN nsa_player bowler ON bat.bowler_id = bowler.player_id\r\n\t\tWHERE mt.team_role IN (" . TeamRole::Home() . "," . TeamRole::Away() . ") ";
     if (count($a_ids)) {
         $s_sql .= "AND mt.match_id IN (" . join(', ', $a_ids) . ') ';
     }
     $s_sql .= "ORDER BY mt.match_id, mt.match_team_id, bat.position";
     $result = $this->GetDataConnection()->query($s_sql);
     while ($row = $result->fetch()) {
         $match = $this->GetItemByProperty('GetId', $row->match_id);
         if (!$match instanceof Match) {
             continue;
         }
         # shouldn't ever happen
         $batter = new Player($this->GetSettings());
         $batter->SetId($row->player_id);
         $batter->SetName($row->batter_name);
         $batter->SetPlayerRole($row->batter_role);
         $batter->SetShortUrl($row->batter_url);
         if (!is_null($row->dismissed_by_id)) {
             $dismissed_by = new Player($this->GetSettings());
             $dismissed_by->SetId($row->dismissed_by_id);
             $dismissed_by->SetName($row->dismissed_by_name);
             $dismissed_by->SetPlayerRole($row->dismissed_by_role);
             $dismissed_by->SetShortUrl($row->dismissed_by_url);
         } else {
             $dismissed_by = null;
         }
         if (!is_null($row->bowler_id)) {
             $bowler = new Player($this->GetSettings());
             $bowler->SetId($row->bowler_id);
             $bowler->SetName($row->bowler_name);
             $bowler->SetPlayerRole($row->bowler_role);
             $bowler->SetShortUrl($row->bowler_url);
         } else {
             $bowler = null;
         }
         $batting = new Batting($batter, $row->how_out, $dismissed_by, $bowler, $row->runs, $row->balls_faced);
         if (intval($row->team_role) == TeamRole::Home()) {
             $match->Result()->HomeBatting()->Add($batting);
         } else {
             if (intval($row->team_role) == TeamRole::Away()) {
                 $match->Result()->AwayBatting()->Add($batting);
             }
         }
     }
     $result->closeCursor();
     # select over-by-over bowling figures
     $s_sql = "SELECT mt.match_id, mt.team_role,\r\n\t\tp.player_name, p.player_role, p.short_url,\r\n\t\tb.player_id, b.position, b.balls_bowled, b.no_balls, b.wides, b.runs_in_over\r\n\t\tFROM nsa_match_team mt\r\n\t\tINNER JOIN nsa_bowling b ON mt.match_team_id = b.match_team_id\r\n\t\tINNER JOIN nsa_player p ON p.player_id = b.player_id\r\n\t\tWHERE mt.team_role IN (" . TeamRole::Home() . "," . TeamRole::Away() . ") ";
     if (count($a_ids)) {
         $s_sql .= "AND mt.match_id IN (" . join(', ', $a_ids) . ') ';
     }
     $s_sql .= "ORDER BY mt.match_id, mt.match_team_id, ISNULL(b.position), b.position";
     # null positions sorted last
     $result = $this->GetDataConnection()->query($s_sql);
     while ($row = $result->fetch()) {
         $match = $this->GetItemByProperty('GetId', $row->match_id);
         if (!$match instanceof Match) {
             continue;
         }
         # shouldn't ever happen
         $bowler = new Player($this->GetSettings());
         $bowler->SetId($row->player_id);
         $bowler->SetName($row->player_name);
         $bowler->SetPlayerRole($row->player_role);
         $bowler->SetShortUrl($row->short_url);
         $bowling = new Over($bowler);
         if (!is_null($row->position)) {
             $bowling->SetOverNumber($row->position);
         }
         if (!is_null($row->balls_bowled)) {
             $bowling->SetBalls($row->balls_bowled);
         }
         if (!is_null($row->no_balls)) {
             $bowling->SetNoBalls($row->no_balls);
         }
         if (!is_null($row->wides)) {
             $bowling->SetWides($row->wides);
         }
         if (!is_null($row->runs_in_over)) {
             $bowling->SetRunsInOver($row->runs_in_over);
         }
         if (intval($row->team_role) == TeamRole::Home()) {
             $match->Result()->HomeOvers()->Add($bowling);
         } else {
             if (intval($row->team_role) == TeamRole::Away()) {
                 $match->Result()->AwayOvers()->Add($bowling);
             }
         }
     }
     $result->closeCursor();
     unset($result);
     # select overall bowling figures for each bowler
     $s_sql = "SELECT mt.match_id, mt.team_role,\r\n\t\tp.player_name, p.player_role, p.short_url,\r\n\t\tb.player_id, b.overs, b.maidens, b.runs_conceded, b.wickets\r\n\t\tFROM nsa_match_team mt\r\n\t\tINNER JOIN nsa_player_match b ON mt.match_team_id = b.match_team_id\r\n\t\tINNER JOIN nsa_player p ON p.player_id = b.player_id\r\n\t\tWHERE mt.team_role IN (" . TeamRole::Home() . "," . TeamRole::Away() . ")\r\n\t\tAND b.wickets IS NOT NULL ";
     if (count($a_ids)) {
         $s_sql .= "AND mt.match_id IN (" . join(', ', $a_ids) . ') ';
     }
     $s_sql .= "ORDER BY mt.match_id, mt.match_team_id, b.first_over";
     $result = $this->GetDataConnection()->query($s_sql);
     while ($row = $result->fetch()) {
         $match = $this->GetItemByProperty('GetId', $row->match_id);
         if (!$match instanceof Match) {
             continue;
         }
         # shouldn't ever happen
         $bowler = new Player($this->GetSettings());
         $bowler->SetId($row->player_id);
         $bowler->SetName($row->player_name);
         $bowler->SetPlayerRole($row->player_role);
         $bowler->SetShortUrl($row->short_url);
         $figures = new Bowling($bowler);
         if (!is_null($row->overs)) {
             $figures->SetOvers($row->overs);
         }
         if (!is_null($row->maidens)) {
             $figures->SetMaidens($row->maidens);
         }
         if (!is_null($row->runs_conceded)) {
             $figures->SetRunsConceded($row->runs_conceded);
         }
         if (!is_null($row->wickets)) {
             $figures->SetWickets($row->wickets);
         }
         if (intval($row->team_role) == TeamRole::Home()) {
             $match->Result()->HomeBowling()->Add($figures);
         } else {
             if (intval($row->team_role) == TeamRole::Away()) {
                 $match->Result()->AwayBowling()->Add($figures);
             }
         }
     }
     $result->closeCursor();
     unset($result);
 }
 /**
  * Builds data posted on pages 2/3 back into a match object
  * @return Match
  */
 private function BuildPostedScorecard()
 {
     $match = new Match($this->GetSettings());
     $match->SetId($this->GetDataObjectId());
     # Must have data on which team is which, otherwise none of the rest makes sense
     # Team ids are essential for saving data, while team names and match title are
     # purely so they can be redisplayed if the page is invalid
     $key = "teams";
     if (!isset($_POST[$key]) or strpos($_POST[$key], ScorecardEditControl::DATA_SEPARATOR) === false) {
         return $match;
     }
     $teams = explode(ScorecardEditControl::DATA_SEPARATOR, $_POST[$key], 6);
     if (count($teams) != 6) {
         return $match;
     }
     switch ($teams[0]) {
         case "0":
             $match->Result()->SetHomeBattedFirst(false);
             $home_batting = $this->GetCurrentPage() == 3;
             break;
         case "1":
             $match->Result()->SetHomeBattedFirst(true);
             $home_batting = $this->GetCurrentPage() == 2;
             break;
         default:
             $home_batting = $this->GetCurrentPage() == 2;
     }
     $home_team = new Team($this->GetSettings());
     $home_team->SetId($teams[1]);
     $home_team->SetName($teams[2]);
     $match->SetHomeTeam($home_team);
     $away_team = new Team($this->GetSettings());
     $away_team->SetId($teams[3]);
     $away_team->SetName($teams[4]);
     $match->SetAwayTeam($away_team);
     $match->SetTitle($teams[5]);
     # Read posted batting data
     $key = "batRows";
     if (isset($_POST[$key])) {
         # This controls not only which fields are read, but also which are redisplayed on an invalid postback or for the next innings.
         $match->SetMaximumPlayersPerTeam(intval($_POST[$key]));
     }
     for ($i = 1; $i <= $match->GetMaximumPlayersPerTeam(); $i++) {
         $key = "batName{$i}";
         if (isset($_POST[$key])) {
             # The row exists - has it been filled in?
             if (trim($_POST[$key])) {
                 # Read the batter data in this row
                 $player = new Player($this->GetSettings());
                 $player->SetName($_POST[$key]);
                 $player->Team()->SetId($home_batting ? $home_team->GetId() : $away_team->GetId());
                 $key = "batHowOut{$i}";
                 $how_out = (isset($_POST[$key]) and is_numeric($_POST[$key])) ? (int) $_POST[$key] : null;
                 $key = "batOutBy{$i}";
                 $dismissed_by = null;
                 if (isset($_POST[$key]) and trim($_POST[$key])) {
                     $dismissed_by = new Player($this->GetSettings());
                     $dismissed_by->SetName($_POST[$key]);
                     $dismissed_by->Team()->SetId($home_batting ? $away_team->GetId() : $home_team->GetId());
                 }
                 $key = "batBowledBy{$i}";
                 $bowler = null;
                 if (isset($_POST[$key]) and trim($_POST[$key])) {
                     $bowler = new Player($this->GetSettings());
                     $bowler->SetName($_POST[$key]);
                     $bowler->Team()->SetId($home_batting ? $away_team->GetId() : $home_team->GetId());
                 }
                 # Correct caught and bowled if marked as caught
                 if ($how_out == Batting::CAUGHT and !is_null($dismissed_by) and !is_null($bowler) and trim($dismissed_by->GetName()) == trim($bowler->GetName())) {
                     $how_out = Batting::CAUGHT_AND_BOWLED;
                     $dismissed_by = null;
                 }
                 $key = "batRuns{$i}";
                 $runs = (isset($_POST[$key]) and is_numeric($_POST[$key])) ? (int) $_POST[$key] : null;
                 $key = "batBalls{$i}";
                 $balls = (isset($_POST[$key]) and is_numeric($_POST[$key])) ? (int) $_POST[$key] : null;
                 # Add that batting performance to the match result
                 $batting = new Batting($player, $how_out, $dismissed_by, $bowler, $runs, $balls);
                 if ($home_batting) {
                     $match->Result()->HomeBatting()->Add($batting);
                 } else {
                     $match->Result()->AwayBatting()->Add($batting);
                 }
             }
         }
     }
     $key = "batByes";
     if (isset($_POST[$key]) and is_numeric($_POST[$key])) {
         $player = new Player($this->GetSettings());
         $player->SetPlayerRole(Player::BYES);
         $player->Team()->SetId($home_batting ? $home_team->GetId() : $away_team->GetId());
         $batting = new Batting($player, null, null, null, (int) $_POST[$key]);
         if ($home_batting) {
             $match->Result()->HomeBatting()->Add($batting);
         } else {
             $match->Result()->AwayBatting()->Add($batting);
         }
     }
     $key = "batWides";
     if (isset($_POST[$key]) and is_numeric($_POST[$key])) {
         $player = new Player($this->GetSettings());
         $player->SetPlayerRole(Player::WIDES);
         $player->Team()->SetId($home_batting ? $home_team->GetId() : $away_team->GetId());
         $batting = new Batting($player, null, null, null, (int) $_POST[$key]);
         if ($home_batting) {
             $match->Result()->HomeBatting()->Add($batting);
         } else {
             $match->Result()->AwayBatting()->Add($batting);
         }
     }
     $key = "batNoBalls";
     if (isset($_POST[$key]) and is_numeric($_POST[$key])) {
         $player = new Player($this->GetSettings());
         $player->SetPlayerRole(Player::NO_BALLS);
         $player->Team()->SetId($home_batting ? $home_team->GetId() : $away_team->GetId());
         $batting = new Batting($player, null, null, null, (int) $_POST[$key]);
         if ($home_batting) {
             $match->Result()->HomeBatting()->Add($batting);
         } else {
             $match->Result()->AwayBatting()->Add($batting);
         }
     }
     $key = "batBonus";
     if (isset($_POST[$key]) and is_numeric($_POST[$key])) {
         $player = new Player($this->GetSettings());
         $player->SetPlayerRole(Player::BONUS_RUNS);
         $player->Team()->SetId($home_batting ? $home_team->GetId() : $away_team->GetId());
         $batting = new Batting($player, null, null, null, (int) $_POST[$key]);
         if ($home_batting) {
             $match->Result()->HomeBatting()->Add($batting);
         } else {
             $match->Result()->AwayBatting()->Add($batting);
         }
     }
     $key = "batTotal";
     if (isset($_POST[$key]) and is_numeric($_POST[$key])) {
         if ($home_batting) {
             $match->Result()->SetHomeRuns($_POST[$key]);
         } else {
             $match->Result()->SetAwayRuns($_POST[$key]);
         }
     }
     $key = "batWickets";
     if (isset($_POST[$key]) and is_numeric($_POST[$key])) {
         if ($home_batting) {
             $match->Result()->SetHomeWickets($_POST[$key]);
         } else {
             $match->Result()->SetAwayWickets($_POST[$key]);
         }
     }
     # Read posted bowling data
     $key = "bowlerRows";
     if (isset($_POST[$key])) {
         # This controls not only which fields are read, but also which are redisplayed on an invalid postback or for the next innings.
         $match->SetOvers(intval($_POST[$key]));
     }
     for ($i = 1; $i <= $match->GetOvers(); $i++) {
         $key = "bowlerName{$i}";
         if (isset($_POST[$key])) {
             # The row exists - has it been filled in?
             if (trim($_POST[$key])) {
                 # Read the bowler data in this row
                 # strlen test allows 0 but not empty string, because is_numeric allows empty string
                 $player = new Player($this->GetSettings());
                 $player->SetName($_POST[$key]);
                 $player->Team()->SetId($home_batting ? $away_team->GetId() : $home_team->GetId());
                 $key = "bowlerBalls{$i}";
                 $balls = (isset($_POST[$key]) and is_numeric($_POST[$key]) and strlen(trim($_POST[$key]))) ? (int) $_POST[$key] : null;
                 $key = "bowlerNoBalls{$i}";
                 $no_balls = (isset($_POST[$key]) and is_numeric($_POST[$key]) and strlen(trim($_POST[$key]))) ? (int) $_POST[$key] : null;
                 $key = "bowlerWides{$i}";
                 $wides = (isset($_POST[$key]) and is_numeric($_POST[$key]) and strlen(trim($_POST[$key]))) ? (int) $_POST[$key] : null;
                 $key = "bowlerRuns{$i}";
                 $runs = (isset($_POST[$key]) and is_numeric($_POST[$key]) and strlen(trim($_POST[$key]))) ? (int) $_POST[$key] : null;
                 # Add that over to the match result
                 $bowling = new Over($player);
                 $bowling->SetBalls($balls);
                 $bowling->SetNoBalls($no_balls);
                 $bowling->SetWides($wides);
                 $bowling->SetRunsInOver($runs);
                 if ($home_batting) {
                     $match->Result()->AwayOvers()->Add($bowling);
                 } else {
                     $match->Result()->HomeOvers()->Add($bowling);
                 }
             }
         }
     }
     return $match;
 }