<?php
/**
 * -------------------------------------------------------------------------
 *
 * The module for routing the current request.
 *
 * -------------------------------------------------------------------------
 *
 * How did this file run?
 *
 *     ├─> .htaccess
 *     └─> index.php
 *           ├─> tiny.news.feed/Config.php
 *           ├─> mimimi.core/Routines.php
 *           │               │
 *           │               ├─<─ routine mimimiInclude()
 *           │               ├─<─ routine mimimiUri()
 *           │               └─<─ routine mimimiStop()
 *           │
 *           ├─> [MAKE THE $app GLOBAL VARIABLE]
 *           │
 *           ├─> tiny.news.feed/Constants.php
 *           │                      │
 *           │                      └─<─ constant TINYFEED_ERROR_NO_THEMES
 *           │
 *           │                                      ┌─<─ class mimimi.core/Module.php
 *           │                                      │                        └─> __construct()
 *           │               ┌─<─ class mimimi.core/NodeModule.php
 *           │               │                           └─> __construct()
 *           └─> tiny.news.feed/Application.php
 *                              │    └─> run()                ┌─<─ class mimimi.core/Module.php
 *                              │         │                   │                        └─> __construct()
 *                              │         ├─> mimimi.core/Has/Has.php
 *                              │         │                    └─> __get()
 *                              │         │
 *                              │         │                         ┌─<─ class mimimi.core/Module.php
 *                              │         │                         │                        └─> __construct()
 *                              │         └─> tiny.news.feed/Router/Router.php
 *                              │                                   │  └─> run()
 *                              ├─<─ method getLatest()             │       │
 *                              ├─<─ method getViewers()            │       └─> [PLAY A RENDERING SCENARIO]
 *                              ├─<─ method getSitemap()            │
 *                              ├─<─ method getList()               ├─<─ method checkFor()
 *                              ├─<─ method getPage()               ├─<─ method findMe()
 *                              └─<─ method amIAdmin()              ├─<─ method cutViewer()
 *                                                                  ├─<─ method cutPagenum()
 *                                                                  └─<─ method cutCommand()
 *
 * The down-right arrows show the order in which app files are loaded and
 * their methods that are called when processing a request to the site.
 * The left-down arrows show the classes from which the corresponding
 * application file is derived. The left-up arrows show some of the public
 * routines or some of the public methods that the corresponding file
 * exposes to other application modules.
 *
 * -------------------------------------------------------------------------
 *
 * @package    MimimiFramework
 * @subpackage Examples / Tiny News Feed site
 * @license    GPL-2.0
 *             https://opensource.org/license/gpl-2-0/
 * @copyright  2022 MiMiMi Community
 *             https://mimimi.software/
 *
 * -------------------------------------------------------------------------
 */

                                                        // -----------------
mimimiInclude(                                          // load a file              ( see file mimimi.core/Routines.php -> mimimiInclude )
    'Module.php'                                        // . . with this base class ( see file mimimi.core/Module.php   -> MimimiModule )
);                                                      //
                                                        // -----------------
class MyMimimiRouter extends MimimiModule {             // define required "My..." class for this module named ROUTER

    /**
     * ---------------------------------------------------------------------
     *
     * Renders the requested page.
     *
     * ---------------------------------------------------------------------
     *
     * This method parses a path of the requested URL to play a scenario that
     * matches that URL. The parsed path can contain a standard address, such
     * as a home page or a robots.txt document. For example:
     *
     *     https://your.site/
     *     https://your.site/robots.txt
     *
     * But it can also contain a compound locator where the first path
     * segment is equal to the viewer module name and the last segment is
     * equal to the name of the administrative/informational command or
     * contains the page number being viewed. For example:
     *
     *     https://your.site/news                     <─ the viewer name only
     *     https://your.site/news/page-NNN            <─ the viewer name and a page number
     *     https://your.site/news/sitemap             <─ the viewer name and the informational command SITEMAP
     *     https://your.site/news/add                 <─ the viewer name and the administrative command ADD
     *
     * Internal path segments are considered to be the address of the
     * publication. Also, if the last segment does not match the locators
     * listed above, it is also recognized as a publication address. For
     * example:
     *
     *     https://your.site/news/hello-world/delete  <─ the viewer name, the publication address, and the administrative command DELETE
     *     https://your.site/news/hello-world/edit    <─ the viewer name, the publication address, and the administrative command EDIT
     *     https://your.site/news/hello-world         <─ the viewer name and the publication address
     *
     * Based on the parsed details, the router finds the appropriate
     * template file in your website's theme, the installed viewer that was
     * called by its name in the URL, and corresponding publication/list.
     * If all those actions are successful, the content of the requested
     * page is rendered according to the found template and the data
     * retrieved from the database using the invoked viewer.
     *
     * ---------------------------------------------------------------------
     *
     * @public
     * @param   mixed  $params  (optional) Some parameters from the calling process.
     * @return  void
     *
     * ---------------------------------------------------------------------
     */

