<?php
/**
 * -------------------------------------------------------------------------
 *
 * Модуль субконтроллера Tasks.
 *
 * -------------------------------------------------------------------------
 *
 * @package    MimimiFramework
 * @subpackage Examples / Repost Vacancies
 * @license    GPL-2.0
 *             https://opensource.org/license/gpl-2-0/
 * @copyright  2022 MiMiMi Community
 *             https://mimimi.software/
 *
 * -------------------------------------------------------------------------
 */

    /**
     * ---------------------------------------------------------------------
     *
     * Подключаем из папки ядра фреймворка файл "mimimi.core/Module.php".
     * Там объявлен класс "MimimiModule", являющийся простейшей модульной
     * заготовкой. Этот класс подходит как основа для реализуемого ниже
     * модуля.
     *
     * ---------------------------------------------------------------------
     */

    mimimiInclude ( 'Module.php' );

    /**
     * ---------------------------------------------------------------------
     *
     * Создаём на основе класса той заготовки новый класс, в котором напишем
     * программный код текущего модуля. Обратите внимание как задано имя
     * нового класса - оно сложено из имени класса вышестоящего модуля, то
     * есть "MyMimimiControllersDashboard", и имени текущего PHP-файла без
     * расширения.
     *
     * ---------------------------------------------------------------------
     */

    class MyMimimiControllersDashboardTasks extends MimimiModule {

        /**
         * -----------------------------------------------------------------
         *
         * Метод: Маршрутизировать запрос к сопоставленному макету шаблона.
         *
         * -----------------------------------------------------------------
         *
         * Этот метод обслуживает следующие URL-ы:
         *
         *     https://ваш.сайт/tasks
         *     https://ваш.сайт/tasks/add
         *     https://ваш.сайт/tasks/copy
         *     https://ваш.сайт/tasks/edit
         *     https://ваш.сайт/tasks/delete
         *
         * Генерация HTML-кода страницы пройдёт на основе одного из таких
         * макетов:
         *
         *     repost.vacancies/Themes/default/dashboard/tasks.tpl
         *     repost.vacancies/Themes/default/dashboard/tasks-add.tpl
         *     repost.vacancies/Themes/default/dashboard/tasks-copy.tpl
         *     repost.vacancies/Themes/default/dashboard/tasks-edit.tpl
         *     repost.vacancies/Themes/default/dashboard/tasks-delete.tpl
         *
         * -----------------------------------------------------------------
         *
         * @public
         * @param   string  $url  (необязательный) Относительный URL запрошенной страницы.
         * @return  void
         *
         * -----------------------------------------------------------------
         */

        public function run ( $url = '' ) {
            if ( $this->owner->hasAdmin ( ) ) {
                $success = '';
                switch ( $url ) {
                    // когда страница "Список задач"
                    case 'tasks':
                         $rows = $this->app->models->tasks->selectAll ( );
                         $this->owner->render ( 'dashboard/tasks.tpl', $rows );
                         return;
                    // когда страница "Добавить задачу"
                    case 'tasks/add':
                         $struct = $this->app->models->tasks->getStructure ( );
                         $row    = [ ];
                         foreach ( $struct as $data ) {
                             $row[ $data[ 0 ] ] = is_array ( $data[ 1 ] ) ? ''
                                                                          : $data[ 1 ];
                         }
                         $row[ 'id'       ] = 0;
                         $row[ 'url_root' ] = 'tasks/';
                         $error  = $this->owner->hasForm ( ) ? $this->onUpdate ( $row, $struct, $success, TRUE )
                                                             : '';
                         $data   = [ 'success'     => $success ,
                                     'error'       => $error   ,
                                     'button_name' => 'form'   ,
                                     'structure'   => $struct  ,
                                     'row'         => $row     ];
                         $this->owner->render ( 'dashboard/tasks-add.tpl', $data );
                         return;
                    // когда страница "Скопировать задачу"
                    case 'tasks/copy':
                         $row = $this->getRequested ( );
                         if ( $row ) {
                             $row[ 'item_id' ] = $row[ 'id' ];
                             $row[ 'id'      ] = 0;
                             $struct = $this->app->models->tasks->getStructure ( );
                             $error  = $this->owner->hasForm ( ) ? $this->onUpdate ( $row, $struct, $success, TRUE )
                                                                 : '';
                             $data   = [ 'success'     => $success ,
                                         'error'       => $error   ,
                                         'button_name' => 'form'   ,
                                         'structure'   => $struct  ,
                                         'row'         => $row     ];
                             $this->owner->render ( 'dashboard/tasks-copy.tpl', $data );
                             return;
                         }
                         break;
                    // когда страница "Изменить задачу"
                    case 'tasks/edit':
                         $row = $this->getRequested ( );
                         if ( $row ) {
                             $struct = $this->app->models->tasks->getStructure ( );
                             $error  = $this->owner->hasForm ( ) ? $this->onUpdate ( $row, $struct, $success )
                                                                 : '';
                             $data   = [ 'success'     => $success ,
                                         'error'       => $error   ,
                                         'button_name' => 'form'   ,
                                         'structure'   => $struct  ,
                                         'row'         => $row     ];
                             $this->owner->render ( 'dashboard/tasks-edit.tpl', $data );
                             return;
                         }
                         break;
                    // когда страница "Удалить задачу"
                    case 'tasks/delete':
                         $row = $this->getRequested ( );
                         if ( $row ) {
                             if ( $this->owner->hasAgreed ( ) ) {
                                 $error = $this->onRemove ( $row, $success );
                             } else {
                                 $error = $this->owner->hasForm ( ) ? 'Ошибка: Вы не выполнили обязательное действие с флажком ниже!'
                                                                    : '';
                             }
                             $data = [ 'success'     => $success ,
                                       'error'       => $error   ,
                                       'button_name' => 'form'   ,
                                       'row'         => $row     ];
                             $this->owner->render ( 'dashboard/tasks-delete.tpl', $data );
                             return;
                         }
                         break;
                }
                // иначе запросили неизвестную нам страницу, тогда показываем "Ошибка 404"
                $this->app->controllers->seo->run ( '404' );
                return;
            }
            // иначе это оказался не админ, значит перебрасываем его на страницу "Вход"
            $this->owner->gotoLogin ( );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Метод: Получить запись задания, запрошенного в URL.
         *
         * -----------------------------------------------------------------
         *
         * Здесь мы с помощью подходящего метода, размещённого в модуле
         * хранителя контроллеров, извлекаем сначала ИД записи, указанный
         * сейчас в URL-e. Затем по этому ИД с помощью модели Tasks читаем
         * такую записи из базы данных и отдаём на выход.
         *
         * Перед этим ещё преобразуем значение колонки "active" из булевого
         * вида в число 1 или 0, так как знаем, что запись отправится далее
         * в шаблон сайта, где редактируемое поле "active" сделано с помощью
         * тега <input type="number">, для которого значение TRUE или FALSE
         * является неверным и потому исказит результат редактирования. За
         * разбором этого нюанса обратитесь к файлам:
         *
         *     repost.vacancies/Models/Tasks/Tasks.php  -->  метод getStructure()
         *     repost.vacancies/Themes/default/snippets/task-form.tpl
         *
         * -----------------------------------------------------------------
         *
         * @protected
         * @return  array  Массив, индексированный именами колонок прочитанной записи.
         *
         * -----------------------------------------------------------------
         */

        protected function getRequested ( ) {
            $id  = $this->app->controllers->getItemId ( );
            $row = $id ? $this->app->models->tasks->getBy ( $id )
                       : [ ];
            if ( $row ) {
                $row[ 'active' ] = $row[ 'active' ] ? 1 : 0;
            }
            return $row;
        }

        /**
         * -----------------------------------------------------------------
         *
         * Метод: Обработчик формы редактирования задания.
         *
         * -----------------------------------------------------------------
         *
         * В случае успешного редактирования администратор будет принудительно
         * перенаправлен на страницу списка заданий. В противном случае он
         * останется на той же форме ввода, в которую будет возвращён текст
         * сообщения об ошибке или демо успехе.
         *
         * -----------------------------------------------------------------
         */

        protected function onUpdate ( & $previous, $structure, & $success, $isNew = FALSE ) {
            $id = mimimiPost ( 'id', 0 );
            if ( $id != $previous[ 'id' ] ) {
                return 'Ошибка: Обнаружена попытка подменить ИД редактируемой записи!';
            }
            $error = '';
            $row   = [ ];
            foreach ( $structure as $struct ) {
                $name  = $struct[ 0 ];
                $value = mimimiPost ( $name, NULL );
                if ( is_null ( $value ) ) {
                    return 'Ошибка: Полученная форма задания не соответствует ожидаемой!';
                }
                $value = preg_replace ( '~(^\s+|\s+$)~u', '', $value );
                if ( $isNew
                ||   ! isset ( $previous[ $name ] )
                ||             $previous[ $name ] != $value ) {
                    $previous[ $name ] = $value;
                    if ( ! $error ) {
                        switch ( $name ) {
                            case 'name':
                                 if ( $value == '' ) $error = 'Ошибка: Вы должны ввести название задания!';
                                 break;
                            case 'module':
                                 if ( ! $this->app->controllers->parser->has->$value ) $error = 'Ошибка: Вы должны выбрать имя модуля только из числа доступных!';
                                 break;
                            case 'lifetime':
                                 $value = min ( max ( 1, intval ( $value ) ), 365 );
                                 break;
                            case 'active':
                                 $value = $value ? 1 : 0;
                                 break;
                            case 'filter_name':
                                 if ( $value == '' ) $error = 'Ошибка: Вы должны указать название данных в фильтре сайта!';
                                 break;
                            case 'filter_value':
                                 if ( $value == '' ) $error = 'Ошибка: Вы должны указать ИД данных в фильтре сайта!';
                                 break;
                            case 'tg_chat_id':
                            case 'max_chat_id':
                                 if ( $value != '' ) {
                                     $pattern = '~^(' . '-?\d{1,19}'               . '|'
                                                      . '[a-z][a-z\d_]{3,30}[a-z]' . ')$~i';
                                     if ( ! preg_match ( $pattern, $value ) ) $error = 'Ошибка: Имя или ИД принимающего канала не соответствует формату!';
                                 }
                                 break;
                            case 'type':
                            case 'params':
                            case 'source_url':
                            case 'chat_caption':
                            default:
                        }
                        $row[ $name ] = $value;
                    }
                }
            }
            if ( $error ) {
                return $error;
            }
            if ( $row ) {
                if ( $this->owner->isDemo ( ) ) {
                    $success = 'Ок! Но так как Вы сейчас в демо режиме, сайт игнорирует сохранение любых изменений. Чтобы увидеть, как это работает в действительности, скачайте приложение и запустите у себя на сайте, отключив демо режим.';
                    return '';
                }
                if ( $id ) $this->app->models->tasks->update ( $id, $row );
                else       $this->app->models->tasks->add    (      $row );
            }
            $this->gotoList ( );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Метод: Обработчик формы удаления задания.
         *
         * -----------------------------------------------------------------
         *
         * В случае успешного удаления администратор будет принудительно
         * перенаправлен на страницу списка заданий. В противном случае он
         * останется на той же форме ввода, в которую будет возвращён текст
         * о демо успехе.
         *
         * -----------------------------------------------------------------
         */

        protected function onRemove ( $previous, & $success ) {
            if ( $this->owner->isDemo ( ) ) {
                $success = 'Ок! Но так как Вы сейчас в демо режиме, сайт игнорирует удаление любых записей. Чтобы увидеть, как это работает в действительности, скачайте приложение и запустите у себя на сайте, отключив демо режим.';
                return '';
            }
            $this->app->models->tasks->remove ( $previous[ 'id' ] );
            $this->gotoList ( );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Метод: Принудительно перебросить на страницу списка заданий.
         *
         * -----------------------------------------------------------------
         */

        protected function gotoList ( ) {
            $this->owner->redirect ( 'tasks' );
        }
    }
