DIR : /home/kozerus/public_html/dgs/tournaments/include/tournament_participant.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/utilities.php';
require_once 'include/db_classes.php';
require_once 'include/gui_functions.php';
require_once 'include/rating.php';
require_once 'tournaments/include/tournament.php';
require_once 'tournaments/include/tournament_utils.php';
require_once 'tournaments/include/tournament_globals.php';

 /*!
  * \file tournament_participant.php
  *
  * \brief Functions for handling tournament participants: tables TournamentParticipant
  */


 /*!
  * \class TournamentParticipant
  *
  * \brief Class to manage TournamentParticipant-table
  */

global $ENTITY_TOURNAMENT_PARTICIPANT; //PHP5
$ENTITY_TOURNAMENT_PARTICIPANT = new Entity( 'TournamentParticipant',
      FTYPE_PKEY, 'ID',
      FTYPE_AUTO, 'ID',
      FTYPE_CHBY,
      FTYPE_INT,  'ID', 'tid', 'uid', 'Flags', 'StartRound', 'NextRound', 'Finished', 'Won', 'Lost', 'PenaltyPoints',
      FTYPE_FLOAT, 'Rating',
      FTYPE_TEXT, 'Comment', 'DirectorMessage',
      FTYPE_DATE, 'Created', 'Lastchanged', 'Lastmoved',
      FTYPE_ENUM, 'Status'
   );

class TournamentParticipant
{
   private static $ARR_TP_TEXTS = array(); // lazy-init in TournamentParticipant::get..Text()-funcs: [key][id] => text

   public $ID;
   public $tid;
   public $uid;
   public $Status; // null | TP_STATUS_...
   public $Flags;
   public $Rating; // NO_RATING | valid-rating
   public $StartRound;
   public $NextRound;
   public $Created;
   public $Lastchanged;
   public $ChangedBy;
   public $Comment;
   public $DirectorMessage;
   public $Finished;
   public $Won;
   public $Lost;
   public $PenaltyPoints;
   public $Lastmoved;

   // non-DB fields

   public $User; // User-object

   /*! \brief Constructs TournamentParticipant-object with specified arguments. */
   public function __construct( $id=0, $tid=0, $uid=0, User $user=NULL, $status=null, $flags=0,
         $rating=NULL, $start_round=1, $next_round=0, $created=0, $lastchanged=0, $changed_by='',
         $comment='', $director_message='', $finished=0, $won=0, $lost=0, $penalty_points=0, $lastmoved=0 )
   {
      $this->ID = (int)$id;
      $this->tid = (int)$tid;
      $this->uid = (int)$uid;
      $this->setStatus( $status );
      $this->Flags = (int)$flags;
      $this->setRating( $rating );
      $this->setStartRound( $start_round );
      $this->NextRound = (int)$next_round;
      $this->Created = (int)$created;
      $this->Lastchanged = (int)$lastchanged;
      $this->ChangedBy = $changed_by;
      $this->Comment = $comment;
      $this->DirectorMessage = $director_message;
      $this->Finished = (int)$finished;
      $this->Won = (int)$won;
      $this->Lost = (int)$lost;
      $this->PenaltyPoints = (int)$penalty_points;
      $this->Lastmoved = (int)$lastmoved;
      // non-DB fields
      $this->User = ($user instanceof User) ? $user : new User( $this->uid );
   }

   public function setStatus( $status )
   {
      if ( !is_null($status) && !preg_match( "/^(".CHECK_TP_STATUS.")$/", $status ) )
         error('invalid_args', "TournamentParticipant.setStatus($status)");
      $this->Status = $status;
   }

   public function setRating( $rating )
   {
      $this->Rating = TournamentUtils::normalizeRating( $rating );
   }

   public function hasRating()
   {
      return (abs($this->Rating) < OUT_OF_RATING);
   }

   public function setStartRound( $start_round )
   {
      $this->StartRound = limit( (int)$start_round, 1, 255, 1 );
   }

   /*!
    * \brief Checks if tid and uid of this TournamentParticipant-object matches given $tid and $uid.
    * \param $uid 0 to skip assertion on uid, e.g. for deletion
    * \see load_tournament_participant_by_id()
    */
   private function assert_tournament_participant( $dbgmsg, $tid, $uid )
   {
      if ( $this->tid != $tid )
         error('tournament_register_edit_not_allowed', $dbgmsg.".TP.assert_tp.check.tid($tid,$uid,{$this->ID})");
      if ( $uid > 0 && $this->uid != $uid )
         error('tournament_register_edit_not_allowed', $dbgmsg.".TP.assert_tp.check.uid($tid,$uid,{$this->ID})");
   }

