DIR : /home/kozerus/public_html/dgs/tournaments/include/tournament_status.php

/home/kozerus/public_html/dgs/tournaments/include

<?php
/*
Dragon Go Server
Copyright (C) 2001-  Erik Ouchterlony, Jens-Uwe Gaspar

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

 /* Author: Jens-Uwe Gaspar */

$TranslateGroups[] = "Tournament";

require_once 'include/std_classes.php';
require_once 'tournaments/include/tournament.php';
require_once 'tournaments/include/tournament_cache.php';
require_once 'tournaments/include/tournament_director.php';
require_once 'tournaments/include/tournament_factory.php';
require_once 'tournaments/include/tournament_games.php';
require_once 'tournaments/include/tournament_participant.php';
require_once 'tournaments/include/tournament_properties.php';
require_once 'tournaments/include/tournament_result.php';
require_once 'tournaments/include/tournament_utils.php';

 /*!
  * \file tournament_status.php
  *
  * \brief class with checks for different phases/status of tournaments
  */


 /*!
  * \class TournamentStatus
  *
  * \brief Class to help with precondition-checks for tournaments
  */
class TournamentStatus
{
   private $tid; // Tournament.ID
   private $tourney; // Tournament-object
   private $ttype; // specific typed TournamentTemplate-object
   private $tprops; // TournamentProperties-object
   private $tround; // TournamentRound-object
   private $curr_status; // old Tournament.Status
   private $new_status; // new Tournament.Status
   private $errors; // arr
   private $warnings; // arr


   /*!
    * \brief Constructs TournamentStatus.
    * \param $tid Tournament-object or tournament-id
    */
   public function __construct( $tid )
   {
      if ( $tid instanceof Tournament )
      {
         $this->tourney = $tid;
         $this->tid = $this->tourney->ID;
      }
      elseif ( is_numeric($tid) && $tid > 0 )
      {
         $this->tid = (int)$tid;
         $this->tourney = TournamentCache::load_cache_tournament(
            'TournamentStatus.construct.find_tournament.find_tournament', $this->tid );
      }
      if ( is_null($this->tourney) || (int)$this->tid <= 0 )
         error('unknown_tournament', "TournamentStatus.construct.find_tournament2({$this->tid})");

      $this->ttype = TournamentFactory::getTournament($this->tourney->WizardType);
      $this->tprops = null;
      $this->tround = null;

      $this->curr_status = $this->new_status = $this->tourney->Status;
      $this->errors = array();
      $this->warnings = array();
   }

   public function get_tournament()
   {
      return $this->tourney;
   }

   public function has_error()
   {
      return (bool)count($this->errors);
   }

   public function get_errors()
   {
      return $this->errors;
   }

   public function add_error( $str )
   {
      if ( $str )
         $this->errors[] = $str;
   }

   public function has_warning()
   {
      return (bool)count($this->warnings);
   }

   public function get_warnings()
   {
      return $this->warnings;
   }

   public function add_warning( $str )
   {
      if ( $str )
         $this->warnings[] = $str;
   }

   public function get_current_status()
   {
      return $this->curr_status;
   }

   public function get_new_status()
   {
      return $this->new_status;
   }

   /*! \internal to load TournamentProperties. */
   private function _load_tprops()
   {
      if ( is_null($this->tprops) )
         $this->tprops = TournamentCache::load_cache_tournament_properties( 'TournamentStatus.find_tprops', $this->tid );
   }

   /*! \internal to load TournamentRound (if needed). */
   private function _load_tround()
   {
      if ( is_null($this->tround) && $this->ttype->need_rounds )
      {
         $round = $this->tourney->CurrentRound;
         $this->tround = TournamentCache::load_cache_tournament_round( 'TournamentStatus.find_tround', $this->tid, $round );
      }
   }

   /*! \brief Checks change for new-status (writes also $this->errors). */
   public function check_status_change( $new_status )
   {
      $this->new_status = $new_status;

      if ( $this->curr_status != $new_status )
      {
         // expected status is: TOURNEY_STATUS_(ADM|NEW|REG|PAIR|PLAY|CLOSED|DEL)
         $check_funcname = 'check_conditions_status_' . strtoupper($new_status);
         call_user_func( array( $this, $check_funcname ) );
      }
   }