    public function run ( $params = '' ) {              // -----------------
        global $item;                                   // init desired variables for the corresponding template in the website theme
               $item = FALSE;                           // . .
        global $items;                                  // . .
               $items = FALSE;                          // . .
        global $page;                                   // . .
               $page = 0;                               // . .
        global $viewer;                                 // . .
               $viewer = '';                            // . .
        global $url;                                    // . .
               $url = mimimiUri(FALSE);                 // . . get URL path ( see file mimimi.core/Routines.php -> mimimiUri )
                                                        // -----------------
        $file = FALSE;                                  // there is no associated template
        switch ( $url ) {                               // where did we stay?
            case '':                                    //     if on Home page                        (it's scenario 1)
                $file = $this->findMe('home.tpl');      //         get associated template
                break;                                  //
                                                        // -----------------
            case 'robots.txt':                          //     if on ROBOTS.TXT document              (it's scenario 2)
                $file = $this->findMe('robots.tpl');    //         get associated template
                break;                                  //
                                                        // -----------------
            default:                                    //     else
                $viewer = $this->cutViewer($url);       //         trim viewer name - it's the first segment of URL
                $ok = $this->checkFor($viewer);         //         is the requested viewer installed?
                if ( $ok ) {                            //         if it's true
                                                        // -----------------
                    $file = $this                       //             check if this viewer has its own router
                            ->app                       //             . . via APPLICATION module ( see file tiny.news.feed/Application.php )
                            ->viewers                   //             . . via VIEWERS module     ( see file tiny.news.feed/Viewers/Viewers.php )
                            ->$viewer                   //             . . via this submodule     ( see file tiny.news.feed/Viewers/[$viewer]/[$viewer].php -> run )
                            ->run($url);                //             . . using this method
                                                        // -----------------
                    if ( $file === FALSE ) {            //             if no own router
                        $page = $this->cutPagenum($url);//                 trim paginator - it's the last segment of URL
                                                        // -----------------
                        switch ( $url ) {               //                 where did we stay now?
                            case '':                    //                     if on List page            (it's scenario 3)
                                $file = $this->findMe(  //                         get associated template
                                            $viewer . '-list.tpl'
                                        );              //
                                if ( $file ) {          //                         if successful
                                    $items = $this      //                             get a list of publications
                                             ->app      //                             . . via APPLICATION module ( see file tiny.news.feed/Application.php -> getList )
                                             ->getList( //                             . . using this method
                                                 $viewer, //                               . . using this viewer module
                                                 $page  //                                 . . located on the current page
                                             );         //
                                    $ok = ! empty($items); //                          check status
                                }                       //
                                break;                  //
                                                        // -----------------
                            case 'sitemap':             //                     if on SITEMAP.XML document (it's scenario 4)
                                $file = $this->findMe(  //                         get associated template
                                            $viewer . '-sitemap.tpl'
                                        );              //
                                $page = 0;              //                         reset this variable for template
                                break;                  //
                                                        // -----------------
                            case 'add':                 //                     if on Add page             (it's scenario 5.1)
                                $file = $this->findMe(  //                         get associated template
                                            $viewer . '-add.tpl'
                                        );              //
                                if ( $file ) {          //                         if successful
                                    $ok = $this         //                             am I admin?
                                          ->app         //                             . . via APPLICATION module ( see file tiny.news.feed/Application.php -> amIAdmin )
                                          ->amIAdmin(); //                             . . using this method
                                }                       //
                                $page = 0;              //                         reset this variable for template
                                break;                  //
                                                        // -----------------
                            default:                    //                     else
                                $ok = FALSE;            //                         reset status
                                $page = 0;              //                         reset this variable for template
                                $command = $this        //                         trim command - it's the last segment of URL
                                           ->cutCommand($url);
                                                        // -----------------
                                switch ( $command ) {   //                         what is it?
                                    case 'delete':      //                             if Delete command  (it's scenario 5.2)
                                    case 'edit':        //                             or if Edit command (it's scenario 5.2)
                                        if ( $url ) {   //                                 if command has valid argument
                                            $file = $this->findMe( //                          get associated template
                                                        $viewer . '-' . $command . '.tpl'
                                                    );  //
                                            if ( $file ) { //                                  if successful
                                                $ok = $this //                                     am I admin?
                                                      ->app //                                     . . via APPLICATION module ( see file tiny.news.feed/Application.php -> amIAdmin )
                                                      ->amIAdmin(); //                             . . using this method
                                            }           //
                                        }               //
                                        break;          //
                                                        // -----------------
                                    default:            //                             else               (it's scenario 6)
                                        $url = $this    //                                 restore last segment of URL
                                               ->app    //                                 . . via APPLICATION module ( see file tiny.news.feed/Application.php )
                                               ->url    //                                 . . via URL module         ( see file mimimi.modules/Url/Url.php -> pasteParameter )
                                               ->pasteParameter( //                        . . using this method
                                                   $url,    //                                 . . use this URL
                                                   $command //                                 . . plus this segment
                                               );       //
                                        $file = $this->findMe( //                          get associated template
                                                    $viewer . '-page.tpl'
                                                );      //
                                        $ok = ! empty($file); //                           check status
                                }                       //
                                                        // -----------------
                                if ( $ok ) {            //                         if there is all right
                                    $item = $this       //                             get publication by its URL
                                            ->app       //                             . . via APPLICATION module ( see file tiny.news.feed/Application.php -> getPage )
                                            ->getPage(  //                             . . using this method
                                                $viewer,//                                 . . using this viewer module
                                                $url    //                                 . . find record by this URL
                                            );          //
                                    $ok = !empty($item);//                             check status
                                }                       //
                        }                               //
                                                        // -----------------
                        if ( ! $ok ) {                  //                 if a failure occurs
                            $file = FALSE;              //                     reset associated template
                            $page = 0;                  //                     reset this variable for template
                        }                               //
                    }                                   //
                }                                       //
        }                                               //
                                                        // -----------------
        $ok = $this                                     // check if themes are installed in this app
              ->app                                     // . . via APPLICATION module ( see file tiny.news.feed/Application.php )
              ->has                                     // . . via HAS module         ( see file mimimi.core/Has/Has.php -> __get )
              ->themes;                                 // . . check for this module  ( see file tiny.news.feed/Themes/Themes.php )
                                                        // -----------------
        $ok                                             // if it's true
            ? $this                                     //     render the page
              ->app                                     //     . . via APPLICATION module ( see file tiny.news.feed/Application.php )
              ->themes                                  //     . . via THEMES module      ( see file tiny.news.feed/Themes/Themes.php -> render )
              ->render(                                 //     . . using this method
                  $file ? $file                         //         . . using this template file
                        : '404.tpl'                     //         . . otherwise use "Error 404" template
              )                                         //
                                                        // -----------------
            : mimimiStop(                               //     otherwise stop execution   ( see file mimimi.core/Routines.php     -> mimimiStop )
                  TINYFEED_ERROR_NO_THEMES,             //     . . with this notification ( see file tiny.news.feed/Constants.php -> TINYFEED_ERROR_NO_THEMES )
                  501                                   //     . . with this HTML status code
              );                                        //             
    }                                                   // -----------------