   public function to_string()
   {
      return " ID=[{$this->ID}]"
            . ", tid=[{$this->tid}]"
            . ", uid=[{$this->uid}]"
            . sprintf( ", User=[%s]", $this->User->to_string() )
            . ", Status=[{$this->Status}]"
            . sprintf( ",Flags=[0x%x]", $this->Flags)
            . ", Rating=[{$this->Rating}]"
            . ", StartRound=[{$this->StartRound}]"
            . ", NextRound=[{$this->NextRound}]"
            . ", Created=[{$this->Created}]"
            . ", Lastchanged=[{$this->Lastchanged}]"
            . ", ChangedBy=[{$this->ChangedBy}]"
            . ", Comment=[{$this->Comment}]"
            . ", DirectorMessage=[{$this->DirectorMessage}]"
            . ", Finished=[{$this->Finished}]"
            . ", Won=[{$this->Won}]"
            . ", Lost=[{$this->Lost}]"
            . ", PenaltyPoints=[{$this->PenaltyPoints}]"
            . ", Lastmoved=[{$this->Lastmoved}]"
         ;
   }

   public function build_result_info()
   {
      $rating_str = ( is_valid_rating($this->Rating) )
         ? sprintf( T_(", T-Rating [%s][Elo rating %1.2f]"), echo_rating($this->Rating), $this->Rating )
         : '';
      return
         echo_image_info( "tournaments/edit_participant.php?tid={$this->tid}".URI_AMP."uid={$this->uid}",
            T_('Tournament Participant') )
         . MINI_SPACING
         . span('bold', T_('Tournament Participant'), '%s: ')
         . sprintf( T_("rid [%s], StartRound [%s], Finished [%s], Won [%s], Lost [%s], PenaltyPoints [%s],\n"
                  . "Flags [%s]%s,\n"
                  . "Created [%s]#tourney"),
               $this->ID, $this->StartRound, $this->Finished, $this->Won, $this->Lost, $this->PenaltyPoints,
               self::getFlagsText($this->Flags), $rating_str,
               ($this->Created > 0 ? date(DATE_FMT, $this->Created) : '') );
   }

   public function build_log_string()
   {
      $out = array();
      if ( $this->ID > 0 )
         $out[] = "ID=[{$this->ID}]";
      $out[] = "Status=[{$this->Status}]";
      $out[] = sprintf('Flags=[%s]', self::getFlagsText($this->Flags));
      if ( !is_null($this->Rating) )
         $out[] = "Rating=[{$this->Rating}]";
      $out[] = "StartRound=[{$this->StartRound}]";
      if ( $this->StartRound != $this->NextRound )
         $out[] = "NextRound=[{$this->NextRound}]";
      if ( (string)$this->Comment != '' )
         $out[] = "Comment=[{$this->Comment}]";
      if ( (string)$this->DirectorMessage != '' )
         $out[] = "DirMsg=[{$this->DirectorMessage}]";
      if ( $this->Finished + $this->Won + $this->Lost > 0 )
         $out[] = "Fin/Won/Lost=[{$this->Finished}/{$this->Won}/{$this->Lost}]";
      $out[] = "PenaltyPoints=[{$this->PenaltyPoints}]";
      if ( $this->Lastmoved > 0 )
         $out[] = "Lastmoved=[".date(DATE_FMT, $this->Lastmoved)."]";
      return implode(', ', $out);
   }//build_log_string

   public function calc_init_status( $rating_use_mode )
   {
      return ( $rating_use_mode == TPROP_RUMODE_COPY_CUSTOM && !$this->User->hasRating() )
         ? TP_STATUS_APPLY
         : TP_STATUS_REGISTER;
   }


   /*!
    * \brief Returns true if removal of tournament-participant is authorised.
    * \param $t_status TOURNEY_STATUS_...
    */
   public function authorise_delete( $t_status )
   {
      if ( $t_status == TOURNEY_STATUS_REGISTER )
         return true;
      if ( $t_status == TOURNEY_STATUS_PLAY && $this->ID && $this->Status != TP_STATUS_REGISTER )
         return true;
      return false;
   }

