<?php

namespace nadar\quill;

/**
 * Debug Object.
 *
 * The Debug class can return informations in a readable way from a lexer object. It will generate a html table
 * with additional infos about how each line is parsed line by line.
 *
 * ```php
 * $lexer = new Lexer($json);
 * $lexer->render(); // make sure to run the render before call debugPrint();
 *
 * $debug = new Debug($lexer);
 * echo $debug->debugPrint();
 * ```
 *
 * In order to push informations into the Debug Panel, you can use
 * the `debugInfo($text)` method which is available on all `Line` objects.
 *
 * @author Basil Suter <basil@nadar.io>
 * @since 1.0.0
 */
class Debug
{
    /**
     * @var Lexer
     */
    public $lexer;

    /**
     * Debug constructor
     */
    public function __construct(Lexer $lexer)
    {
        $this->lexer = $lexer;
    }

    /**
     * Get an array of lines which does not have status done.
     *
     * @return array<Line>
     */
    protected function getNotDoneLines()
    {
        $lines = [];
        foreach ($this->lexer->getLines() as $line) {
            if (!$line->isDone()) {
                $lines[] = $line;
            }
        }

        return $lines;
    }

    /**
     * Get an array of lines which does not have the status picked
     *
     * @return array<Line>
     */
    protected function getNotPickedLines()
    {
        $lines = [];
        foreach ($this->lexer->getLines() as $line) {
            if (!$line->isPicked() && !$line->isDone()) {
                $lines[] = $line;
            }
        }

        return $lines;
    }

    /**
     * return a string with debug informations.
     *
     * @return string
     */
    public function debugPrint()
    {
        $d = "<p><b>NOT PICKED LINES</b></p>";
        $d.= $this->getLinesTable($this->getNotPickedLines());

        $d.= "<p><b>NOT DONE LINES</b></p>";
        $d.= $this->getLinesTable($this->getNotDoneLines());

        $d.= "<p><b>LINE BY LINE</b></p>";
        $d.= $this->getLinesTable($this->lexer->getLines());

        return nl2br($d);
    }

    /**
     * Get an array with alles lines rendered a string
     *
     * @param array<Line> $lines
     * @return string
     */
    public function getLinesTable(array $lines)
    {
        $_lines = [];
        foreach ($lines as $line) {
            $_lines[] = [
                $line->getIndex(),
                $line->getInput(),
                htmlentities($line->output, ENT_QUOTES),
                htmlentities($line->renderPrepend(), ENT_QUOTES),
                implode(", ", $line->getDebugInfo()),
                var_export($line->getAttributes(), true),
                var_export($line->isInline(), true),
                $this->lineStatus($line),
                var_export($line->hasEndNewline(), true),
                var_export($line->hasNewline(), true),
                var_export($line->isEmpty(), true),
            ];
        }

        return $this->renderTable($_lines, ['ID', 'input', 'output', 'prepend', 'debug', 'attributes', 'is inline', 'status', 'has end newline', 'has new line', 'is empty']);
    }

    /**
     * Get the status waterfall of a given line
     *
     * @return string
     */
    public function lineStatus(Line $line)
    {
        if ($line->isDone()) {
            return 'Picked => Done';
        } elseif ($line->isPicked()) {
            return 'Picked';
        }

        return '';
    }

    /**
     * Render the given table line by line
     *
     * @param array<mixed> $rows
     * @param array<string> $head
     * @return string
     */
    protected function renderTable(array $rows, array $head = [])
    {
        $buffer = '<table class="table table-bordered table-striped table-hover table-sm small" border="1" width="100%" cellpadding="3" cellspacing="0">';

        if (!empty($head)) {
            $buffer.= '<thead><tr>';
            foreach ($head as $col) {
                $buffer.= '<td><b>'.$col.'</b></td>';
            }

            $buffer.= '</tr></thead>';
        }

        foreach ($rows as $cols) {
            $buffer .= '<tr onclick="this.style.backgroundColor=(this.style.backgroundColor==\'red\')?(\'transparent\'):(\'red\');">';
            foreach ($cols as $col) {
                $buffer .= '<td>'.$col.'</td>';
            }

            $buffer .= '</tr>';
        }

        return $buffer . '</table>';
    }
}
