<?php

declare(strict_types=1);

namespace Jfcherng\Diff\Renderer\Html;

use Jfcherng\Diff\Differ;
use Jfcherng\Diff\Factory\LineRendererFactory;
use Jfcherng\Diff\SequenceMatcher;

/**
 * HTML Json diff generator, with raw info.
 */
final class JsonHtmlWithRaw extends JsonHtml
{
    public function getChanges(Differ $differ): array
    {
        $lineRenderer = LineRendererFactory::make(
            $this->options['detailLevel'],
            $differ->getOptions(),
            $this->options,
        );

        $old = $differ->getOld();
        $new = $differ->getNew();
	    $oldRaw = $differ->getOld();
	    $newRaw = $differ->getNew();

        $changes = [];

        foreach ($differ->getGroupedOpcodes() as $hunk) {
            $change = [];

            foreach ($hunk as [$op, $i1, $i2, $j1, $j2]) {
                $change[] = $this->getDefaultBlock($op, $i1, $j1);
                $block = &$change[\count($change) - 1];

                // if there are same amount of lines replaced
                // we can render the inner detailed changes with corresponding lines
                // @todo or use LineRenderer to do the job regardless different line counts?
                if ($op === SequenceMatcher::OP_REP && $i2 - $i1 === $j2 - $j1) {
                    for ($k = $i2 - $i1 - 1; $k >= 0; --$k) {
                        $this->renderChangedExtent($lineRenderer, $old[$i1 + $k], $new[$j1 + $k]);
                    }
                }

                // The next two lines are the only addition to the parent class.
	            $block['old']['raw_lines'] = \array_slice($oldRaw, $i1, $i2 - $i1);
	            $block['new']['raw_lines'] = \array_slice($newRaw, $j1, $j2 - $j1);
                $block['old']['lines'] = \array_slice($old, $i1, $i2 - $i1);
                $block['new']['lines'] = \array_slice($new, $j1, $j2 - $j1);
            }
            unset($block);

            $changes[] = $change;
        }

        if (static::AUTO_FORMAT_CHANGES) {
            $this->formatChanges($changes);
        }

        return $changes;
    }
}