   /*!
    * \brief Returns true if editing customized fields is authorised.
    * \param $t_status TOURNEY_STATUS_...
    */
   public function authorise_edit_customized( $t_status )
   {
      if ( $t_status == TOURNEY_STATUS_REGISTER )
         return true;
      if ( $t_status == TOURNEY_STATUS_PLAY )
      {
         if ( $this->ID <= 0 || $this->Status != TP_STATUS_REGISTER )
            return true;
      }
      return false;
   }

   /*!
    * \brief Returns true if TP-status-change from TP-REGISTER is authorised.
    * \param $t_status TOURNEY_STATUS_...
    */
   public function authorise_edit_register_status( $t_status, $tp_status_old, array &$errors )
   {
      $allowed = false;
      if ( $t_status == TOURNEY_STATUS_REGISTER )
         $allowed = true;
      elseif ( $t_status == TOURNEY_STATUS_PLAY )
      {
         if ( $this->ID <= 0 ) // new
            $allowed = true;
         elseif ( $tp_status_old != TP_STATUS_REGISTER || $tp_status_old == $this->Status ) // existing TP
            $allowed = true;
      }

      if ( !$allowed )
         $errors[] = sprintf( T_('Registration status change [%s] to [%s] is not allowed for tournament status [%s].'),
                              (is_null($tp_status_old) ? NO_VALUE : self::getStatusText($tp_status_old)),
                              self::getStatusText($this->Status),
                              Tournament::getStatusText($t_status) );
      return $allowed;
   }//authorise_edit_register_status


   /*! \brief Inserts or updates tournament-participant in database. */
   public function persist()
   {
      if ( $this->ID > 0 )
         $success = $this->update();
      else
         $success = $this->insert();
      return $success;
   }

   public function insert()
   {
      $this->Created = $this->Lastchanged = $GLOBALS['NOW'];

      $this->checkData();
      $entityData = $this->fillEntityData(true);
      $result = $entityData->insert( "TournamentParticipant.insert(%s)" );
      if ( $result )
         $this->ID = mysql_insert_id();
      self::delete_cache_tournament_participant_counts( 'TournamentParticipant.insert', $this->tid );
      self::delete_cache_tournament_participant( 'TournamentParticipant.insert', $this->tid, $this->uid );
      return $result;
   }

   public function update()
   {
      $this->Lastchanged = $GLOBALS['NOW'];

      $this->checkData();
      $entityData = $this->fillEntityData();
      $result = $entityData->update( "TournamentParticipant.update(%s)" );
      self::delete_cache_tournament_participant_counts( 'TournamentParticipant.update', $this->tid );
      self::delete_cache_tournament_participant( 'TournamentParticipant.update', $this->tid, $this->uid );
      return $result;
   }

   public function delete()
   {
      $entityData = $this->fillEntityData();
      $result = $entityData->delete( "TournamentParticipant.delete(%s)" );
      self::delete_cache_tournament_participant_counts( 'TournamentParticipant.delete', $this->tid );
      self::delete_cache_tournament_participant( 'TournamentParticipant.delete', $this->tid, $this->uid );
      return $result;
   }

   private function checkData()
   {
      if ( is_null($this->Status) )
         error('invalid_args', "TournamentParticipant.checkData.miss_status({$this->ID},{$this->tid})");
   }

   public function fillEntityData( $withCreated=false )
   {
      // checked fields: Rating/StartRound
      $data = $GLOBALS['ENTITY_TOURNAMENT_PARTICIPANT']->newEntityData();
      $data->set_value( 'ID', $this->ID );
      $data->set_value( 'tid', $this->tid );
      $data->set_value( 'uid', $this->uid );
      $data->set_value( 'Status', $this->Status );
      $data->set_value( 'Flags', $this->Flags );
      $data->set_value( 'Rating', $this->Rating );
      $data->set_value( 'StartRound', $this->StartRound );
      $data->set_value( 'NextRound', $this->NextRound );
      if ( $withCreated )
         $data->set_value( 'Created', $this->Created );
      $data->set_value( 'Lastchanged', $this->Lastchanged );
      $data->set_value( 'ChangedBy', $this->ChangedBy );
      $data->set_value( 'Comment', $this->Comment );
      $data->set_value( 'DirectorMessage', $this->DirectorMessage );
      $data->set_value( 'Finished', $this->Finished );
      $data->set_value( 'Won', $this->Won );
      $data->set_value( 'Lost', $this->Lost );
      $data->set_value( 'PenaltyPoints', $this->PenaltyPoints );
      $data->set_value( 'Lastmoved', $this->Lastmoved );
      return $data;
   }