   /*!
    * \brief Check if change to ADM-tourney-status is allowed.
    * \note Change to ADM-status is mostly done to take tournament completly out of the loop.
    *       It should be documented somewhere what the last status was to be able to reactivate it,
    *       because the status before the change could be any status.
    */
   public function check_conditions_status_ADM()
   {
      $this->errors[] = sprintf( T_('Change on Tournament Status [%s] only allowed by Tournament Admin.'),
                                 Tournament::getStatusText($this->new_status) );
   }


   /*!
    * \brief Check if change to NEW-tourney-status is allowed.
    * \note Change to NEW-status can normally happen to re-activate a tournament from ADM-status or
    *       for a finished or deleted and resetted tournament.
    */
   public function check_conditions_status_NEW()
   {
      $this->errors[] = sprintf( T_('Change on Tournament Status [%s] only allowed by Tournament Admin.'),
                                 Tournament::getStatusText($this->new_status) );
   }


   /*!
    * \brief Check if change to REG-tourney-status is allowed.
    * \note Normal allowed status-change is only NEW-to-REG.
    */
   public function check_conditions_status_REG()
   {
      $this->check_expected_status( TOURNEY_STATUS_NEW );
      $this->check_basic_conditions_status_change();

      if ( $this->tourney->CurrentRound > 1 )
         $this->errors[] = sprintf( T_('Tournament-Status [%s] is only allowed for first round.'),
            Tournament::getStatusText(TOURNEY_STATUS_REGISTER) );

      // check tournament-type specific checks
      $this->errors = array_merge( $this->errors,
         $this->ttype->checkProperties( $this->tourney, TOURNEY_STATUS_REGISTER ) );
   }


   /*!
    * \brief Check if change to PAIR-tourney-status is allowed.
    * \note Normal allowed status-change is only REG-to-PAIR.
    * \note IMPORTANT: Do NOT use these checks for PLAY-to-PAIR status-change as different checks for higher rounds are required!
    */
   public function check_conditions_status_PAIR()
   {
      global $base_path;

      $this->check_expected_status( TOURNEY_STATUS_REGISTER );
      $this->check_basic_conditions_status_change();

      // check min/max participants-count for current round on TP.NextRound
      $curr_round = $this->tourney->CurrentRound;
      $this->_load_tprops();
      $this->_load_tround();
      $min_participants = $this->ttype->calcTournamentMinParticipants( $this->tprops, $this->tround );
      $max_participants = $this->tprops->getMaxParticipants();
      $tp_reg_count = TournamentParticipant::count_tournament_participants(
         $this->tid, TP_STATUS_REGISTER, $curr_round, /*NextR*/true );
      if ( $min_participants > 0 && $tp_reg_count < $min_participants )
      {
         $this->errors[] = sprintf(
            T_('Tournament min. participant limit (%s users) for round %s has not been reached yet: %s registrations are missing.'),
            $min_participants, $curr_round, $min_participants - $tp_reg_count );
      }
      if ( $curr_round == 1 && $tp_reg_count > $max_participants ) // no MAX-TP-check for higher rounds
         $this->errors[] = sprintf( T_('Tournament max. participant limit (%s users) has been exceeded by %s registrations.'),
            $max_participants, $tp_reg_count - $max_participants );

      // check basic restrictions for all REGISTERED users for ALL rounds 1..n on TP.StartRound.
      // (checks on TP.NextRound for higher rounds must be done separately)
      $iterator = new ListIterator( 'TournamentStatus.check_conditions_status_PAIR.TP',
            new QuerySQL( SQLP_WHERE, "TP.Status='".TP_STATUS_REGISTER."'" )); // only registered TPs
      $iterator = TournamentParticipant::load_tournament_participants($iterator, $this->tid);
      $err_count = $limit_err_count = 50; // check all, but limit error-output to some users
      while ( list(,$arr_item) = $iterator->getListIterator() )
      {
         list( $tp, $orow ) = $arr_item;
         list( $reg_errors, $reg_warnings ) =
            $this->tprops->checkUserRegistration( $this->tourney, $tp, $tp->User, TCHKTYPE_TD, /*chk-flags*/0 );
         foreach ( $reg_errors as $err )
         {
            $err_link = anchor( $base_path."tournaments/edit_participant.php?tid={$this->tid}".URI_AMP."uid={$tp->uid}", $tp->User->Handle );
            $this->errors[] = make_html_safe( sprintf( T_('Error for user %s'), "[$err_link]"), 'line') . ": $err";
            if ( $err_count-- <= 0 )
               break;
         }
         if ( $err_count < 0 )
            break;
      }
      if ( $err_count < 0 )
         $this->errors[] = sprintf( T_('More than %s errors occured, so output was limited.#tourney'), $limit_err_count );

      // warn about TPs in higher start-rounds
      $tp_rnd_counts = TournamentParticipant::count_registered_tournament_participants( $this->tid, $curr_round + 1 );
      $arr_rounds = array();
      foreach ( $tp_rnd_counts as $start_round => $cnt_tp )
      {
         if ( $cnt_tp > 0 )
            $arr_rounds[] = sprintf( T_('%s users for round #%s#tourney'), $cnt_tp, $start_round );
      }
      if ( count($arr_rounds) )
         $this->warnings[] = sprintf( T_('Be prepared to handle participants on higher start rounds [%s].#tourney'),
            implode(', ', $arr_rounds) );

      // check tournament-type specific checks
      $this->errors = array_merge( $this->errors,
         $this->ttype->checkProperties( $this->tourney, TOURNEY_STATUS_PAIR ) );
   }//check_conditions_status_PAIR


