*/
class admin_plugin_logviewer extends DokuWiki_Admin_Plugin
{
    const MAX_READ_SIZE = 1048576; // 1 MB
    protected $facilities;
    protected $facility;
    protected $date;
    /** @inheritDoc */
    public function forAdminOnly()
    {
        return true;
    }
    /** @inheritDoc */
    public function handle()
    {
        global $INPUT;
        $this->facilities = $this->getFacilities();
        $this->facility = $INPUT->str('facility');
        if (!in_array($this->facility, $this->facilities)) {
            $this->facility = $this->facilities[0];
        }
        $this->date = $INPUT->str('date');
        if (!preg_match('/^\d\d\d\d-\d\d-\d\d$/', $this->date)) {
            $this->date = gmdate('Y-m-d');
        }
    }
    /** @inheritDoc */
    public function html()
    {
        echo '
';
        echo $this->locale_xhtml('intro');
        $this->displayTabs();
        $this->displayLog();
        echo '
';
    }
    /**
     * Show the navigational tabs and date picker
     */
    protected function displayTabs()
    {
        global $ID;
        $form = new dokuwiki\Form\Form(['method' => 'GET']);
        $form->setHiddenField('do', 'admin');
        $form->setHiddenField('page', 'logviewer');
        $form->setHiddenField('facility', $this->facility);
        $form->addTextInput('date', $this->getLang('date'))
            ->attr('type', 'date')->val($this->date)->addClass('quickselect');
        $form->addButton('submit', '>')->attr('type', 'submit');
        echo $form->toHTML();
        echo '';
        foreach ($this->facilities as $facility) {
            echo '- ';
            if ($facility == $this->facility) {
                echo '' . hsc($facility) . '';
            } else {
                $link = wl($ID,
                    ['do' => 'admin', 'page' => 'logviewer', 'date' => $this->date, 'facility' => $facility]);
                echo '' . hsc($facility) . '';
            }
            echo '';
        }
        echo '
';
    }
    /**
     * Read and output the logfile contents
     */
    protected function displayLog()
    {
        $logfile = Logger::getInstance($this->facility)->getLogfile($this->date);
        if (!file_exists($logfile)) {
            echo $this->locale_xhtml('nolog');
            return;
        }
        try {
            $lines = $this->getLogLines($logfile);
            $this->printLogLines($lines);
        } catch (Exception $e) {
            msg($e->getMessage(), -1);
        }
    }
    /**
     * Get the available logging facilities
     *
     * @return array
     */
    protected function getFacilities()
    {
        global $conf;
        // default facilities first
        $facilities = [
            Logger::LOG_ERROR,
            Logger::LOG_DEPRECATED,
            Logger::LOG_DEBUG,
        ];
        // add all other dirs
        $dirs = glob($conf['logdir'] . '/*', GLOB_ONLYDIR);
        foreach ($dirs as $dir) {
            $facilities[] = basename($dir);
        }
        $facilities = array_unique($facilities);
        return $facilities;
    }
    /**
     * Read the lines of the logfile and return them as array
     *
     * @param string $logfilePath
     * @return array
     * @throws Exception when reading fails
     */
    protected function getLogLines($logfilePath)
    {
        global $lang;
        $size = filesize($logfilePath);
        $fp = fopen($logfilePath, 'r');
        if (!$fp) throw new Exception($lang['log_file_failed_to_open']);
        try {
            if ($size < self::MAX_READ_SIZE) {
                $toread = $size;
            } else {
                $toread = self::MAX_READ_SIZE;
                fseek($fp, -$toread, SEEK_END);
            }
            $logData = fread($fp, $toread);
            if (!$logData) throw new Exception($lang['log_file_failed_to_read']);
            $lines = explode("\n", $logData);
            unset($logData); // free memory early
            if ($size >= self::MAX_READ_SIZE) {
                array_shift($lines); // Discard the first line
                while (!empty($lines) && (substr($lines[0], 0, 2) === '  ')) {
                    array_shift($lines); // Discard indented lines
                }
                // A message to inform users that previous lines are skipped
                array_unshift($lines, "******\t" . "\t" . '[' . $lang['log_file_too_large'] . ']');
            }
        } finally {
            fclose($fp);
        }
        return $lines;
    }
    /**
     * Get an array of log lines and print them using appropriate styles
     *
     * @param array $lines
     */
    protected function printLogLines($lines)
    {
        $numberOfLines = count($lines);
        echo "";
        for ($i = 0; $i < $numberOfLines; $i++) {
            $line = $lines[$i];
            if (substr($line, 0, 2) === '  ') {
                // lines indented by two spaces are details, aggregate them
                echo '- ';
                while (substr($line, 0, 2) === '  ') {
                    echo hsc(substr($line, 2)) . '
 ';
                    $i++;
                    $line = $lines[$i] ?? '';
                }
                echo '
';
                $i -= 1; // rewind the counter
            } else {
                // other lines are actual log lines in three parts
                list($dt, $file, $msg) = sexplode("\t", $line, 3, '');
                echo '- ';
                echo '' . hsc($dt) . '';
                echo '';
                echo '' . hsc($msg) . '';
                echo '' . hsc($file) . '';
                echo '';
                echo '';
            }
        }
        echo "
";
    }
}