   // ------------ static functions ----------------------------

   /*!
    * \brief Returns count of TournamentParticipants for given tournament, TP-status, round and NextRound.
    * \param $tp_status one of TP_STATUS_... or array of TP_STATUS_... or null (=count all TP-stati)
    * \param $round 0 (=count all rounds), >0 (=count only given round)
    * \param $use_next_round true = match $next_round on TP.NextRound; false = match on TP.StartRound
    */
   public static function count_tournament_participants( $tid, $tp_status, $round, $use_next_round )
   {
      $qsql = new QuerySQL(
         SQLP_FIELDS, 'COUNT(*) AS X_Count',
         SQLP_FROM,   'TournamentParticipant',
         SQLP_WHERE,  "tid=$tid" );

      $stat_out = array();
      if ( is_array($tp_status) )
      {
         foreach ( $tp_status as $tp_stat )
            $stat_out[] = mysql_addslashes($tp_stat);
         if ( count($stat_out) )
            $qsql->add_part( SQLP_WHERE, "Status IN ('" . implode("','", $stat_out) . "')" );
      }
      elseif ( !is_null($tp_status) )
         $qsql->add_part( SQLP_WHERE, "Status='" . mysql_addslashes($tp_status) . "'" );

      $round_field = ($use_next_round) ? 'NextRound' : 'StartRound';
      if ( is_numeric($round) && $round > 0 )
         $qsql->add_part( SQLP_WHERE, "$round_field=$round" );

//error_log(sprintf("TP.count_tps($tid,$tp_status,$round,$use_next_round: SQL=[%s]", $qsql->get_select()));
      $row = mysql_single_fetch( "TournamentParticipant:count_TPs($tid,".implode('/',$stat_out).",$round_field=$round)",
            $qsql->get_select() );
      return ($row) ? (int)$row['X_Count'] : 0;
   }//count_tournament_participants

   /*!
    * \brief Returns count of registered TournamentParticipants group by StartRound.
    * \param $min_start_round 0 = find all rounds, >0 = find only entries with higher start-rounds
    * \return arr( TP.StartRound => count )
    */
   public static function count_registered_tournament_participants( $tid, $min_start_round )
   {
      $qsql = new QuerySQL(
         SQLP_FIELDS, 'StartRound', 'COUNT(*) AS X_Count',
         SQLP_FROM,   'TournamentParticipant',
         SQLP_WHERE,  "tid=$tid", "Status='".TP_STATUS_REGISTER."'",
         SQLP_GROUP,  'StartRound' );
      if ( is_numeric($min_start_round) && $min_start_round > 0 )
         $qsql->add_part( SQLP_WHERE, "StartRound >= $min_start_round" );

      $result = db_query( "TournamentParticipant:count_registered_TPs($tid,$min_start_round)", $qsql->get_select() );

      $out = array();
      while ( $row = mysql_fetch_array($result) )
         $out[$row['StartRound']] = (int)$row['X_Count'];
      mysql_free_result($result);

      return $out;
   }//count_registered_tournament_participants

   /*!
    * \brief Returns non-null array with count of TournamentParticipants for all start-rounds and TP-stati.
    * \return array( TPCOUNT_STATUS_ALL => sum-count for all rounds,
    *                TP.StartRound      => array( TP_STATUS_... => count, ... ))
    */
   public static function count_all_tournament_participants( $tid )
   {
      $result = db_query( "TournamentParticipant:count_all_TPs($tid)",
            "SELECT SQL_SMALL_RESULT Status, StartRound, COUNT(*) AS X_Count FROM TournamentParticipant " .
            "WHERE tid=$tid GROUP BY Status, StartRound" );

      $out = array();
      while ( $row = mysql_fetch_array($result) )
      {
         $status = @$row['Status'];
         $round = (int)@$row['StartRound'];
         $cnt = (int)@$row['X_Count'];
         if ( !isset($out[$round]) )
            $out[$round] = array();
         $out[$round][$status] = $cnt;
      }
      mysql_free_result($result);

      return $out;
   }//count_all_tournament_participants


