<commit_before><?php

/**
 *    Copyright 2015-2017 ppy Pty. Ltd.
 *
 *    This file is part of osu!web. osu!web is distributed with the hope of
 *    attracting more community contributions to the core ecosystem of osu!.
 *
 *    osu!web is free software: you can redistribute it and/or modify
 *    it under the terms of the Affero GNU General Public License version 3
 *    as published by the Free Software Foundation.
 *
 *    osu!web is distributed 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 osu!web.  If not, see <http://www.gnu.org/licenses/>.
 */

namespace App\Http\Controllers;

use App\Models\Beatmap;
use App\Models\Country;
use App\Models\CountryStatistics;
use App\Models\Spotlight;
use App\Models\User;
use App\Models\UserStatistics;
use Illuminate\Pagination\LengthAwarePaginator;
use Redirect;
use Request;

class RankingController extends Controller
{
    protected $section = 'rankings';

    const PAGE_SIZE = 50;
    const MAX_RESULTS = 10000;
    const SPOTLIGHT_MAX_RESULTS = 40;
    const RANKING_TYPES = ['performance', 'monthly', 'charts', 'score', 'country'];
    const SPOTLIGHT_TYPES = ['charts', 'monthly'];

    public function __construct()
    {
        parent::__construct();

        view()->share('currentAction', request('type'));
        view()->share('mode', request('mode'));
        view()->share('type', request('type'));
    }

    public function index($mode = 'osu', $type = null)
    {
        if (!array_key_exists($mode, Beatmap::MODES)) {
            abort(404);
        }

        if ($type === null) {
            return ujs_redirect(route('rankings', ['mode' => $mode, 'type' => 'performance']));
        }

        if (!in_array($type, static::RANKING_TYPES, true)) {
            abort(404);
        }

        $country = null;
        $modeInt = Beatmap::modeInt($mode);

        if ($type === 'country') {
            $maxResults = CountryStatistics::where('display', 1)
                ->where('mode', $modeInt)
                ->count();

            $stats = CountryStatistics::where('display', 1)
                ->with('country')
                ->where('mode', $modeInt)
                ->orderBy('performance', 'desc');
        } elseif ($type === 'charts') {
            return $this->spotlight($mode);
        } elseif ($type === 'monthly') {
            return $this->monthly($mode);
        } else { // if $type == 'performance' || $type == 'score'
            if (Request::has('country')) {
                $countryStats = CountryStatistics::where('display', 1)
                    ->where('country_code', Request::input('country'))
                    ->first();

                if (!$countryStats) {
                    return Redirect::route('rankings', ['mode' => $mode, 'type' => $type]);
                } else {
                    $country = $countryStats->country;
                }
            }

            $maxResults = min(isset($country) ? $country->usercount : static::MAX_RESULTS, static::MAX_RESULTS);

            $stats = UserStatistics\Model::getClass($mode)
                ::on('mysql-readonly')
                ->with(['user', 'user.country'])
                ->whereHas('user', function ($userQuery) {
                    $userQuery->default();
                });

            if ($country) {
                $stats->where('country_acronym', $country['acronym']);
            }

            if ($type === 'performance') {
                $stats->orderBy('rank_score', 'desc');
            } else { // 'score'
                $stats->orderBy('ranked_score', 'desc');
            }
        }

        $maxPages = ceil($maxResults / static::PAGE_SIZE);
        $page = clamp(get_int(Request::input('page')), 1, $maxPages);

        if (is_api_request()) {
            $stats->with(['user.userProfileCustomization']);
        }

        $stats = $stats->limit(static::PAGE_SIZE)
            ->offset(static::PAGE_SIZE * ($page - 1))
            ->get();

        if (is_api_request()) {
            switch ($type) {
                case 'country':
                    return json_collection($stats, 'CountryStatistics', ['country']);
                break;

                case 'performance':
                case 'score':
                    return json_collection($stats, 'UserStatistics', ['user', 'user.cover', 'user.country']);
                    break;
            }
        } else {
            $scores = new LengthAwarePaginator($stats, $maxPages * static::PAGE_SIZE, static::PAGE_SIZE, $page, [
                'path' => route('rankings', ['mode' => $mode, 'type' => $type]),
            ]);

            return view("rankings.{$type}", compact('scores', 'country'));
        }
    }

    public function monthly($mode)
    {
        $country = null;

        list($spotlight, $range) = $this->getSpotlightAndRange();

        $scores = $this->getUserStats($spotlight, $mode)->get();
        $beatmapsets = $spotlight->beatmapsets($mode)->get();

        // should use whatever attribute we're ordering by; for now chart_id is assumed.
        $earliest = Spotlight::monthly()->orderBy('chart_id', 'asc')->first();
        $latest = Spotlight::monthly()->orderBy('chart_id', 'desc')->first();
        $noPager = true;

        return view(
            "rankings.monthly",
            compact('scores', 'country', 'range', 'spotlight', 'beatmapsets', 'earliest', 'latest', 'noPager')
        );
    }

