/**
  * Simulates youth matches. They are executed differently from normal matches sinc they have a different structure
  * and other simulation observers.
  * 
  * @param WebSoccer $websoccer Application context.
  * @param DbConnection $db DB conncetion.
  * @param int $maxMatchesToSimulate Maximum number of matches to simulate.
  */
 public static function simulateOpenYouthMatches(WebSoccer $websoccer, DbConnection $db, $maxMatchesToSimulate)
 {
     // is feature enabled at the moment?
     if (!$websoccer->getConfig('youth_enabled')) {
         return;
     }
     $simulator = new Simulator($db, $websoccer);
     // observer stores results
     $simulator->attachObserver(new YouthMatchDataUpdateSimulatorObserver($websoccer, $db));
     // ceate match report items on events
     $simulator->getSimulationStrategy()->attachObserver(new YouthMatchReportSimulationObserver($websoccer, $db));
     // get matches to simulate
     $result = $db->querySelect('*', $websoccer->getConfig('db_prefix') . '_youthmatch', 'simulated != \'1\' AND matchdate <= %d ORDER BY matchdate ASC', $websoccer->getNowAsTimestamp(), $maxMatchesToSimulate);
     while ($matchinfo = $result->fetch_array()) {
         $match = self::_createMatch($websoccer, $db, $matchinfo);
         if ($match != null) {
             $simulator->simulateMatch($match, 100);
             // let garbage collector free memory before script execution by removing all references to objects
             $match->cleanReferences();
             unset($match);
         }
     }
     $result->free();
 }
 /**
  * Gets matches to simulate, registers simulation obervers, creates internal data model (loading data from the database)
  * and eventually calls the Simulator. After simulation, it stores the current state.
  * Additionally, it triggers also youth matches simulation, in case maximum number of matches has not exceeded yet.
  * 
  * @param WebSoccer $websoccer request context.
  * @param DbConnection $db database connection.
  */
 public static function simulateOpenMatches(WebSoccer $websoccer, DbConnection $db)
 {
     $simulator = new Simulator($db, $websoccer);
     // add creating match report texts
     $strategy = $simulator->getSimulationStrategy();
     $simulationObservers = explode(',', $websoccer->getConfig('sim_simulation_observers'));
     foreach ($simulationObservers as $observerClassName) {
         $observerClass = trim($observerClassName);
         if (strlen($observerClass)) {
             $strategy->attachObserver(new $observerClass($websoccer, $db));
         }
     }
     $simulatorObservers = explode(',', $websoccer->getConfig('sim_simulator_observers'));
     foreach ($simulatorObservers as $observerClassName) {
         $observerClass = trim($observerClassName);
         if (strlen($observerClass)) {
             $simulator->attachObserver(new $observerClass($websoccer, $db));
         }
     }
     // find and execute open matches
     $fromTable = $websoccer->getConfig('db_prefix') . '_spiel AS M';
     $fromTable .= ' INNER JOIN ' . $websoccer->getConfig('db_prefix') . '_verein AS HOME_T ON HOME_T.id = M.home_verein';
     $fromTable .= ' INNER JOIN ' . $websoccer->getConfig('db_prefix') . '_verein AS GUEST_T ON GUEST_T.id = M.gast_verein';
     $fromTable .= ' LEFT JOIN ' . $websoccer->getConfig('db_prefix') . '_aufstellung AS HOME_F ON HOME_F.match_id = M.id AND HOME_F.verein_id = M.home_verein';
     $fromTable .= ' LEFT JOIN ' . $websoccer->getConfig('db_prefix') . '_aufstellung AS GUEST_F ON GUEST_F.match_id = M.id AND GUEST_F.verein_id = M.gast_verein';
     $columns['M.id'] = 'match_id';
     $columns['M.spieltyp'] = 'type';
     $columns['M.home_verein'] = 'home_id';
     $columns['M.gast_verein'] = 'guest_id';
     $columns['M.minutes'] = 'minutes';
     $columns['M.soldout'] = 'soldout';
     $columns['M.elfmeter'] = 'penaltyshooting';
     $columns['M.pokalname'] = 'cup_name';
     $columns['M.pokalrunde'] = 'cup_roundname';
     $columns['M.pokalgruppe'] = 'cup_groupname';
     $columns['M.stadion_id'] = 'custom_stadium_id';
     $columns['M.player_with_ball'] = 'player_with_ball';
     $columns['M.prev_player_with_ball'] = 'prev_player_with_ball';
     $columns['M.home_tore'] = 'home_goals';
     $columns['M.gast_tore'] = 'guest_goals';
     $columns['M.home_offensive'] = 'home_offensive';
     $columns['M.home_setup'] = 'home_setup';
     $columns['M.home_noformation'] = 'home_noformation';
     $columns['M.home_longpasses'] = 'home_longpasses';
     $columns['M.home_counterattacks'] = 'home_counterattacks';
     $columns['M.home_morale'] = 'home_morale';
     $columns['M.home_freekickplayer'] = 'home_freekickplayer';
     $columns['M.gast_offensive'] = 'guest_offensive';
     $columns['M.guest_noformation'] = 'guest_noformation';
     $columns['M.gast_setup'] = 'guest_setup';
     $columns['M.gast_longpasses'] = 'guest_longpasses';
     $columns['M.gast_counterattacks'] = 'guest_counterattacks';
     $columns['M.gast_morale'] = 'guest_morale';
     $columns['M.gast_freekickplayer'] = 'guest_freekickplayer';
     $columns['HOME_F.id'] = 'home_formation_id';
     $columns['HOME_F.offensive'] = 'home_formation_offensive';
     $columns['HOME_F.setup'] = 'home_formation_setup';
     $columns['HOME_F.longpasses'] = 'home_formation_longpasses';
     $columns['HOME_F.counterattacks'] = 'home_formation_counterattacks';
     $columns['HOME_F.freekickplayer'] = 'home_formation_freekickplayer';
     $columns['HOME_T.name'] = 'home_name';
     $columns['HOME_T.nationalteam'] = 'home_nationalteam';
     $columns['HOME_T.interimmanager'] = 'home_interimmanager';
     $columns['HOME_T.captain_id'] = 'home_captain_id';
     $columns['GUEST_T.nationalteam'] = 'guest_nationalteam';
     $columns['GUEST_T.name'] = 'guest_name';
     $columns['GUEST_T.captain_id'] = 'guest_captain_id';
     $columns['GUEST_T.interimmanager'] = 'guest_interimmanager';
     for ($playerNo = 1; $playerNo <= 11; $playerNo++) {
         $columns['HOME_F.spieler' . $playerNo] = 'home_formation_player' . $playerNo;
         $columns['HOME_F.spieler' . $playerNo . '_position'] = 'home_formation_player_pos_' . $playerNo;
         $columns['GUEST_F.spieler' . $playerNo] = 'guest_formation_player' . $playerNo;
         $columns['GUEST_F.spieler' . $playerNo . '_position'] = 'guest_formation_player_pos_' . $playerNo;
         if ($playerNo <= 5) {
             $columns['HOME_F.ersatz' . $playerNo] = 'home_formation_bench' . $playerNo;
             $columns['GUEST_F.ersatz' . $playerNo] = 'guest_formation_bench' . $playerNo;
         }
     }
     // substitutions
     for ($subNo = 1; $subNo <= 3; $subNo++) {
         // will be used for initial creation
         $columns['HOME_F.w' . $subNo . '_raus'] = 'home_formation_sub' . $subNo . '_out';
         $columns['HOME_F.w' . $subNo . '_rein'] = 'home_formation_sub' . $subNo . '_in';
         $columns['HOME_F.w' . $subNo . '_minute'] = 'home_formation_sub' . $subNo . '_minute';
         $columns['HOME_F.w' . $subNo . '_condition'] = 'home_formation_sub' . $subNo . '_condition';
         $columns['HOME_F.w' . $subNo . '_position'] = 'home_formation_sub' . $subNo . '_position';
         // will be used for loading from state
         $columns['M.home_w' . $subNo . '_raus'] = 'home_sub_' . $subNo . '_out';
         $columns['M.home_w' . $subNo . '_rein'] = 'home_sub_' . $subNo . '_in';
         $columns['M.home_w' . $subNo . '_minute'] = 'home_sub_' . $subNo . '_minute';
         $columns['M.home_w' . $subNo . '_condition'] = 'home_sub_' . $subNo . '_condition';
         $columns['M.home_w' . $subNo . '_position'] = 'home_sub_' . $subNo . '_position';
         $columns['GUEST_F.w' . $subNo . '_raus'] = 'guest_formation_sub' . $subNo . '_out';
         $columns['GUEST_F.w' . $subNo . '_rein'] = 'guest_formation_sub' . $subNo . '_in';
         $columns['GUEST_F.w' . $subNo . '_minute'] = 'guest_formation_sub' . $subNo . '_minute';
         $columns['GUEST_F.w' . $subNo . '_condition'] = 'guest_formation_sub' . $subNo . '_condition';
         $columns['GUEST_F.w' . $subNo . '_position'] = 'guest_formation_sub' . $subNo . '_position';
         $columns['M.gast_w' . $subNo . '_raus'] = 'guest_sub_' . $subNo . '_out';
         $columns['M.gast_w' . $subNo . '_rein'] = 'guest_sub_' . $subNo . '_in';
         $columns['M.gast_w' . $subNo . '_minute'] = 'guest_sub_' . $subNo . '_minute';
         $columns['M.gast_w' . $subNo . '_condition'] = 'guest_sub_' . $subNo . '_condition';
         $columns['M.gast_w' . $subNo . '_position'] = 'guest_sub_' . $subNo . '_position';
     }
     $columns['GUEST_F.id'] = 'guest_formation_id';
     $columns['GUEST_F.offensive'] = 'guest_formation_offensive';
     $columns['GUEST_F.setup'] = 'guest_formation_setup';
     $columns['GUEST_F.longpasses'] = 'guest_formation_longpasses';
     $columns['GUEST_F.counterattacks'] = 'guest_formation_counterattacks';
     $columns['GUEST_F.freekickplayer'] = 'guest_formation_freekickplayer';
     $whereCondition = 'M.berechnet != \'1\' AND M.blocked != \'1\' AND M.datum <= %d ORDER BY M.datum ASC';
     $parameters = $websoccer->getNowAsTimestamp();
     $interval = (int) $websoccer->getConfig('sim_interval');
     $maxMatches = (int) $websoccer->getConfig('sim_max_matches_per_run');
     $result = $db->querySelect($columns, $fromTable, $whereCondition, $parameters, $maxMatches);
     $matchesSimulated = 0;
     $lockArray = array('blocked' => '1');
     $unlockArray = array('blocked' => '0');
     $matchTable = $websoccer->getConfig('db_prefix') . '_spiel';
     while ($matchinfo = $result->fetch_array()) {
         // lock record
         $db->queryUpdate($lockArray, $matchTable, 'id = %d', $matchinfo['match_id']);
         $match = null;
         if ($matchinfo['minutes'] < 1) {
             $match = self::createInitialMatchData($websoccer, $db, $matchinfo);
         } else {
             $match = SimulationStateHelper::loadMatchState($websoccer, $db, $matchinfo);
         }
         if ($match != null) {
             $simulator->simulateMatch($match, $interval);
             SimulationStateHelper::updateState($websoccer, $db, $match);
         }
         // let garbage collector free memory before script execution by removing all references to objects
         $match->cleanReferences();
         unset($match);
         // unlock record
         $db->queryUpdate($unlockArray, $matchTable, 'id = %d', $matchinfo['match_id']);
         $matchesSimulated++;
     }
     $result->free();
     // Simulate youth matches
     $maxYouthMatchesToSimulate = $maxMatches - $matchesSimulated;
     if ($maxYouthMatchesToSimulate) {
         YouthMatchSimulationExecutor::simulateOpenYouthMatches($websoccer, $db, $maxYouthMatchesToSimulate);
     }
 }