/**
  * Marks user as absent, makes his teams managable by deputy and sends deputy notification about it.
  * 
  * @param WebSoccer $websoccer Application context.
  * @param DbConnection $db DB connection.
  * @param int $userId ID of user who is absent.
  * @param int $deputyId ID of user's deputy during absence.
  * @param int $days Number of days to be absent.
  */
 public static function makeUserAbsent(WebSoccer $websoccer, DbConnection $db, $userId, $deputyId, $days)
 {
     // create absence record
     $fromDate = $websoccer->getNowAsTimestamp();
     $toDate = $fromDate + 24 * 3600 * $days;
     $db->queryInsert(array('user_id' => $userId, 'deputy_id' => $deputyId, 'from_date' => $fromDate, 'to_date' => $toDate), $websoccer->getConfig('db_prefix') . '_userabsence');
     // update manager reference of managed teams
     $db->queryUpdate(array('user_id' => $deputyId, 'user_id_actual' => $userId), $websoccer->getConfig('db_prefix') . '_verein', 'user_id = %d', $userId);
     // create notification for deputy
     $user = UsersDataService::getUserById($websoccer, $db, $userId);
     NotificationsDataService::createNotification($websoccer, $db, $deputyId, 'absence_notification', array('until' => $toDate, 'user' => $user['nick']), 'absence', 'user');
 }
 private static function createTransaction(WebSoccer $websoccer, DbConnection $db, $user, $userId, $amount, $subject, $data)
 {
     // create transaction
     $fromTable = $websoccer->getConfig('db_prefix') . '_premiumstatement';
     $columns = array('user_id' => $userId, 'action_id' => $subject, 'amount' => $amount, 'created_date' => $websoccer->getNowAsTimestamp(), 'subject_data' => json_encode($data));
     $db->queryInsert($columns, $fromTable);
     // update user budget
     $newBudget = $user['premium_balance'] + $amount;
     $updateColumns = array('premium_balance' => $newBudget);
     $fromTable = $websoccer->getConfig('db_prefix') . '_user';
     $whereCondition = 'id = %d';
     $parameters = $userId;
     $db->queryUpdate($updateColumns, $fromTable, $whereCondition, $parameters);
     // also update user profile, if executed by user.
     if ($userId == $websoccer->getUser()->id) {
         $websoccer->getUser()->premiumBalance = $newBudget;
     }
 }
 private static function createTransaction(WebSoccer $websoccer, DbConnection $db, $team, $teamId, $amount, $subject, $sender)
 {
     // ignore transaction if team is without user and option is enabled
     if (!$team["user_id"] && $websoccer->getConfig("no_transactions_for_teams_without_user")) {
         return;
     }
     // create transaction
     $fromTable = $websoccer->getConfig("db_prefix") . "_konto";
     $columns["verein_id"] = $teamId;
     $columns["absender"] = $sender;
     $columns["betrag"] = $amount;
     $columns["datum"] = $websoccer->getNowAsTimestamp();
     $columns["verwendung"] = $subject;
     $db->queryInsert($columns, $fromTable);
     // update team budget
     $newBudget = $team["team_budget"] + $amount;
     $updateColumns["finanz_budget"] = $newBudget;
     $fromTable = $websoccer->getConfig("db_prefix") . "_verein";
     $whereCondition = "id = %d";
     $parameters = $teamId;
     $db->queryUpdate($updateColumns, $fromTable, $whereCondition, $parameters);
 }
 private static function updateMaintenanceStatus(WebSoccer $websoccer, DbConnection $db, $homeInfo)
 {
     $columns = array('maintenance_pitch' => $homeInfo['maintenance_pitch'] - 1, 'maintenance_videowall' => $homeInfo['maintenance_videowall'] - 1, 'maintenance_seatsquality' => $homeInfo['maintenance_seatsquality'] - 1, 'maintenance_vipquality' => $homeInfo['maintenance_vipquality'] - 1);
     // check if maintenance interval expired
     $types = array('pitch', 'videowall', 'seatsquality', 'vipquality');
     foreach ($types as $type) {
         if ($columns['maintenance_' . $type] <= 0) {
             $columns['maintenance_' . $type] = $websoccer->getConfig('stadium_maintenanceinterval_' . $type);
             $columns['level_' . $type] = max(0, $homeInfo['level_' . $type] - 1);
         }
     }
     $db->queryUpdate($columns, $websoccer->getConfig('db_prefix') . '_stadion', 'id = %d', $homeInfo['stadium_id']);
 }
 /**
  * Creates a new action log for the specified user and deletes old ones.
  * If there is already a recent log for the same action, it will onl update the timestamp.
  * 
  * @param WebSoccer $websoccer Application context.
  * @param DbConnection $db DB connection.
  * @param int $userId ID of user.
  * @param string $actionId Action name.
  */
 public static function createOrUpdateActionLog(WebSoccer $websoccer, DbConnection $db, $userId, $actionId)
 {
     $fromTable = $websoccer->getConfig('db_prefix') . '_useractionlog';
     // delete old entries of user (entries which are older than 20 days)
     $deleteTimeThreshold = $websoccer->getNowAsTimestamp() - 24 * 3600 * 20;
     $db->queryDelete($fromTable, 'user_id = %d AND created_date < %d', array($userId, $deleteTimeThreshold));
     // check if action has been triggered within the last X minutes. If so, just update timestamp rather than filling DB unnecessary.
     $timeThreshold = $websoccer->getNowAsTimestamp() - 30 * 60;
     $result = $db->querySelect('id', $fromTable, 'user_id = %d AND action_id = \'%s\' AND created_date >= %d ORDER BY created_date DESC', array($userId, $actionId, $timeThreshold), 1);
     $lastLog = $result->fetch_array();
     $result->free();
     // update last log
     if ($lastLog) {
         $db->queryUpdate(array('created_date' => $websoccer->getNowAsTimestamp()), $fromTable, 'id = %d', $lastLog['id']);
         // create new log
     } else {
         $db->queryInsert(array('user_id' => $userId, 'action_id' => $actionId, 'created_date' => $websoccer->getNowAsTimestamp()), $fromTable);
     }
 }
 private static function _transferPlayer(WebSoccer $websoccer, DbConnection $db, $playerId, $targetClubId, $targetUserId, $currentUserId, $currentClubId, $amount, $exchangePlayer1 = 0, $exchangePlayer2 = 0)
 {
     $db->queryUpdate(array("verein_id" => $targetClubId, "vertrag_spiele" => $websoccer->getConfig("transferoffers_contract_matches")), $websoccer->getConfig("db_prefix") . "_spieler", "id = %d", $playerId);
     // create log
     $db->queryInsert(array("bid_id" => 0, "datum" => $websoccer->getNowAsTimestamp(), "spieler_id" => $playerId, "seller_user_id" => $currentUserId, "seller_club_id" => $currentClubId, "buyer_user_id" => $targetUserId, "buyer_club_id" => $targetClubId, "directtransfer_amount" => $amount, "directtransfer_player1" => $exchangePlayer1, "directtransfer_player2" => $exchangePlayer2), $websoccer->getConfig("db_prefix") . "_transfer");
 }
 private static function updatePlayerState(WebSoccer $websoccer, DbConnection $db, $matchId, $player, $fieldArea)
 {
     $fromTable = $websoccer->getConfig('db_prefix') . '_spiel_berechnung';
     $whereCondition = 'spieler_id = %d AND spiel_id = %d';
     $parameters = array($player->id, $matchId);
     $columns = self::getPlayerColumns($matchId, $player, $fieldArea);
     $db->queryUpdate($columns, $fromTable, $whereCondition, $parameters);
 }
 /**
  * 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);
     }
 }