    /**
     * ---------------------------------------------------------------------
     *
     * Checks if the viewer is installed.
     *
     * ---------------------------------------------------------------------
     *
     * @public
     * @param   string  $viewer  (optional) Name of the viewer to be checked.
     * @return  bool
     *
     * ---------------------------------------------------------------------
     */

    public function checkFor ( $viewer = '' ) {         // -----------------
        return $this                                    // check if viewers are installed in this app
               ->app                                    // . . via APPLICATION module ( see file tiny.news.feed/Application.php )
               ->has                                    // . . via HAS module         ( see file mimimi.core/Has/Has.php -> __get )
               ->viewers                                // . . check for this module  ( see file tiny.news.feed/Viewers/Viewers.php )
                                                        // -----------------
            && ( empty($viewer)                         // and nothing more
                 || $this                               //     or check if the requested viewer is installed
                    ->app                               //        . . via APPLICATION module   ( see file tiny.news.feed/Application.php )
                    ->viewers                           //        . . via VIEWERS module       ( see file tiny.news.feed/Viewers/Viewers.php )
                    ->has                               //        . . via HAS module           ( see file mimimi.core/Has/Has.php -> __get )
                    ->$viewer );                        //        . . check for this submodule ( see file tiny.news.feed/Viewers/[$viewer]/[$viewer].php )
    }                                                   // -----------------

    /**
     * ---------------------------------------------------------------------
     *
     * Checks if your website's theme has a specific template.
     *
     * ---------------------------------------------------------------------
     *
     * @public
     * @param   string       $template  Name of the template file to be checked.
     * @return  string|bool             Same name as the input parameter if successful.
     *                                  FALSE on failure.
     *
     * ---------------------------------------------------------------------
     */

