/**
     * @param int $quizId
     * @param int $applicationId
     * @return array
     */
    static function getQuizData( $quizId, $applicationId, $isLocalQuiz = true )
    {
        $quizData = self::fetchOneBy( array( 'quiz_id' => $quizId, 'application_id' => $applicationId ) );
        if( !$quizData )
        {
            // We don't have the quiz meta for the requested quiz, we try to create it (happens only once)
            $object =& eZContentObject::fetch( $quizId );
            if( !$object )
                return null;
            /* @type $dm eZContentObjectAttribute[] */
            $dm = $object->DataMap();
            $mc = $dm['media_content']->content();
            if( isset( $mc['relation_list'][0]['node_id'] ) )
            {
                $quiz =& eZContentObjectTreeNode::fetch( $mc['relation_list'][0]['node_id'] );
                /* @type $quizDM eZContentObjectAttribute[] */
                $quizDM = $quiz->DataMap();
                self::add( $quizId, ClusterTool::clusterIdentifier(), $applicationId, (int)$quizDM['points']->content(), (int)$quizDM['correct_reply']->content() );
                $quizData = self::fetchOneBy( array( 'quiz_id' => $quizId, 'application_id' => $applicationId ) );
            } else {
                return null;
            }
        }
        $currentMMUser = MMUsers::getCurrentUserObject();
        $currentUserResponse = false;
        $nbCorrect     = (int)$quizData->attribute( 'nb_correct' );
        $nbWrong       = (int)$quizData->attribute( 'nb_wrong' );
        if ( $currentMMUser )
        {
            $responseFetchParams = array(
                'quiz_id' => $quizId,
                'uuid' => $currentMMUser->attribute( 'uuid' ),
                'application_id' => $applicationId
            );
            if (!$isLocalQuiz)
            {
                $responseFetchParams['cluster_identifier'] = null;
            }
            $currentUserResponse = QuizReply::fetchOneBy( $responseFetchParams );
        }

        if( $currentUserResponse )
        {
            $currentUserResponded = true;
            $answerWasCorrect = (bool)$currentUserResponse->attribute( 'is_correct' );
        }
        else
        {
            $currentUserResponded = false;
            $answerWasCorrect = false;
        }
        $speRepliesResult = array( 'total' => 0, 'correct' => 0, 'wrong' => 0 );
        $userSpecialtyTranslations = FacetFilteringTool::getTaxoTranslationWithIDs( 'user_specialty' );
        if ( $currentMMUser )
        {
            $userSpecialtyId = $userSpecialtyTranslations[$currentMMUser->attribute( 'user_speciality' )]['id'];
            $speReplies = QuizReply::fetchBySpecialtyInScoring( $currentMMUser->attribute( 'uuid' ), $quizId, $applicationId, $userSpecialtyId );
            if( $speReplies )
            {
                $speRepliesResult['total'] = count( $speReplies );
                foreach( $speReplies as $reply )
                {
                    if( $reply['is_correct'] == 1 )
                        $speRepliesResult['correct']++;
                    else
                        $speRepliesResult['wrong']++;
                }
            }
        }
        $response = array(
            'points'                 => (int)$quizData->attribute( 'points' ),
            'correct_answer'         => (int)$quizData->attribute( 'correct_answer' ),
            'global_answers'         => array( 'total' => ( $nbCorrect + $nbWrong ), 'correct' => $nbCorrect, 'wrong' => $nbWrong ),
            'specialty_answers'      => $speRepliesResult,
            'current_user_responded' => $currentUserResponded,
            'answer_was_correct'     => $answerWasCorrect
        );
        if( $currentUserResponded )
        {
            /* @type $quizArticleDM eZContentObjectAttribute[] */
            $quizArticleDM   = eZContentObject::fetch( $quizId )->DataMap();
            $mediaContent    = $quizArticleDM["media_content"]->content();
            $quizDM          = eZContentObjectTreeNode::fetch( $mediaContent['relation_list'][0]['node_id'] )->DataMap();
            $outputHandler   = new eZXHTMLXMLOutput( $quizDM['commented_answer']->DataText, false );
            $commentedAnswer = $outputHandler->outputText();
            $response['commented_answer'] = $commentedAnswer;
        }
        return $response;
    }
    /**
     * @param string $newGameName
     * @param int $applicationId
     * @return array
     */
    static function createNewPlayer( $newGameName, $applicationId, $isLocalQuiz = true )
    {
        $currentMMUser = MMUsers::getCurrentUserObject();
        if( $currentMMUser )
        {
            $clusterIdentifier = ($isLocalQuiz) ? ClusterTool::clusterIdentifier() : '';
            $newPlayer = new QuizPlayerScoring();

            // Setting up the global ranking of the new player
            $lowestGlobalScore = self::fetchBy( array( 'application_id' => $applicationId, 'cluster_identifier' => $clusterIdentifier ), array( 'global_ranking' => 'desc' ), array( 'length' => 1 ) );
            if( $lowestGlobalScore )
                $lgs = $lowestGlobalScore[0]->attribute( 'score' ) == 0 ? $lowestGlobalScore[0]->attribute( 'global_ranking' ) : ( $lowestGlobalScore[0]->attribute( 'global_ranking' ) + 1 );
            else
                $lgs = 1;

            // Setting up the specialty ranking of the new player
            $userSpecialtyTranslations = FacetFilteringTool::getTaxoTranslationWithIDs( 'user_specialty' );
            $userSpecialtyTaxonomyId   = $userSpecialtyTranslations[$currentMMUser->attribute( 'user_speciality' )]['id'];
            $lowestSpecialtyScore      = self::fetchBy( array( 'application_id' => $applicationId, 'user_specialty' => $userSpecialtyTaxonomyId ), array( 'specialty_ranking' => 'desc' ), array( 'length' => 1 ) );
            if( $lowestSpecialtyScore )
                $lss = $lowestSpecialtyScore[0]->attribute( 'score' ) == 0 ? $lowestSpecialtyScore[0]->attribute( 'specialty_ranking' ) : ( $lowestSpecialtyScore[0]->attribute( 'specialty_ranking' ) + 1 );
            else
                $lss = 1;

            $newPlayer->setAttribute( 'game_name', $newGameName );
            $newPlayer->setAttribute( 'uuid', $currentMMUser->attribute( 'uuid' ) );
            $newPlayer->setAttribute( 'cluster_identifier', $clusterIdentifier);
            $newPlayer->setAttribute( 'application_id', $applicationId );
            $newPlayer->setAttribute( 'score', 0 );
            $newPlayer->setAttribute( 'user_specialty', Taxonomy::fetchObject( Taxonomy::definition(), null, array( 'code' => $currentMMUser->attribute( 'user_speciality' ) ), true)->attribute( 'id' ) );
            $newPlayer->setAttribute( 'nb_correct', 0 );
            $newPlayer->setAttribute( 'nb_wrong', 0 );
            $newPlayer->setAttribute( 'global_ranking', $lgs );
            $newPlayer->setAttribute( 'specialty_ranking', $lss );
            $newPlayer->setAttribute( 'user_cluster', ClusterTool::clusterIdentifier() );
            $newPlayer->store();

            return array( 'lgs' => $lgs, 'lss' => $lss );
        }
        return null;
    }
    public function getHallOfFame($season)
    {
        $tpl = $this->tpl();
        $db         = eZDB::instance();
        $ust        = array();
        $playerData = null;
        $totalPlayers = 0;
        $lowestGlobalRanking         = 0;
        $uuidsInGlobalLeaderboard = array();
        $_globalLeaderboard          = array(
            1 => array(),
            2 => array(),
            3 => array(),
        );

        $userSpecialtyTranslations = FacetFilteringTool::getTaxoTranslationWithIDs( 'user_specialty' );
        foreach( $userSpecialtyTranslations as $translation )
            $ust[$translation['id']] = $translation['label'];
        $userSpecialtyTaxonomyId = $userSpecialtyTranslations[$this->user()->attribute( 'user_speciality' )]['id'];
        $clusterIdentifier = ($this->isLocalQuiz()) ? ClusterTool::clusterIdentifier() : '';
        $results = array();
        for ($i = 1; $i <= 3; $i++)
        {
            $chunks = $db->arrayQuery( sprintf("
                    SELECT
                        COUNT(id) as total, uuid, user_specialty, game_name, global_ranking, specialty_ranking, score, nb_correct, nb_wrong
                    FROM
                        %s
                    WHERE
                        cluster_identifier = '%s'
                        AND application_id = %d
                        AND global_ranking = %d
                        AND season = %d
                    GROUP BY
                        uuid
                    ORDER BY
                        global_ranking ASC,
                        uuid = '%s' DESC
                    LIMIT
                        5",
                QuizHallOfFame::SQL_TABLENAME,
                $db->escapeString( $clusterIdentifier ),
                $this->applicationObject->attribute( 'id' ),
                $i,
                $season,
                $this->user()->attribute('uuid')
            ));
            $results = array_merge($results, $chunks);
        }

        if( $results )
        {

            foreach( $results as $row )
            {
                if( $row['nb_correct'] == 0 && $row['nb_wrong'] == 0 )
                    continue;
                if( $row['global_ranking'] <= 10 && !in_array( $row['uuid'], $uuidsInGlobalLeaderboard ) && count( $uuidsInGlobalLeaderboard ) < 10 )
                {
                    $_globalLeaderboard[$row['global_ranking']][] = array(
                        'game_name'       => is_null( $row['game_name'] ) || $row['game_name'] == '' ? ezpI18n::tr( 'merck/quiz', 'ANONYMOUS' ) : $row['game_name'],
                        'specialty_label' => $ust[$row['user_specialty']],
                        'ranking'         => $row['global_ranking'],
                        'uuid'            => $row['uuid'],
                        'score'           => $row['score']
                    );
                    $uuidsInGlobalLeaderboard[] = $row['uuid'];
                }
                if( $row['uuid'] == $this->user()->attribute( 'uuid' ) && is_null( $playerData ) )
                {
                    $playerData = $row;
                }
            }
            if( !in_array( $this->user()->attribute( 'uuid' ), $uuidsInGlobalLeaderboard ) )
            {
                if( is_null( $playerData ) )
                {
                    $playerData = QuizHallOfFame::fetchUserInSeason( $this->applicationObject->attribute( 'id' ), $season, false, $this->isLocalQuiz() );
                }
                if( $playerData && ( $playerData['nb_correct'] == 0 && $playerData['nb_wrong'] == 0 ) )
                {
                    $playerData = null;
                }
            }
            $playersCount = $db->arrayQuery( sprintf("
                    SELECT
                        COUNT(*) as total,
                        user_specialty,
                        MAX(global_ranking) as lowest_global_ranking,
                        MAX(specialty_ranking) as lowest_specialty_ranking
                    FROM
                        %s
                    WHERE
                        cluster_identifier = '%s'
                        AND application_id = %d
                        AND ( nb_correct > 0 OR nb_wrong > 0 )
                        AND season = %d
                    GROUP BY
                        (user_specialty)",
                QuizHallOfFame::SQL_TABLENAME,
                $db->escapeString( $clusterIdentifier ),
                $this->applicationObject->attribute( 'id' ),
                $season
            ) );

            foreach( $playersCount as $row )
            {
                $totalPlayers += $row['total'];
                if( $row['user_specialty'] == $userSpecialtyTaxonomyId )
                {
                    $totalSpecialtyPlayers  = $row['total'];
                    $lowestSpecialtyRanking = $row['lowest_specialty_ranking'];
                }
                if( $row['lowest_global_ranking'] > $lowestGlobalRanking )
                    $lowestGlobalRanking = $row['lowest_global_ranking'];
            }
        }
        $tpl->setVariable( 'global_leaderboard', $_globalLeaderboard );
        $tpl->setVariable( 'current_player_uuid', $this->user()->attribute('uuid') );

        $response = array(
            'player_position' => ($playerData) ? $playerData['global_ranking'] : 0,
            'hall_of_fame'    => $tpl->fetch( 'design:esibuild/app_content/train-the-brain/hall_of_fame.tpl' ),
            'total_players'   => $totalPlayers,
        );

        return $response;
    }
    'clusterIdentifier' => 'Cluster identifier',
    'countryCode'       => 'Country code'
) );