    public function spotlight($mode)
    {
        $country = null;

        $chartId = get_int(request('spotlight'));

        $spotlights = Spotlight::notMonthly()->orderBy('chart_id', 'desc')->get();
        if ($chartId === null) {
            $spotlight = $spotlights->first();
        } else {
            $spotlight = Spotlight::notMonthly()->findOrFail($chartId);
        }

        $selectOptions = [
            'selected' => $this->optionFromSpotlight($spotlight),
            'options' => $spotlights->map(function ($s) {
                return $this->optionFromSpotlight($s);
            }),
        ];

        $scores = $this->getUserStats($spotlight, $mode)->get();
        $beatmapsets = $spotlight->beatmapsets($mode)->get();

        $noPager = true;

        return view(
            "rankings.charts",
            compact('scores', 'country', 'selectOptions', 'spotlight', 'beatmapsets', 'noPager')
        );
    }

    private function getSpotlightAndRange()
    {
        $chartId = get_int(request('spotlight'));
        $before = get_int(request('before'));
        $after = get_int(request('after'));

        if ($chartId !== null) {
            $spotlight = $this->spotlightQueryBase()->findOrFail($chartId);
            $range = $spotlight->getSpotlightsInYearRange()->get();
        } elseif ($before !== null) {
            $range = $this->spotlightQueryBase()->inYearRange($before - 1)->get();
            $spotlight = $range->last();
        } elseif ($after !== null) {
            $range = $this->spotlightQueryBase()->inYearRange($after + 1)->get();
            $spotlight = $range->first();
        } else {
            $spotlight = $this->spotlightQueryBase()->orderBy('chart_id', 'desc')->first();
            $range = $spotlight->getSpotlightsInYearRange()->get();
        }

        return [$spotlight, $range];
    }

    private function getUserStats($spotlight, $mode)<commit_msg>country related stuff can be set separately via middleware.<commit_after><?php

/**
 *    Copyright 2015-2017 ppy Pty. Ltd.
 *
 *    This file is part of osu!web. osu!web is distributed with the hope of
 *    attracting more community contributions to the core ecosystem of osu!.
 *
 *    osu!web is free software: you can redistribute it and/or modify
 *    it under the terms of the Affero GNU General Public License version 3
 *    as published by the Free Software Foundation.
 *
 *    osu!web is distributed 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 osu!web.  If not, see <http://www.gnu.org/licenses/>.
 */

namespace App\Http\Controllers;

use App\Models\Beatmap;
use App\Models\Country;
use App\Models\CountryStatistics;
use App\Models\Spotlight;
use App\Models\User;
use App\Models\UserStatistics;
use Illuminate\Pagination\LengthAwarePaginator;
use Redirect;
use Request;

class RankingController extends Controller
{
    protected $section = 'rankings';

    private $country;

    const PAGE_SIZE = 50;
    const MAX_RESULTS = 10000;
    const SPOTLIGHT_MAX_RESULTS = 40;
    const RANKING_TYPES = ['performance', 'monthly', 'charts', 'score', 'country'];
    const SPOTLIGHT_TYPES = ['charts', 'monthly'];

    public function __construct()
    {
        parent::__construct();

        view()->share('currentAction', request('type'));
        view()->share('mode', request('mode'));
        view()->share('type', request('type'));

        $this->middleware(function ($request, $next) {
            if (Request::has('country')) {
                $countryStats = CountryStatistics::where('display', 1)
                    ->where('country_code', Request::input('country'))
                    ->first();

                if ($countryStats === null) {
                    return Redirect::route('rankings', ['mode' => request('mode'), 'type' => request('type')]);
                }

                $this->country = $countryStats->country;
            }

            view()->share('country', $this->country);

            return $next($request);
        });
    }