    public function findMe ( $template ) {              // -----------------
        return $this                                    // check if themes are installed in this app
               ->app                                    // . . via APPLICATION module ( see file tiny.news.feed/Application.php )
               ->has                                    // . . via HAS module         ( see file mimimi.core/Has/Has.php -> __get )
               ->themes                                 // . . check for this module  ( see file tiny.news.feed/Themes/Themes.php )
                                                        // -----------------
            && $this                                    // and check if the theme has that template
               ->app                                    //     . . via APPLICATION module ( see file tiny.news.feed/Application.php )
               ->themes                                 //     . . via THEMES module      ( see file tiny.news.feed/Themes/Themes.php -> checkFor )
               ->checkFor($template)                    //     . . using this method
                   ? $template                          //         . . return the input template name
                   : FALSE;                             //         . . otherwise return none
    }                                                   // -----------------

    /**
     * ---------------------------------------------------------------------
     *
     * Trims the URL on the left.
     *
     * ---------------------------------------------------------------------
     *
     * @public
     * @param   string  $url  The URL path of the requested page.
     * @return  string        The viewer name.
     *
     * ---------------------------------------------------------------------
     */

    public function cutViewer ( & $url ) {              // -----------------
        return $this                                    // if this app has the required module installed
               ->app                                    // . . via APPLICATION module ( see file tiny.news.feed/Application.php )
               ->has                                    // . . via HAS module         ( see file mimimi.core/Has/Has.php -> __get )
               ->url                                    // . . check for this module  ( see file mimimi.modules/Url/Url.php )
                                                        // -----------------
                   ? $this                              //     then return the first segment of URL
                     ->app                              //     . . via APPLICATION module ( see file tiny.news.feed/Application.php )
                     ->url                              //     . . via URL module         ( see file mimimi.modules/Url/Url.php -> cutSegment )
                     ->cutSegment($url)                 //     . . using this method
                                                        // -----------------
                   : '';                                //     otherwise return none
    }                                                   // -----------------

    /**
     * ---------------------------------------------------------------------
     *
     * Trims the URL on the right as a number.
     *
     * ---------------------------------------------------------------------
     *
     * You can use this method when you need to extract the page number from
     * a URL. For example, if you have an absolute URL, use code like this:
     *
     *     $locator = 'https://your.site/news/page-2';
     *     $num = $this->app->router->curPagenum( $locator );
     *
     * Here the variable $num will be set to 2. Moreover, it is important
     * to understand that your $locator variable is passed by reference and
     * after the method is completed it will take the same value, but with
     * the paginator removed.
     *
     * The next example is identical even if you have a relative URL:
     *
     *     $locator = 'news/page-2';
     *     $num = $this->app->router->curPagenum( $locator );
     *
     * Also note that if your locator does not contain a paginator, the
     * return value will always be 1 and the locator will remain unchanged.
     *
     * ---------------------------------------------------------------------
     *
     * @public
     * @param   string  $url  The URL path of the requested page.
     * @return  int           The page number being viewed.
     *
     * ---------------------------------------------------------------------
     */

    public function cutPagenum ( & $url ) {             // -----------------
        return $this                                    // if this app has the required module installed
               ->app                                    // . . via APPLICATION module ( see file tiny.news.feed/Application.php )
               ->has                                    // . . via HAS module         ( see file mimimi.core/Has/Has.php -> __get )
               ->url                                    // . . check for this module  ( see file mimimi.modules/Url/Url.php )
                                                        // -----------------
                   ? $this                              //     then return the last segment of URL
                     ->app                              //     . . via APPLICATION module ( see file tiny.news.feed/Application.php )
                     ->url                              //     . . via URL module         ( see file mimimi.modules/Url/Url.php -> cutPaginator )
                     ->cutPaginator($url)               //     . . using this method
                                                        // -----------------
                   : 1;                                 //     otherwise return 1
    }                                                   // -----------------

    /**
     * ---------------------------------------------------------------------
     *
     * Trims the URL on the right as a string.
     *
     * ---------------------------------------------------------------------
     *
     * @public
     * @param   string  $url  The URL path of the requested page.
     * @return  string        The command being executed.
     *
     * ---------------------------------------------------------------------
     */

    public function cutCommand ( & $url ) {             // -----------------
        return $this                                    // if this app has the required module installed
               ->app                                    // . . via APPLICATION module ( see file tiny.news.feed/Application.php )
               ->has                                    // . . via HAS module         ( see file mimimi.core/Has/Has.php -> __get )
               ->url                                    // . . check for this module  ( see file mimimi.modules/Url/Url.php )
                                                        // -----------------
                   ? $this                              //     then return the last segment of URL
                     ->app                              //     . . via APPLICATION module ( see file tiny.news.feed/Application.php )
                     ->url                              //     . . via URL module         ( see file mimimi.modules/Url/Url.php -> cutParameter )
                     ->cutParameter($url)               //     . . using this method
                                                        // -----------------
                   : '';                                //     otherwise return none
    }                                                   // -----------------
};