   /*! \brief Returns db-fields to be used for query of TournamentParticipant-object. */
   public static function build_query_sql()
   {
      $qsql = $GLOBALS['ENTITY_TOURNAMENT_PARTICIPANT']->newQuerySQL('TP');
      $qsql->add_part( SQLP_FIELDS,
         'TPP.ID AS TPP_ID',
         'TPP.Name AS TPP_Name',
         'TPP.Handle AS TPP_Handle',
         'TPP.Country AS TPP_Country',
         'TPP.Rating2 AS TPP_Rating2',
         'TPP.RatingStatus AS TPP_RatingStatus',
         'TPP.RatedGames AS TPP_RatedGames',
         'TPP.Finished AS TPP_Finished',
         'UNIX_TIMESTAMP(TPP.Lastaccess) AS TPP_X_Lastaccess' );
      $qsql->add_part( SQLP_FROM,
         'INNER JOIN Players AS TPP ON TPP.ID=TP.uid' );
      return $qsql;
   }

   /*! \brief Returns TournamentParticipant-object created from specified (db-)row. */
   public static function new_from_row( array $row )
   {
      $tp = new TournamentParticipant(
            // from TournamentParticipant
            @$row['ID'],
            @$row['tid'],
            @$row['uid'],
            User::new_from_row( $row, 'TPP_' ), // from Players TPP
            @$row['Status'],
            @$row['Flags'],
            @$row['Rating'],
            @$row['StartRound'],
            @$row['NextRound'],
            @$row['X_Created'],
            @$row['X_Lastchanged'],
            @$row['ChangedBy'],
            @$row['Comment'],
            @$row['DirectorMessage'],
            @$row['Finished'],
            @$row['Won'],
            @$row['Lost'],
            @$row['PenaltyPoints'],
            @$row['X_Lastmoved']
         );
      return $tp;
   }

   /*!
    * \brief Checks, if user is participating for given tournament.
    * \return TournamentParticipant.Status if entry found; false otherwise
    */
   public static function isTournamentParticipant( $tid, $uid )
   {
      $tid = (int)$tid;
      $uid = (int)$uid;
      $row = mysql_single_fetch( "TournamentParticipant:isTournamentParticipant($tid,$uid)",
         "SELECT Status FROM TournamentParticipant WHERE tid=$tid AND uid=$uid LIMIT 1" );
      return ($row) ? @$row['Status'] : false;
   }

   /*!
    * \brief Loads and returns TournamentParticipant-object for given registration-id ($rid, which is PK).
    * \param $uid 0 to skip assertion on uid, e.g. for deletion
    * \return TournamentParticipant-object; or null if TP not found
    */
   public static function load_tournament_participant_by_id( $rid, $tid, $uid )
   {
      $rid = (int)$rid;

      $result = NULL;
      if ( $rid > 0 )
      {
         $qsql = self::build_query_sql();
         $qsql->add_part( SQLP_WHERE, "TP.ID=$rid" ); // primary-key
         $qsql->add_part( SQLP_LIMIT, '1' );

         $row = mysql_single_fetch( "TournamentParticipant:load_tournament_participant_by_id($rid)",
            $qsql->get_select() );
         if ( $row )
         {
            $result = self::new_from_row( $row );
            $result->assert_tournament_participant("TournamentParticipant:load_tournament_participant_by_id($rid)", $tid, $uid);
         }
      }
      return $result;
   }//load_tournament_participant_by_id

   /*!
    * \brief Loads and returns TournamentParticipant-object for given tournament-ID and user-id.
    * \return TournamentParticipant-object; NULL if no entry found.
    */
   public static function load_tournament_participant( $tid, $uid )
   {
      $tid = (int)$tid;
      $uid = (int)$uid;

      $result = NULL;
      if ( $tid > 0 && $uid > GUESTS_ID_MAX )
      {
         $qsql = self::build_query_sql();
         $qsql->add_part( SQLP_WHERE, "TP.tid=$tid", "TP.uid=$uid" );
         $qsql->add_part( SQLP_LIMIT, '1' );

         $row = mysql_single_fetch( "TournamentParticipant:load_tournament_participant($tid,$uid)",
            $qsql->get_select() );
         if ( $row )
            $result = self::new_from_row( $row );
      }
      return $result;
   }//load_tournament_participant