$script->startup();
$script->initialize();

if( $options['clusterIdentifier'] && $options['countryCode'] )
{
    $updated = 0;
    $lowestRankingsPerQuizApp = array();
    $playerScoringRows = QuizPlayerScoring::fetchBy( array( 'cluster_identifier' => array( array( $options['clusterIdentifier'] ) ) ) );
    if( $playerScoringRows )
    {
        ClusterTool::setCurrentCluster( $options['clusterIdentifier'] );
        $us = FacetFilteringTool::getTaxoTranslationWithIDs( 'user_specialty' );
        foreach( $playerScoringRows as $playerScoring )
        {
            $user = MMUsers::fetchByIdAndCountry( $playerScoring->attribute( 'uuid' ), $options['countryCode'] );
            if( $user )
            {
                if( isset( $us[$user->attribute( 'user_speciality' )] ) && $us[$user->attribute( 'user_speciality' )]['id'] != $playerScoring->attribute( 'user_specialty' ) )
                {
                    if( !isset( $lowestRankingsPerQuizApp[$playerScoring->attribute( 'application_id' )] ) || ( isset( $lowestRankingsPerQuizApp[$playerScoring->attribute( 'application_id' )] ) && $lowestRankingsPerQuizApp[$playerScoring->attribute( 'application_id' )] < (int)$playerScoring->attribute( 'global_ranking' ) ) )
                        $lowestRankingsPerQuizApp[$playerScoring->attribute( 'application_id' )] = (int)$playerScoring->attribute( 'global_ranking' );
                    $oldUS = $playerScoring->attribute( 'user_specialty' );
                    $playerScoring->setAttribute( 'user_specialty', $us[$user->attribute( 'user_speciality' )]['id'] );
                    $playerScoring->store();
                    $updated++;
                    $cli->output( "Updated user speciality (" . $oldUS . " -> " . $us[$user->attribute( 'user_speciality' )]['id'] . ") in scoring data for user " . $playerScoring->attribute( 'uuid' ) );
                }
    /**
     * @param array $uncrytedTicket
     * @return MMUsers
     */
    public static function createOrUpdateMMUser( $uncrytedTicket )
    {
        $userId = $uncrytedTicket['uuid'];
        $customerType = $uncrytedTicket['customerType'];
        if ( isset($uncrytedTicket['userSpeciality']) )
        {
            $userSpeciality = $uncrytedTicket['userSpeciality'];
        }
        else
        {
            $userSpeciality = $uncrytedTicket['mainSpeciality'];
        }
        $state = $uncrytedTicket['state'];
        $country = eZIni::instance('site.ini')->variable('RegionalSettings','CountryOfRegistration');
        $language = $uncrytedTicket['language'];
        /**
         * @todo: check $language entry format and parse it if needed to get an iso code on 2 chars
         */
        $iniMapping = eZINI::instance('mercktaxonomymapping.ini');
        $taxonomyType = $iniMapping->variable( 'Taxonomy', 'SpecialtiesTaxonomyType');

        $specialtiesMappingINI = $iniMapping->variable( 'Taxonomy', 'Specialties' );
        $customerTypesMappingINI = $iniMapping->variable( 'Taxonomy', 'CustomerTypes' );

        if($taxonomyType != "transitive")
        {
            if ( isset( $customerTypesMappingINI[$customerType] ) )
            {
                $customerType = $customerTypesMappingINI[$customerType];
            }
            else
            {
                $customerType = $customerTypesMappingINI['Default'];
                self::updateDBWithEmptyValue( 'empty-CT', $userId, $country );
            }

            if ( isset( $specialtiesMappingINI[$userSpeciality] ) )
            {
                $userSpeciality = $specialtiesMappingINI[$userSpeciality];
            }
            else
            {
                $userSpeciality = $specialtiesMappingINI['Default'];
                self::updateDBWithEmptyValue( 'empty-SPE', $userId, $country );
            }
        }
        else
        {
            $customerTypesMapping = SolrSafeOperatorHelper::getCustomerTypes();
            if ( !isset( $customerTypesMapping["$customerType"] ) )
            {
                // fill with default value
                $customerType = $customerTypesMappingINI['Default'];
                self::updateDBWithEmptyValue( 'empty-CT', $userId, $country );
            }

            $specialtiesMapping = SolrSafeOperatorHelper::getUserSpecialities();
            if ( !isset( $specialtiesMapping[(string)$userSpeciality] ) )
            {
                // fill with default value
                $userSpeciality = $specialtiesMappingINI['Default'];
                self::updateDBWithEmptyValue( 'empty-SPE', $userId, $country );
            }
        }

        /** @var MMUsers $user */
        $user = MMUsers::fetchByIdAndCountry( $userId, $country );
        $isModifiedUser = false;

        if ( $user )
        {
            if ( $customerType != $user->attribute('customer_type') )
            {
                $user->setAttribute('customer_type', $customerType);
                $isModifiedUser = true;
            }
            if ( $userSpeciality !== $user->attribute('user_speciality') )
            {
                $mainSpeciality = UserSpecialityContentSpeciality::getContentSpeciality ( $userSpeciality );
                $defaultAdditionalSpecialities = MMUserLogin::getAddSpecialties($mainSpeciality);

                $user->setAttribute('user_speciality', $userSpeciality);

                // mapping main_spe additional spe
                $preferences = $user->getPreferences();
                $userAditionalSpecialities = $preferences['specialities'];
                array_shift($userAditionalSpecialities);
                $tmp = array_diff( $userAditionalSpecialities, $defaultAdditionalSpecialities );
                if( empty( $tmp ) )    // we don't modify the user spes if he has changed his selection
                {
                    $preferences["specialities"] = MMUserLogin::getAddSpecialties($mainSpeciality);
                    $user->setPreferences($preferences);
                }
                $user->setPreferences($preferences);

                // The user specialty has been modified, we need to update it for Quiz-type applications of the current cluster
                if( CacheApplicationTool::buildLocalizedApplicationByIdentifier('train-the-brain') instanceof ApplicationLocalized)
                {
                    $playerScoring = QuizPlayerScoring::fetchOneBy( array( 'application_id' => (int)$app->applicationObject->id, 'uuid' => $user->attribute( 'uuid' ) ) );
                    // Checking if the current user has scored at least once for the application
                    if( $playerScoring )
                    {
                        foreach( FacetFilteringTool::getTaxoTranslationWithIDs( 'user_specialty' ) as $k => $t )
                        {
                            if( ($k . "") === ($userSpeciality . "") )
                            {
                                // Updating the user specialty id in the player scoring table
                                $playerScoring->setAttribute( 'user_specialty', $t['id'] );
                                $playerScoring->store();
                            }
                        }
                        // Scheduling a ranking update
                        QuizPendingRankingUpdate::add( $playerScoring->attribute( 'global_ranking' ), $app->applicationObject->id );
                    }
                }

                $isModifiedUser = true;
            }

            if ( $country != $user->attribute('country') )
            {
                $user->setAttribute('country', $country);
                $isModifiedUser = true;
            }

            if( $language != $user->attribute( 'language' ) )
            {
                $user->setAttribute('language', $language );
                $isModifiedUser = true;
            }

            if ( $state != $user->attribute('state') )
            {
                $user->setAttribute('state', $state);
                $isModifiedUser = true;
            }

            if ( $isModifiedUser )
            {
                $user->setAttribute('date_update', time());
                $user->store();
            }

            // set gpnotebook hand shake data in preferences
            if($user->getGPNotebookHS())
            {
                SolrSafeOperatorHelper::getAndStoreGPNotebookHS();
            }
        }
        else
        {
            $mainSpeciality = UserSpecialityContentSpeciality::getContentSpeciality ( $userSpeciality );
            $insertedArray = array (
                'uuid' => $userId,
                'customer_type' => $customerType,
                'user_speciality' => $userSpeciality,
                'country' => $country,
                'language' => $language,
                'date_update' => time(),
                'state' => $state,
            );

            $user = new MMUsers ($insertedArray);
            $user->store();

            // mapping main_spe additional spe
            $preferences = $user->getPreferences();
            $preferences["specialities"] = MMUserLogin::getAddSpecialties($mainSpeciality);
            $user->setPreferences($preferences);

            $isModifiedUser = true;
        }

        if ( $isModifiedUser )
        {
            // Tag Lyris user to be reimported :
            $user->tagLyrisToProcess();
        }

        return $user;
    }