    public function index($mode = 'osu', $type = null)
    {
        if (!array_key_exists($mode, Beatmap::MODES)) {
            abort(404);
        }

        if ($type === null) {
            return ujs_redirect(route('rankings', ['mode' => $mode, 'type' => 'performance']));
        }

        if (!in_array($type, static::RANKING_TYPES, true)) {
            abort(404);
        }

        $modeInt = Beatmap::modeInt($mode);

        if ($type === 'country') {
            $maxResults = CountryStatistics::where('display', 1)
                ->where('mode', $modeInt)
                ->count();

            $stats = CountryStatistics::where('display', 1)
                ->with('country')
                ->where('mode', $modeInt)
                ->orderBy('performance', 'desc');
        } elseif ($type === 'charts') {
            return $this->spotlight($mode);
        } elseif ($type === 'monthly') {
            return $this->monthly($mode);
        } else {
            $maxResults = min(
                $this->country !== null ? $this->country->usercount : static::MAX_RESULTS,
                static::MAX_RESULTS
            );

            $stats = UserStatistics\Model::getClass($mode)
                ::on('mysql-readonly')
                ->with(['user', 'user.country'])
                ->whereHas('user', function ($userQuery) {
                    $userQuery->default();
                });

            if ($this->country !== null) {
                $stats->where('country_acronym', $this->country['acronym']);
            }

            if ($type === 'performance') {
                $stats->orderBy('rank_score', 'desc');
            } else { // 'score'
                $stats->orderBy('ranked_score', 'desc');
            }
        }

        $maxPages = ceil($maxResults / static::PAGE_SIZE);
        $page = clamp(get_int(Request::input('page')), 1, $maxPages);

        if (is_api_request()) {
            $stats->with(['user.userProfileCustomization']);
        }

        $stats = $stats->limit(static::PAGE_SIZE)
            ->offset(static::PAGE_SIZE * ($page - 1))
            ->get();

        if (is_api_request()) {
            switch ($type) {
                case 'country':
                    return json_collection($stats, 'CountryStatistics', ['country']);
                break;

                case 'performance':
                case 'score':
                    return json_collection($stats, 'UserStatistics', ['user', 'user.cover', 'user.country']);
                    break;
            }
        } else {
            $scores = new LengthAwarePaginator($stats, $maxPages * static::PAGE_SIZE, static::PAGE_SIZE, $page, [
                'path' => route('rankings', ['mode' => $mode, 'type' => $type]),
            ]);

            return view("rankings.{$type}", compact('scores'));
        }
    }

    public function monthly($mode)
    {
        list($spotlight, $range) = $this->getSpotlightAndRange();

        $scores = $this->getUserStats($spotlight, $mode)->get();
        $beatmapsets = $spotlight->beatmapsets($mode)->get();

        // should use whatever attribute we're ordering by; for now chart_id is assumed.
        $earliest = Spotlight::monthly()->orderBy('chart_id', 'asc')->first();
        $latest = Spotlight::monthly()->orderBy('chart_id', 'desc')->first();
        $noPager = true;

        return view(
            "rankings.monthly",
            compact('scores', 'range', 'spotlight', 'beatmapsets', 'earliest', 'latest', 'noPager')
        );
    }

    public function spotlight($mode)
    {
        $chartId = get_int(request('spotlight'));

        $spotlights = Spotlight::notMonthly()->orderBy('chart_id', 'desc')->get();
        if ($chartId === null) {
            $spotlight = $spotlights->first();
        } else {
            $spotlight = Spotlight::notMonthly()->findOrFail($chartId);
        }

        $selectOptions = [
            'selected' => $this->optionFromSpotlight($spotlight),
            'options' => $spotlights->map(function ($s) {
                return $this->optionFromSpotlight($s);
            }),
        ];

        $scores = $this->getUserStats($spotlight, $mode)->get();
        $beatmapsets = $spotlight->beatmapsets($mode)->get();

        $noPager = true;

        return view(
            "rankings.charts",
            compact('scores', 'selectOptions', 'spotlight', 'beatmapsets', 'noPager')
        );
    }

    private function getSpotlightAndRange()
    {
        $chartId = get_int(request('spotlight'));
        $before = get_int(request('before'));
        $after = get_int(request('after'));

        if ($chartId !== null) {
            $spotlight = $this->spotlightQueryBase()->findOrFail($chartId);
            $range = $spotlight->getSpotlightsInYearRange()->get();
        } elseif ($before !== null) {
            $range = $this->spotlightQueryBase()->inYearRange($before - 1)->get();
            $spotlight = $range->last();
        } elseif ($after !== null) {
            $range = $this->spotlightQueryBase()->inYearRange($after + 1)->get();
            $spotlight = $range->first();
        } else {
            $spotlight = $this->spotlightQueryBase()->orderBy('chart_id', 'desc')->first();
            $range = $spotlight->getSpotlightsInYearRange()->get();
        }

        return [$spotlight, $range];
    }

    private function getUserStats($spotlight, $mode)
{'fraction_non_alphanumeric': 0.1595605545383207, 'fraction_numerical': 0.004054407533350772, 'mean_word_length': 2.182726326742976, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 153, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6948603', 'n_tokens_mistral': 4369, 'n_tokens_neox': 4146, 'n_words': 923}