   /*!
    * \brief Check if change to PLAY-tourney-status is allowed.
    * \note Normal allowed status-change is only PAIR-to-PLAY.
    */
   public function check_conditions_status_PLAY()
   {
      $this->check_expected_status( TOURNEY_STATUS_PAIR );
      $this->check_basic_conditions_status_change();

      // check that all registered TPs are added
      $arr_TPs = TournamentParticipant::load_tournament_participants_registered( $this->tid, $this->tourney->CurrentRound );
      $check_errors = $this->ttype->checkParticipantRegistrations( $this->tid, $arr_TPs );
      if ( count($check_errors) )
         $this->errors = array_merge( $this->errors, $check_errors );

      // check that all games have been started
      $this->errors = array_merge( $this->errors,
         $this->ttype->checkGamesStarted( $this->tid ) );
   }


   /*!
    * \brief Check if change to CLOSED-tourney-status is allowed.
    * \note Normal allowed status-change is only PLAY-to-CLOSED.
    */
   public function check_conditions_status_CLOSED()
   {
      $this->check_expected_status( TOURNEY_STATUS_PLAY );
      $this->check_basic_conditions_status_change();

      $this->check_conditions_unfinished_tourney_games();
      $this->check_conditions_missing_tournament_results();

      list( $chk_errors, $chk_warnings ) = $this->ttype->checkClosingTournament( $this->tourney );
      $this->errors = array_merge( $this->errors, $chk_errors );
      $this->warnings = array_merge( $this->warnings, $chk_warnings );
   }


   /*!
    * \brief Check if change to DEL-tourney-status is allowed.
    * \note This could happen if a tournament is discontinued (normally done by admin, but allowed for TD as well).
    */
   public function check_conditions_status_DEL()
   {
      $this->check_conditions_unfinished_tourney_games();
   }



   /*! \brief Checks basic conditions for change of tourney-status: title/description/TD. */
   public function check_basic_conditions_status_change()
   {
      if ( strlen($this->tourney->Title) < 8 )
         $this->errors[] = T_('Tournament title missing or too short');
      if ( strlen($this->tourney->Description) < 4 )
         $this->errors[] = T_('Tournament description missing or too short');
      if ( !TournamentDirector::has_tournament_director($this->tid) )
         $this->errors[] = T_('Missing at least one tournament director');
   }

