<?php

/**
 * DokuWiki Action component of DiffPreview Plugin
 *
 * @license  GPL-2.0-or-later (http://www.gnu.org/licenses/gpl.html)
 * @author   Mikhail I. Izmestev <izmmishao5@gmail.com>
 * @author   Tilwa Qendov <tilwa.qendov@gmail.com>
 * @version  1.3.1
 */
class action_plugin_diffpreview extends DokuWiki_Action_Plugin
{
    /**
     * Register its handlers with the DokuWiki's event controller
     */
    public function register(Doku_Event_Handler $controller)
    {
        $controller->register_hook('HTML_EDITFORM_OUTPUT', 'BEFORE', $this, '_edit_form'); // release Hogfather and below
        $controller->register_hook('FORM_EDIT_OUTPUT', 'BEFORE', $this, '_edit_form'); // release Igor and above

        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, '_action_act_preprocess');
        $controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE', $this, '_tpl_act_changes');
    }

    /**
     * Add "Changes" button to the edit form
     */
    public function _edit_form(Doku_Event $event, $param)
    {
        $form = $event->data;

        /* Check the DokuWiki release */
        if (is_a($form, \dokuwiki\Form\Form::class)) {
            /* release Igor and above */

            $pos = $form->findPositionByAttribute('id', 'edbtn__preview');
            if ($pos !== false) {
                $form->addButton('do[changes]', $this->getLang('changes'), $pos+1)
                    ->attr('type', 'submit')
                    ->attrs(['accesskey' => 'c', 'tabindex' => '5'])
                    ->id('edbtn__changes');
            }

        } else {
            /* release Hogfather and below */

            $preview = $form->findElementById('edbtn__preview');
            if ($preview !== false) {
                $form->insertElement($preview+1,
                    form_makeButton('submit', 'changes', $this->getLang('changes'),
                        array('id' => 'edbtn__changes', 'accesskey' => 'c', 'tabindex' => '5')));
            }
        }
    }

    /**
     * Process the "changes" action
     */
    public function _action_act_preprocess(Doku_Event $event, $param)
    {
        global $ACT, $INFO;

        $action =& $event->data;

        if (!( /* Valid cases */
            $action == 'changes' // Greebo
            // Frusterick Manners and below... probably
            || is_array($action) && array_key_exists('changes', $action)
        )) return;

        /* We check the DokuWiki release */
        if (class_exists('\\dokuwiki\\ActionRouter', false)) {
            /* release Greebo and above */

            /* See ActionRouter->setupAction() and Action\Preview */
            // WARN: Only works because Action\Edit methods are public
            $ae = new dokuwiki\Action\Edit();
            $ae->checkPreconditions();
            $this->savedraft();
            $ae->preProcess();

            $event->stopPropagation();
            $event->preventDefault();

        } elseif (function_exists('act_permcheck')) {
            /* release Frusterick Manners and below */

            // Same setup as preview: permissions and environment
            if ('preview' == act_permcheck('preview')
                && 'preview' == act_edit('preview'))
            {
                act_draftsave('preview');
                $ACT = 'changes';

                $event->stopPropagation();
                $event->preventDefault();
            } else {
                $ACT = 'preview';
            }

        } else {
            // Fallback
            $ACT = 'preview';
        }
    }

    /**
     * Display the "changes" page
     */
    public function _tpl_act_changes(Doku_Event $event, $param)
    {
        global $TEXT;
        global $PRE;
        global $SUF;

        if ('changes' != $event->data) return;

        /* Check the DokuWiki release */
        try {
            // Try to load the Ui\Editor class ourselves to avoid a fatal error in `class_exists`
            spl_autoload('\\dokuwiki\\Ui\\Editor');
        } catch (Exception $e) {}
        if (class_exists('\\dokuwiki\\Ui\\Editor', false)) {
            /* release Igor and above */
            (new helper_plugin_diffpreview_changes)->tplContent();
        } else {
            /* release Hogfather and below */
            html_edit($TEXT);
            echo '<br id="scroll__here" />';
            html_diff(con($PRE,$TEXT,$SUF));
        }

        $event->preventDefault();
    }

    /**
     * Saves a draft on show changes
     * Returns if the permissions don't allow it
     *
     * Copied from dokuwiki\Action\Preview (inc/Action/Preview.php)
     * so that we use the same draft. The two different versions come from
     * different releases.
     */
    protected function savedraft()
    {
        global $INFO, $ID, $INPUT, $conf;

        if (class_exists('\\dokuwiki\\Draft', false)) {
            /* Release Hogfather (and above) */

            $draft = new \dokuwiki\Draft($ID, $INFO['client']);
            if (!$draft->saveDraft()) {
                $errors = $draft->getErrors();
                foreach ($errors as $error) {
                    msg(hsc($error), -1);
                }
            }

        } else {
            /* Release Greebo and below */

            if (!$conf['usedraft']) return;
            if (!$INPUT->post->has('wikitext')) return;

            // ensure environment (safeguard when used via AJAX)
            assert(isset($INFO['client']), 'INFO.client should have been set');
            assert(isset($ID), 'ID should have been set');

            $draft = array(
                'id' => $ID,
                'prefix' => substr($INPUT->post->str('prefix'), 0, -1),
                'text' => $INPUT->post->str('wikitext'),
                'suffix' => $INPUT->post->str('suffix'),
                'date' => $INPUT->post->int('date'),
                'client' => $INFO['client'],
            );
            $cname = getCacheName($draft['client'] . $ID, '.draft');
            if (io_saveFile($cname, serialize($draft))) {
                $INFO['draft'] = $cname;
            }
        }
    }
}
