<commit_before><?php

namespace Cpeter\PhpQkeylmEmailNotification\Qkeylm;

use Cpeter\PhpQkeylmEmailNotification\Exception\EmptyUrlException;
use GuzzleHttp\Exception\RequestException;
use voku\helper\HtmlDomParser;

/**
 * Class QkeylmApi
 * 
 * Handle interactions with the QKeyLM website:
 * - login
 * - fetch journal page for the current day
 * - fetch images
 * - prepare html to be set to the client
 * 
 * @package Cpeter\PhpQkeylmEmailNotification\Qkeylm
 */
class QkeylmApi
{

    /**
     * Config values passed to the app
     *
     * @var array
     */
    private $config = array();

    /**
     * Track the login state
     *
     * @var bool
     */
    private $logged_in = false;

    /**
     * QkeylmApi constructor.
     *
     * @param array $config
     */
    public function __construct($config)
    {
        $this->config = $config;

        // http client
        $client_config = [
            'cookies' => true,
            'headers' => [
                'Referer'   => $this->config['host']
            ]
        ];

        // if handler is specified inject into the client
        // this will be handy for unit testing without hitting the remote api
        if (!empty($this->config['handler'])){
            $client_config['handler'] = $this->config['handler'];
        }

        $this->client = new \GuzzleHttp\Client($client_config);
    }

    /**
     * Log in to the website.
     *
     * There are a couple of securify measures in place to get the user authetificated. Hence we need to
     * send the initial login request, then follow up with another post with the security challange.
     *
     * @return bool true|false True if login successfull
     * @throws EmptyUrlException
     */
    public function login()
    {
        $url = $this->config['host'].$this->config['page_token'];
        $res = $this->getUrl($url);

        // get the Auth token
        $auth_token = $this->getAuthToken($res->getBody());
        $post_data = $this->getPostData($auth_token, $this->config['login'], $this->config['password']);

        $res = $this->postUrl($url, $post_data);
        $wsignin = $this->getWSignInData($res->getBody());
        $post_data = [
            'wa' => 'wsignin1.0',
            'wresult' => $wsignin
        ];

        $url = $this->config['host'].$this->config['page_wsingin'];
        $res = $this->postUrl($url, $post_data);
        $body = $res->getBody();
        $this->logged_in = strpos($body, "/webui/Account/Logout") !== false;

        return $this->logged_in;
    }

    /**
     * Fetch the daily journal.
     *
     * @todo upon request this methos could be improved to accept a date the journal to be fetched from
     * @param string $date
     * @return mixed
     * @throws EmptyUrlException
     */
    public function getDailyJournal($date = '')
    {
        if (!$this->logged_in) {
            $this->login();
        }

        // fetch the journal page in order to be able to fetch the print page
        $url = $this->config['host'].$this->config['page_journal'];
        $this->getUrl($url);

        if (empty($date)){
            $date = date("Y-m-d");
        }
        $url = $this->config['host'].$this->config['page_journal_date'].$date;

        $res = $this->getUrl($url);
        if ($res->getBody()) {
            return $this->extractContent($res->getBody());
        }
        return array();
    }