   /*! \brief Checks if there are unfinished tourney-games that can prohibit tourney-status-change. */
   private function check_conditions_unfinished_tourney_games()
   {
      // check for not-DONE T-games
      $tg_count_running = TournamentGames::count_tournament_games( $this->tid );
      if ( $tg_count_running > 0 )
      {
         $this->errors[] = sprintf( T_('Tournament has %s unfinished tournament games, that must be ended first.'),
            $tg_count_running );
      }
   }

   /*! \brief Checks if there are no tournament-results (for last round) of tournament. */
   private function check_conditions_missing_tournament_results()
   {
      $tresult_count = TournamentResult::count_tournament_results(
         "TournamentStatus.check_conditions_missing_tournament_results.TResult", $this->tid, $this->tourney->Rounds );
      if ( $tresult_count == 0 )
      {
         $this->warnings[] = sprintf( T_('Missing tournament-results for final round #%s in this tournament.'),
            $this->tourney->Rounds );
      }
   }


   // \param $arr_status status-array or single status
   private function check_expected_status( $arr_status )
   {
      if ( !is_array($arr_status) )
         $arr_status = array( $arr_status );

      if ( !in_array( $this->curr_status, $arr_status ) )
      {
         $this->errors[] = sprintf( T_('Expecting current Tournament Status [%s] for change to status [%s]'),
            build_text_list( 'Tournament::getStatusText', $arr_status, ' | ' ),
            Tournament::getStatusText($this->new_status) );
      }
   }//check_expected_status

   /*!
    * \brief Checks if current tournament-status allows certain action.
    * \param $errmsgfmt error-message-format expecting two args: 1. tourney-status, 2. expected status-list
    * \param $arr_status status-array
    * \param $arr_status_td_adm_edit status-array to check against $t_director with TD_FLAG_ADMIN_EDIT rights
    * \param $t_director if TournamentDirector-object check tournament-status against $arr_status_td_adm_edit
    *       and director-flags
    * \param $allow_admin if true, admin can do anything; otherwise admin is treated like non-admin
    * \return error-list; empty if no error
    */
   private function check_action_status( $errmsgfmt, array $arr_status, array $arr_status_td_adm_edit = null,
                                         TournamentDirector $t_director = null, $allow_admin = true )
   {
      $errors = array();

      // T-Admin can do anything at any time
      if ( $allow_admin && TournamentUtils::isAdmin() )
         $allow = true;
      elseif ( !is_null($t_director) && ($t_director->Flags & TD_FLAG_ADMIN_EDIT) && is_array($arr_status_td_adm_edit) )
         $allow = in_array($this->tourney->Status, $arr_status_td_adm_edit);
      else
         $allow = in_array($this->tourney->Status, $arr_status);

      if ( !$allow )
      {
         $errors[] = sprintf( $errmsgfmt,
                              Tournament::getStatusText($this->tourney->Status),
                              build_text_list( 'Tournament::getStatusText', $arr_status, ' | ' ) );
      }

      return $errors;
   }//check_action_status

   public function check_edit_status( array $arr_status, array $arr_status_td_adm_edit = null,
                                      TournamentDirector $t_director = null, $allow_admin = true )
   {
      return $this->check_action_status(
         T_('Edit is forbidden for tournament on status [%s], only allowed for [%s] !'),
         $arr_status, $arr_status_td_adm_edit, $t_director, $allow_admin );
   }

   public function check_view_status( array $arr_status, array $arr_status_td_adm_edit = null,
                                      TournamentDirector $t_director = null, $allow_admin = true )
   {
      return $this->check_action_status(
         T_('View of tournament is forbidden on status [%s], only allowed for [%s] !'),
         $arr_status, $arr_status_td_adm_edit, $t_director, $allow_admin );
   }

} // end of 'TournamentStatus'

?>
//


koh5_pano



Your browser does not support the HTML5 canvas element.


Drag mouse to navigate.

Navigation





17.Aug.2010, Martin Wengenmayer