<commit_before><?php

namespace App\Bundle\MainBundle\Services\Autocompleter\Handler;

use App\Bundle\MainBundle\Form\Model\Submission;
use App\Bundle\MainBundle\Services\Autocompleter\Exception\InvalidUrlException;
use Guzzle\Http\ClientInterface;
use Symfony\Component\DomCrawler\Crawler;

/**
 * Fetch data from a Speedrun.com run page
 */
class SpeedruncomHandler implements HandlerInterface
{
    /**
     * The web client used to fetch the URL content
     *
     * @var ClientInterface
     */
    private $client;

    /**
     * __construct
     *
     * @param ClientInterface $client
     */
    public function __construct(ClientInterface $client)
    {
        $this->client = $client;
    }

    /**
     * {@inheritdoc}
     */
    public function fill(Submission $submission, $url)
    {
        if ($this->match($url)) {
            $request  = $this->client->get($url);
            $response = $request->send();

            if ($response->getStatusCode() === 200) {
                $this->process($submission, $response->getBody(true));
            }
        }

        throw new InvalidUrlException();
    }

    /**
     * Test that the URL has the proper pattern
     *
     * @param string $url
     *
     * @return bool
     */
    private function match($url)
    {
        return preg_match('/^(http?:\/\/)?www\.speedrun\.com\/run\/(\d+)$/', $url);
    }

    /**
     * Process the HTML content of the page and update the given submission
     *
     * @param Submission $submission
     * @param string     $content
     */
    private function process(Submission $submission, $content)
    {
        $crawler = new Crawler($content);

        list($playerName, $playerLink) = $this->getPlayerData($crawler);
        $title = $crawler->filter('#titleheader')->text();
        $description = $crawler->filter('main .maincontent h2')->eq(0)->text();
        list($category, $time) = $this->parseDescription($description);
        $note = $crawler->filter('main .maincontent .note')->text();
        list($platform, $date) = $this->parseNote($note);
        $link = $this->getVideoLink($crawler);

        $submission->setPlayerName($playerName);
        $submission->setPlayerLink($playerLink);
        $submission->setGame($title);
        $submission->setCategory($category);
        $submission->setLink($link);
        $submission->setTime($time);
        $submission->setPlatform($platform);
        if ($date !== null) {
            $submission->setDate($date);
        }
    }

    /**
     * Retrieve the player's name and profile URL
     *
     * @param Crawler $crawler
     *
     * @return array
     */
    private function getPlayerData(Crawler $crawler)
    {
        $linkNode = $crawler->filter('main .maincontent h2')->eq(1)->filter('a')->first()->getNode(0);
        if ($linkNode) {
            $username  = $crawler->filter('main .maincontent h2')->eq(1)->filter('span')->eq(1)->text();
            $link      = sprintf('http://www.speedrun.com/user/%s', $username);
            $twitchUrl = $this->retrieveProfile($link);

            return [
                ucfirst($username),
                ($twitchUrl ?: $link),
            ];
        }

        return [
            ucfirst($crawler->filter('main .maincontent h2')->eq(1)->text()),
            '',
        ];
    }

    /**
     * Retrieve the URL of the twitch video used as proof if there is one
     *
     * @param Crawler $crawler
     *
     * @return string
     */
    private function getVideoLink(Crawler $crawler)
    {
        $twitchNode = $crawler->filter('main .maincontent object.twitch param[name=flashvars]')->first()->getNode(0);
        if ($twitchNode) {
            $info = $twitchNode->getAttribute('value');
            $pattern = '/^channel=(?P<channel>\w+)(?:&\w+=\w+)+&(?:(?:videoId=v(?P<video>\d+))|(?:chapter_id=(?P<chapter>\d+)))$/';
            $matches = [];
            preg_match($pattern, $info, $matches);

            $channel = $matches['channel'];
            $url = ($matches['video'] !== '' ? 'v/'.$matches['video'] : 'c/'.$matches['chapter']);

            return sprintf('http://www.twitch.tv/%s/%s', $channel, $url);
        }

        return '';
    }

    /**
     * Parse the description string to retrieve the category and the time
     *
     * @param string $description<commit_msg>Handle youtube videos in speedruncom autocompletion<commit_after><?php

namespace App\Bundle\MainBundle\Services\Autocompleter\Handler;

use App\Bundle\MainBundle\Form\Model\Submission;
use App\Bundle\MainBundle\Services\Autocompleter\Exception\InvalidUrlException;
use Guzzle\Http\ClientInterface;
use Symfony\Component\DomCrawler\Crawler;

/**
 * Fetch data from a Speedrun.com run page
 */
class SpeedruncomHandler implements HandlerInterface
{
    /**
     * The web client used to fetch the URL content
     *
     * @var ClientInterface
     */
    private $client;