   /*! \brief Returns enhanced (passed) ListIterator with TournamentParticipant-objects of given tournament. */
   public static function load_tournament_participants( ListIterator $iterator, $tid )
   {
      $qsql = self::build_query_sql();
      $qsql->add_part( SQLP_WHERE, "TP.tid='$tid'" );
      $iterator->setQuerySQL( $qsql );
      $query = $iterator->buildQuery();
      $result = db_query( "TournamentParticipant:load_tournament_participants($tid)", $query );
      $iterator->setResultRows( mysql_num_rows($result) );

      $iterator->clearItems();
      while ( $row = mysql_fetch_array( $result ) )
      {
         $tourney = self::new_from_row( $row );
         $iterator->addItem( $tourney, $row );
      }
      mysql_free_result($result);

      return $iterator;
   }//load_tournament_participants

   /*! \brief Returns array( ID=>uid ) with TournamentParticipant.ID for given tournament and round. */
   public static function load_tournament_participants_registered( $tid, $round )
   {
      $query = "SELECT ID, uid FROM TournamentParticipant " .
         "WHERE tid=$tid AND Status='".TP_STATUS_REGISTER."' AND NextRound=$round";
      $result = db_query( "TournamentParticipant:load_tournament_participants_registered($tid,$round)", $query );

      $arr = array();
      while ( $row = mysql_fetch_array( $result ) )
         $arr[$row['ID']] = $row['uid'];
      mysql_free_result($result);
      return $arr;
   }//load_tournament_participants_registered

   /*!
    * \brief Returns array of row-arrays with [ rid=> TP.ID, uid => TP.uid ]
    *        for given tournament and round ordered according to given tourney-seed-order.
    */
   public static function load_registered_users_in_seedorder( $tid, $round, $seed_order )
   {
      // find all registered TPs (optimized)
      $qsql = new QuerySQL(
         SQLP_FIELDS,
            'TP.ID AS rid', 'TP.uid',
         SQLP_FROM,
            'TournamentParticipant AS TP',
         SQLP_WHERE,
            "TP.tid=$tid",
            "TP.Status='".TP_STATUS_REGISTER."'",
            "TP.NextRound=$round"
         );

      if ( $seed_order == TOURNEY_SEEDORDER_CURRENT_RATING )
      {
         $qsql->add_part( SQLP_FROM,  'INNER JOIN Players AS TPP ON TPP.ID=TP.uid' );
         $qsql->add_part( SQLP_ORDER, 'TPP.Rating2 DESC' );
      }
      elseif ( $seed_order == TOURNEY_SEEDORDER_REGISTER_TIME )
         $qsql->add_part( SQLP_ORDER, 'TP.Created ASC' );
      elseif ( $seed_order == TOURNEY_SEEDORDER_TOURNEY_RATING )
         $qsql->add_part( SQLP_ORDER, 'TP.Rating DESC' );

      // load all registered TPs (optimized = no TournamentParticipant-objects)
      $result = db_query( "TournamentParticipant:load_registered_users_in_seedorder.find_TPs($tid,$seed_order)",
         $qsql->get_select() );
      $arr_TPs = array();
      while ( $row = mysql_fetch_array($result) )
         $arr_TPs[] = $row;
      mysql_free_result($result);

      if ( $seed_order == TOURNEY_SEEDORDER_RANDOM )
         shuffle( $arr_TPs );

      return $arr_TPs;
   }//load_registered_users_in_seedorder

   /*! \brief Returns false, if there is at least one TP, that does not have a user-rating. */
   public static function check_rated_tournament_participants( $tid )
   {
      $row = mysql_single_fetch( "TournamentParticipant:check_rated_tournament_participants.exist_tp($tid)",
         "SELECT COUNT(*) AS X_Count FROM TournamentParticipant WHERE tid=$tid" );
      if ( (int)@$row['X_Count'] == 0 )
         return true;

      $row = mysql_single_fetch( "TournamentParticipant:check_rated_tournament_participants.find_unrated($tid)",
         "SELECT TP.uid FROM TournamentParticipant AS TP INNER JOIN Players AS P ON P.ID=TP.uid " .
         "WHERE TP.tid=$tid AND P.RatingStatus='".RATING_NONE."' LIMIT 1" );
      return !$row;
   }