    /**
     * Parse the HTML page returned by the website and keep just the main body that we are interested in.
     * All embeded images are downloaded locally.
     *
     * @param string $body
     * @return array
     * @throws Exception
     */
    public function extractContent($body)
    {
        // get just the main content
        $html = HtmlDomParser::str_get_html($body);
        // daily journal page div[id=mainInner]
        $main_content = $html->find('body>div', 0)->outertext;
        $main_content = $this->highlightChildName($this->config['child_name'], $main_content);
        // embed the small image in the email
        $main_content = str_replace("/webui/Files/Room/large/", "/webui/Files/Room/small/", $main_content);
        $main_content = str_replace('"/webui/', '"' . $this->config['host'] . '/webui/', $main_content);
        
        // get all images and download them
        preg_match_all(
            '|<img.*? src="(' . $this->config['host'] . '/webui/Files/Room/small/.*?)".*?>|',
            $main_content,
            $images
        );

        // process the images if there is any
        $content['images'] = [];
        if (isset($images[1])) {
            foreach ($images[1] as $image) {
                $content['images'][$image]['small'] = $this->fetchImage($image);
                // generate large image name
                $large_image = str_replace('small', 'large', $image);
                $content['images'][$image]['large'] = $this->fetchImage($large_image);<commit_msg>fixing getBody call with dependency injection<commit_after><?php

namespace Cpeter\PhpQkeylmEmailNotification\Qkeylm;

use Cpeter\PhpQkeylmEmailNotification\Exception\EmptyUrlException;
use GuzzleHttp\Exception\RequestException;
use voku\helper\HtmlDomParser;

/**
 * Class QkeylmApi
 * 
 * Handle interactions with the QKeyLM website:
 * - login
 * - fetch journal page for the current day
 * - fetch images
 * - prepare html to be set to the client
 * 
 * @package Cpeter\PhpQkeylmEmailNotification\Qkeylm
 */
class QkeylmApi
{

    /**
     * Config values passed to the app
     *
     * @var array
     */
    private $config = array();

    /**
     * Track the login state
     *
     * @var bool
     */
    private $logged_in = false;

    /**
     * QkeylmApi constructor.
     *
     * @param array $config
     */
    public function __construct($config)
    {
        $this->config = $config;

        // http client
        $client_config = [
            'cookies' => true,
            'headers' => [
                'Referer'   => $this->config['host']
            ]
        ];

        // if handler is specified inject into the client
        // this will be handy for unit testing without hitting the remote api
        if (!empty($this->config['handler'])){
            $client_config['handler'] = $this->config['handler'];
        }

        $this->client = new \GuzzleHttp\Client($client_config);
    }

    /**
     * Log in to the website.
     *
     * There are a couple of securify measures in place to get the user authetificated. Hence we need to
     * send the initial login request, then follow up with another post with the security challange.
     *
     * @return bool true|false True if login successfull
     * @throws EmptyUrlException
     */
    public function login()
    {
        $url = $this->config['host'].$this->config['page_token'];
        $res = $this->getUrl($url);

        // get the Auth token
        $auth_token = $this->getAuthToken($res->getBody());
        $post_data = $this->getPostData($auth_token, $this->config['login'], $this->config['password']);

        $res = $this->postUrl($url, $post_data);
        $wsignin = $this->getWSignInData($res->getBody());
        $post_data = [
            'wa' => 'wsignin1.0',
            'wresult' => $wsignin
        ];

        $url = $this->config['host'].$this->config['page_wsingin'];
        $res = $this->postUrl($url, $post_data);
        $body = $res->getBody();
        $this->logged_in = strpos($body, "/webui/Account/Logout") !== false;

        return $this->logged_in;
    }

    /**
     * Fetch the daily journal.
     *
     * @todo upon request this methos could be improved to accept a date the journal to be fetched from
     * @param string $date
     * @return mixed
     * @throws EmptyUrlException
     */
    public function getDailyJournal($date = '')
    {
        if (!$this->logged_in) {
            $this->login();
        }

        // fetch the journal page in order to be able to fetch the print page
        $url = $this->config['host'].$this->config['page_journal'];
        $this->getUrl($url);

        if (empty($date)){
            $date = date("Y-m-d");
        }
        $url = $this->config['host'].$this->config['page_journal_date'].$date;

        $res = $this->getUrl($url);
        if ($res->getBody()) {
            return $this->extractContent($res->getBody());
        }
        return array();
    }

    /**
     * Parse the HTML page returned by the website and keep just the main body that we are interested in.
     * All embeded images are downloaded locally.
     *
     * @param string $body
     * @return array
     * @throws Exception
     */
    public function extractContent(String $body)
    {
        // get just the main content
        $html = HtmlDomParser::str_get_html($body);
        // daily journal page div[id=mainInner]
        $main_content = $html->find('body>div', 0)->outertext;
        $main_content = $this->highlightChildName($this->config['child_name'], $main_content);
        // embed the small image in the email
        $main_content = str_replace("/webui/Files/Room/large/", "/webui/Files/Room/small/", $main_content);
        $main_content = str_replace('"/webui/', '"' . $this->config['host'] . '/webui/', $main_content);
        
        // get all images and download them
        preg_match_all(
            '|<img.*? src="(' . $this->config['host'] . '/webui/Files/Room/small/.*?)".*?>|',
            $main_content,
            $images
        );

        // process the images if there is any
        $content['images'] = [];
        if (isset($images[1])) {
            foreach ($images[1] as $image) {
                $content['images'][$image]['small'] = $this->fetchImage($image);
                // generate large image name
                $large_image = str_replace('small', 'large', $image);
                $content['images'][$image]['large'] = $this->fetchImage($large_image);
{'fraction_non_alphanumeric': 0.14684258233457548, 'fraction_numerical': 0.0010071507704703395, 'mean_word_length': 2.1939530395625604, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1518434', 'n_tokens_mistral': 2946, 'n_tokens_neox': 2893, 'n_words': 733}