    /**
     * __construct
     *
     * @param ClientInterface $client
     */
    public function __construct(ClientInterface $client)
    {
        $this->client = $client;
    }

    /**
     * {@inheritdoc}
     */
    public function fill(Submission $submission, $url)
    {
        if ($this->match($url)) {
            $request  = $this->client->get($url);
            $response = $request->send();

            if ($response->getStatusCode() === 200) {
                $this->process($submission, $response->getBody(true));
            }
        }

        throw new InvalidUrlException();
    }

    /**
     * Test that the URL has the proper pattern
     *
     * @param string $url
     *
     * @return bool
     */
    private function match($url)
    {
        return preg_match('/^(http?:\/\/)?www\.speedrun\.com\/run\/(\d+)$/', $url);
    }

    /**
     * Process the HTML content of the page and update the given submission
     *
     * @param Submission $submission
     * @param string     $content
     */
    private function process(Submission $submission, $content)
    {
        $crawler = new Crawler($content);

        list($playerName, $playerLink) = $this->getPlayerData($crawler);
        $title = $crawler->filter('#titleheader')->text();
        $description = $crawler->filter('main .maincontent h2')->eq(0)->text();
        list($category, $time) = $this->parseDescription($description);
        $note = $crawler->filter('main .maincontent footer.note')->text();
        list($platform, $date) = $this->parseNote($note);
        $link = $this->getVideoLink($crawler);

        $submission->setPlayerName($playerName);
        $submission->setPlayerLink($playerLink);
        $submission->setGame($title);
        $submission->setCategory($category);
        $submission->setLink($link);
        $submission->setTime($time);
        $submission->setPlatform($platform);
        if ($date !== null) {
            $submission->setDate($date);
        }
    }

    /**
     * Retrieve the player's name and profile URL
     *
     * @param Crawler $crawler
     *
     * @return array
     */
    private function getPlayerData(Crawler $crawler)
    {
        $linkNode = $crawler->filter('main .maincontent h2')->eq(1)->filter('a')->first()->getNode(0);
        if ($linkNode) {
            $username  = $crawler->filter('main .maincontent h2')->eq(1)->filter('span')->eq(1)->text();
            $link      = sprintf('http://www.speedrun.com/user/%s', $username);
            $twitchUrl = $this->retrieveProfile($link);

            return [
                ucfirst($username),
                ($twitchUrl ?: $link),
            ];
        }

        return [
            ucfirst($crawler->filter('main .maincontent h2')->eq(1)->text()),
            '',
        ];
    }

    /**
     * Retrieve the URL of the twitch video used as proof if there is one
     *
     * @param Crawler $crawler
     *
     * @return string
     */
    private function getVideoLink(Crawler $crawler)
    {
        $twitchNode = $crawler->filter('main .maincontent object.twitch param[name=flashvars]')->first()->getNode(0);
        $youtubeNode = $crawler->filter('main .maincontent iframe.youtube')->first()->getNode(0);
        if ($twitchNode) {
            $info = $twitchNode->getAttribute('value');
            $pattern = '/^channel=(?P<channel>\w+)(?:&\w+=\w+)+&(?:(?:videoId=v(?P<video>\d+))|(?:chapter_id=(?P<chapter>\d+)))$/';
            $matches = [];
            preg_match($pattern, $info, $matches);

            $channel = $matches['channel'];
            $url = ($matches['video'] !== '' ? 'v/'.$matches['video'] : 'c/'.$matches['chapter']);

            return sprintf('http://www.twitch.tv/%s/%s', $channel, $url);
        } elseif ($youtubeNode) {
            $info = $youtubeNode->getAttribute('src');
            $pattern = '/^(http)?(\/\/)?www\.youtube\.com\/embed\/(?P<video>\w+)(\?autoplay=0)?$/';
            $matches = [];
            preg_match($pattern, $info, $matches);

            return sprintf('https://www.youtube.com/watch?v=%s', $matches['video']);
        }

        return '';
    }

    /**
     * Parse the description string to retrieve the category and the time
     *
     * @param string $description
{'fraction_non_alphanumeric': 0.17046321525885558, 'fraction_numerical': 0.0032697547683923707, 'mean_word_length': 2.303095752339813, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 104, 'https://': 1, 'lorem ipsum': 0, 'www.': 8, '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': '682520', 'n_tokens_mistral': 2762, 'n_tokens_neox': 2712, 'n_words': 509}