   /*!
    * \brief Updates TournamentParticipant.Finished/Won/Lost-fields for given rid (=TP.ID).
    * \param $uid PK is $rid, but $uid is required for deleting TP-cache
    * \param $score relative score for user: <0 = game won, >0 = game lost for given user
    */
   public static function update_game_end_stats( $tid, $rid, $uid, $score )
   {
      $data = $GLOBALS['ENTITY_TOURNAMENT_PARTICIPANT']->newEntityData();
      $data->set_value( 'ID', $rid );
      $data->set_value( 'tid', $tid );
      $data->set_value( 'Lastchanged', $GLOBALS['NOW'] );
      $data->set_query_value( 'Finished', "Finished+1" );

      // NOTE: jigo is not counted as Win, because count can be calculated: Jigo = Finished - Won - Lost,
      //       though that includes NO-RESULT-games
      if ( $score < 0 )
         $data->set_query_value( 'Won', "Won+1" );
      if ( $score > 0 )
         $data->set_query_value( 'Lost', "Lost+1" );

      $result = $data->update( "TournamentParticipant:update_game_end_stats($tid,$rid,$score)" );
      self::delete_cache_tournament_participant( 'TournamentParticipant:update_game_end_stats', $tid, $uid );
      return $result;
   }//update_game_end_stats

   /*!
    * \brief Updates bitmask $flag in TP.Flags for given tournament and user-id.
    * \param $flag bitmask-value to set or clear
    * \param $flag_op true|>0 = set flag, false|0 = clear flag, <0 = toggle flag
    * \param $penalty_add 0 = no change, otherwise add int-value to TP.PenaltyPoints;
    *       if PP<0 and $penalty_add>0 reset TP.PenaltyPoints to $penalty_add
    */
   public static function update_participant_flags_with_penalty( $tid, $uid, $flag, $flag_op, $penalty_add=0 )
   {
      $dbgmsg = "TournamentParticipant:update_participant_flags_with_penalty";
      if ( !is_numeric($flag) || $flag <= 0 )
         error('invalid_args', "$dbgmsg.check.bad_flag($tid,$uid,$flag,$flag_op,$penalty_add)");
      $tid = (int)$tid;
      $uid = (int)$uid;
      $penalty_add = (int)$penalty_add;

      $qval_flag = ( is_numeric($flag_op) && $flag_op < 0 )
         ? "^ $flag"
         : ( $flag_op ? "| $flag" : "& ~$flag" );
      $result = db_query( "$dbgmsg.upd($tid,$uid,$flag,$flag_op,$penalty_add)",
         "UPDATE TournamentParticipant " .
         "SET Flags=Flags $qval_flag, " .
            "PenaltyPoints=IF($penalty_add>0 AND PenaltyPoints<0,0,PenaltyPoints) + ($penalty_add) " .
         "WHERE tid=$tid AND uid=$uid LIMIT 1" );

      self::delete_cache_tournament_participant( $dbgmsg, $tid, $uid );
      return $result;
   }//update_participant_flags_with_penalty

   /*! \brief Updates Tournament.RegisteredTP if needed by comparing old/new TP-status. */
   public static function sync_tournament_registeredTP( $tid, $old_tp_status, $new_tp_status )
   {
      if ( $old_tp_status != TP_STATUS_REGISTER && $new_tp_status == TP_STATUS_REGISTER )
         Tournament::update_tournament_registeredTP( $tid, 1 );
      elseif ( $old_tp_status == TP_STATUS_REGISTER && $new_tp_status != TP_STATUS_REGISTER )
         Tournament::update_tournament_registeredTP( $tid, -1 );
   }

   /*!
    * \brief Deletes TournamentParticipant-entry for given tournament- and reg-id.
    * \note Updates Tournament.RegisteredTP if TP was REGISTERed. See also sync_tournament_registeredTP()
    *
    * \note IMPORTANT NOTE: caller needs to open TA with HOT-section!!
    */
   public static function delete_tournament_participant( $tid, $rid )
   {
      $tp = self::load_tournament_participant_by_id( $rid, $tid, 0 );
      if ( is_null($tp) )
         $result = true; // already deleted
      else
      {
         $result = $tp->delete();
         if ( $tp->Status == TP_STATUS_REGISTER )
            Tournament::update_tournament_registeredTP( $tid, -1 );
      }
      return $result;
   }//delete_tournament_participant

   /*! \brief Returns status-text or all status-texts (if arg=null). */
   public static function getStatusText( $status=null, $with_value=false, $info_mode=false )
   {
      // lazy-init of texts
      if ( !isset(self::$ARR_TP_TEXTS['STATUS']) )
      {
         $arr = array();
         $arr[TP_STATUS_APPLY]    = T_('Applied#TP_status');
         $arr[TP_STATUS_REGISTER] = T_('Registered#TP_status');
         $arr[TP_STATUS_INVITE]   = T_('Invited#TP_status');
         self::$ARR_TP_TEXTS['STATUS'] = $arr;

         $arr = array();
         $arr['']                 = T_('You are not registered for this tournament.');
         $arr[TP_STATUS_APPLY]    = T_('Your registration needs to be verified by a tournament director.');
         $arr[TP_STATUS_REGISTER] = T_('You are registered for this tournament.');
         $arr[TP_STATUS_INVITE]   = T_('The invitation for this tournament needs your verification.');
         self::$ARR_TP_TEXTS['STATUS_INFO'] = $arr;
      }

      if ( $info_mode )
      {
         $key = 'STATUS_INFO';
         if ( !$status ) $status = '';
         if ( !isset(self::$ARR_TP_TEXTS[$key][$status]) )
            error('invalid_args', "TournamentParticipant:getStatusText($status,$key)");

         $status_str = self::$ARR_TP_TEXTS[$key][$status];
         return $status_str;
      }
      else
      {
         $key = 'STATUS';
         if ( is_null($status) )
            return self::$ARR_TP_TEXTS[$key];

         if ( !isset(self::$ARR_TP_TEXTS[$key][$status]) )
            error('invalid_args', "TournamentParticipant:getStatusText($status,$key)");
         $status_str = self::$ARR_TP_TEXTS[$key][$status];
         return ( $with_value ) ? sprintf( '%s (%s)', $status, $status_str ) : $status_str;
      }
   }//getStatusText

   public static function getStatusUserInfo( $status )
   {
      return self::getStatusText($status, false, true);
   }

   /*! \brief Returns flags-text for given int-bitmask or all flags-texts (if arg=null). */
   public static function getFlagsText( $flags=null )
   {
      // lazy-init of texts
      if ( !isset(self::$ARR_TP_TEXTS['FLAGS']) )
      {
         $arr = array();
         $arr[TP_FLAG_INVITED]     = T_('Invited#TP_flag');
         $arr[TP_FLAG_ACK_INVITE]  = T_('ACK-Invite#TP_flag');
         $arr[TP_FLAG_ACK_APPLY]   = T_('ACK-Apply#TP_flag');
         $arr[TP_FLAG_VIOLATE]     = T_('REG-Violate#TP_flag');
         $arr[TP_FLAG_TIMEOUT_LOSS] = T_('Timeout-Loss#TP_flag');
         self::$ARR_TP_TEXTS['FLAGS'] = $arr;
      }
      else
         $arr = self::$ARR_TP_TEXTS['FLAGS'];
      if ( is_null($flags) )
         return $arr;

      $out = array();
      foreach ( $arr as $flagmask => $flagtext )
         if ( $flags & $flagmask ) $out[] = $flagtext;
      return implode(', ', $out);
   }//getFlagsText

   public static function get_edit_tournament_status()
   {
      static $statuslist = array(
         TOURNEY_STATUS_REGISTER, TOURNEY_STATUS_PLAY
      );
      return $statuslist;
   }

   public static function delete_cache_tournament_participant_counts( $dbgmsg, $tid )
   {
      DgsCache::delete( $dbgmsg, CACHE_GRP_TP_COUNT_ALL, "TPCountAll.$tid" );
      DgsCache::delete_group( $dbgmsg, CACHE_GRP_TP_COUNT, "TPCount.$tid" );
   }

   public static function delete_cache_tournament_participant( $dbgmsg, $tid, $uid )
   {
      DgsCache::delete( $dbgmsg, CACHE_GRP_TPARTICIPANT, "TParticipant.$tid.$uid" );
   }

} // end of 'TournamentParticipant'

?>
//


koh5_pano



Your browser does not support the HTML5 canvas element.


Drag mouse to navigate.

Navigation





17.Aug.2010, Martin Wengenmayer