<?php
/**
 * -------------------------------------------------------------------------
 *
 * The main application module.
 *
 * -------------------------------------------------------------------------
 *
 * @package    MimimiFramework
 * @subpackage Examples / Static Pages only
 * @license    GPL-2.0
 *             https://opensource.org/license/gpl-2-0/
 * @copyright  2022 MiMiMi Community
 *             https://mimimi.software/
 *
 * -------------------------------------------------------------------------
 */

    mimimiLoad    ( 'RoutinesWeb.php'      );
    mimimiInclude ( 'Constants.php', FALSE );
    mimimiInclude ( 'NodeModule.php'       );

    class MyMimimiApplication extends MimimiNodeModule {

        /**
         * -----------------------------------------------------------------
         *
         * Renders a page requested by the browser.
         *
         * -----------------------------------------------------------------
         *
         * This method handles the current URL and routes it to the template
         * file associated with such URL type:
         *
         *     https://your.site/               to view the home page
         *     https://your.site/toc            to view a table of contents
         *     https://your.site/credits        to view a page with gratitude to third-party developers
         *     https://your.site/login          to log in as an admin
         *     https://your.site/robots.txt     to generate "robotx.txt" document
         *     https://your.site/sitemap.xml    to generate sitemap document
         *     https://your.site/SOME-PAGE-URL  to view a page
         *
         * There are also a few URLs that are only routed if the current
         * user is already logged in:
         *
         *     https://your.site/logout                                to log out
         *     https://your.site/settings                              to edit site constants
         *
         *     https://your.site/pages                                 to view a list of pages
         *     https://your.site/add                                   to add a new page
         *     https://your.site/add/SOME-PAGE-URL                     to add a new page if such URL is not already taken
         *     https://your.site/copy/SOME-PAGE-URL                    to copy a page
         *     https://your.site/delete/SOME-PAGE-URL                  to delete a page
         *     https://your.site/edit/SOME-PAGE-URL                    to edit a page
         *     https://your.site/upload                                to upload a new page
         *     https://your.site/upload/SOME-PAGE-URL                  to upload a page instead of existing one
         *     https://your.site/download/SOME-PAGE-URL                to download a page file
         *     https://your.site/markup                                to mark up a new page manually
         *     https://your.site/markup/SOME-PAGE-URL                  to remark up a page manually
         *     https://your.site/construct                             to construct a new page
         *     https://your.site/construct/SOME-PAGE-URL               to reconstruct a page
         *
         *     https://your.site/styles                                to view a list of CSS files
         *     https://your.site/styles/add                            to add a new CSS file
         *     https://your.site/styles/add/SOME-STYLE-URL             to add a new CSS file if such URL is not already taken
         *     https://your.site/styles/copy/SOME-STYLE-URL            to copy a CSS file
         *     https://your.site/styles/delete/SOME-STYLE-URL          to delete a CSS file
         *     https://your.site/styles/edit/SOME-STYLE-URL            to edit a CSS file
         *     https://your.site/styles/upload                         to upload a new CSS file
         *     https://your.site/styles/upload/SOME-STYLE-URL          to upload a CSS file instead of existing one
         *     https://your.site/styles/download/SOME-STYLE-URL        to download a CSS file
         *
         *     https://your.site/bbcodes                               to view a list of bbCode files
         *     https://your.site/bbcodes/add                           to add a new bbCode file
         *     https://your.site/bbcodes/add/SOME-BBCODE-URL           to add a new bbCode file if such URL is not already taken
         *     https://your.site/bbcodes/copy/SOME-BBCODE-URL          to copy a bbCode file
         *     https://your.site/bbcodes/delete/SOME-BBCODE-URL        to delete a bbCode file
         *     https://your.site/bbcodes/edit/SOME-BBCODE-URL          to edit a bbCode file
         *     https://your.site/bbcodes/upload                        to upload a new bbCode file
         *     https://your.site/bbcodes/upload/SOME-BBCODE-URL        to upload a bbCode file instead of existing one
         *     https://your.site/bbcodes/download/SOME-BBCODE-URL      to download a bbCode file
         *
         *     https://your.site/fragments                             to view a list of Fragment files
         *     https://your.site/fragments/add                         to add a new Fragment file
         *     https://your.site/fragments/add/SOME-FRAGMENT-URL       to add a new Fragment file if such URL is not already taken
         *     https://your.site/fragments/copy/SOME-FRAGMENT-URL      to copy a Fragment file
         *     https://your.site/fragments/delete/SOME-FRAGMENT-URL    to delete a Fragment file
         *     https://your.site/fragments/edit/SOME-FRAGMENT-URL      to edit a Fragment file
         *     https://your.site/fragments/upload                      to upload a new Fragment file
         *     https://your.site/fragments/upload/SOME-FRAGMENT-URL    to upload a Fragment file instead of existing one
         *     https://your.site/fragments/download/SOME-FRAGMENT-URL  to download a Fragment file
         *
         * The remaining URLs are routed to a special error template:
         *
         *     https://your.site/add/ALREADY-EXISTING-PAGE-URL                to view the Error409 page
         *     https://your.site/styles/add/ALREADY-EXISTING-STYLE-URL        to view the Error409 page
         *     https://your.site/bbcodes/add/ALREADY-EXISTING-BBCODE-URL      to view the Error409 page
         *     https://your.site/fragments/add/ALREADY-EXISTING-FRAGMENT-URL  to view the Error409 page
         *     https://your.site/UNDEFINED-URL                                to view the Error404 page
         *
         * -----------------------------------------------------------------
         *
         * @public
         * @param   string  $dummy  (optional) It is always an empty string.
         * @return  void
         *
         * -----------------------------------------------------------------
         */

        public function run ( $dummy = '' ) {
            $template = 'error-404.tpl';
            $data     = FALSE;
            $url      = mimimiUri ( FALSE );
            switch ( $url ) {
                case '':
                     $data     = $this->database->pages->run ( );
                     $template = $data != '' ? 'page.tpl'
                                             : 'welcome.tpl';
                     break;
                case 'toc':
                case 'credits':
                     $data     = $this->database->pages->run ( $url );
                     $template = $data != '' ? 'page.tpl'
                                             : ( $url . '.tpl' );
                     break;
                case 'login':
                     $template = 'login.tpl';
                     break;
                case 'robots.txt':
                     $template = 'robots.tpl';
                     break;
                case 'sitemap.xml':
                     $data     = $this->database->pages->getMap ( );
                     $template = 'sitemap.tpl';
                     break;
                case 'logout':
                case 'bbcodes':
                case 'fragments':
                case 'styles':
                case 'pages':
                case 'settings':
                     $template = $this->amIAdmin ( ) ? 'dashboard/' . $url . '.tpl'
                                                     : $template;
                     break;
                case 'add':
                case 'upload':
                     $template = $this->amIAdmin ( ) ? 'dashboard/pages-' . $url . '.tpl'
                                                     : $template;
                     break;
                case 'bbcodes/add':
                case 'bbcodes/upload':
                case 'fragments/add':
                case 'fragments/upload':
                case 'styles/add':
                case 'styles/upload':
                     $template = $this->amIAdmin ( ) ? 'dashboard/' . str_replace ( '/', '-', $url ) . '.tpl'
                                                     : $template;
                     break;
                default:
                     $type = $this->url->getSegment ( $url );
                     switch ( $type ) {
                         case 'bbcodes':
                         case 'fragments':
                         case 'styles':
                              $this->url->cutSegment ( $url );
                              break;
                         default:
                              $type = 'pages';
                     }
                     $command = $this->url->getSegment ( $url );
                     switch ( $command ) {
                         case 'add':
                              if ( $this->amIAdmin ( ) ) {
                                  $this->url->cutSegment ( $url );
                                  $data     = $this->database->$type->run ( $url );
                                  $template = $data == '' ? 'dashboard/' . $type . '-' . $command . '.tpl'
                                                          : 'error-409.tpl';
                              }
                              break;
                         case 'upload':
                              $template = $this->amIAdmin ( ) ? 'dashboard/' . $type . '-' . $command . '.tpl'
                                                              : $template;
                              break;
                         case 'download':
                              if ( $this->amIAdmin ( ) ) {
                                  $this->url->cutSegment ( $url );
                                  $this->database->$type->download ( $url );    // the flow will be stopped in this line if successful
                              }
                              break;
                         case 'construct':
                         case 'markup':
                              if ( $this->amIAdmin ( ) ) {
                                  if ( $type == 'pages' ) {
                                      $this->url->cutSegment ( $url );
                                      $data     = $this->database->$type->run ( $url );
                                      $template = 'dashboard/' . $type . '-' . $command . '.tpl';
                                  }
                              }
                              break;
                         case 'copy':
                         case 'delete':
                         case 'edit':
                              if ( $this->amIAdmin ( ) ) {
                                  $this->url->cutSegment ( $url );
                                  $data     = $this->database->$type->run ( $url );
                                  $template = $data != '' ? 'dashboard/' . $type . '-' . $command . '.tpl'
                                                          : $template;
                              }
                              break;
                         default:
                              switch ( $type ) {
                                  case 'pages':
                                       $data     = $this->database->$type->run ( $url );
                                       $template = $data != '' ? 'page.tpl'
                                                               : $template;
                                       break;
                              }
                     }
            }
            $this->render ( $template, $data );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Renders a template file by passing some data to it.
         *
         * -----------------------------------------------------------------
         *
         * @public
         * @param   string  $template  The relative name of the template file to be rendered.
         * @param   mixed   $data      (optional) Data that will be passed to the template file as a global variable $params.
         * @return  void
         *
         * -----------------------------------------------------------------
         */

        public function render ( $template, $data = FALSE ) {
            if ( $this->helper->run ( $template ) ) {
                mimimiModule ( [ $template, $data ] );
                return;
            }
            mimimiStop ( 'Error: Template for this page is not found!' );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Retrieves a label identifying the current visitor.
         *
         * -----------------------------------------------------------------
         *
         * Note that we compute this label as the MD5-hashed IP to prevent
         * session hijacking by spoofing its ID (for more details, see the
         * amIAdmin() method below).
         *
         * -----------------------------------------------------------------
         *
         * @public
         * @return  string
         *
         * -----------------------------------------------------------------
         */

        public function getMyLabel ( ) {
            $ip  = mimimiServer ( 'REMOTE_ADDR' );
            return md5 ( $ip );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Retrieves a label identifying the last admin.
         *
         * -----------------------------------------------------------------
         *
         * @public
         * @return  string|null  A string label if that admin is still online.
         *                       EMPTY STRING   if that admin is already logged out.
         *                       NULL           if there is no last admin.
         *
         * -----------------------------------------------------------------
         */

        public function getAdminLabel ( ) {
            $this->session->run ( STATICPAGESONLY_SESSION_MODE );
            return $this->session->get ( 'adminLabel', NULL );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Stores a label identifying the last admin.
         *
         * -----------------------------------------------------------------
         *
         * @public
         * @param   string  $label  A label to be saved.
         * @return  void
         *
         * -----------------------------------------------------------------
         */

        public function setAdminLabel ( $label ) {
            $this->session->run ( STATICPAGESONLY_SESSION_MODE );
            $this->session->set ( 'adminLabel', $label );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Retrieves the last timeout period.
         *
         * -----------------------------------------------------------------
         *
         * @public
         * @param   string  $type  Name of the timeout type.
         * @return  int            Time stamp for the expiration of this period.
         *
         * -----------------------------------------------------------------
         */

        public function getTimeout ( $type ) {
            $this->session->run ( STATICPAGESONLY_SESSION_MODE );
            return $this->session->get ( 'activityTimeout_' . $type, time ( ) );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Stores a new timeout period.
         *
         * -----------------------------------------------------------------
         *
         * @public
         * @param   string  $type   Name of the timeout type.
         * @param   int     $pause  A timer in seconds.
         * @return  void
         *
         * -----------------------------------------------------------------
         */

        public function setTimeout ( $type, $pause ) {
            $this->session->run ( STATICPAGESONLY_SESSION_MODE );
            $this->session->set ( 'activityTimeout_' . $type, time ( ) + $pause );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Returns the MD5 hash of a password.
         *
         * -----------------------------------------------------------------
         *
         * @public
         * @param   string  $pass  A password to be hashed.
         * @return  string
         *
         * -----------------------------------------------------------------
         */

        public function computeHash ( $pass ) {
            return md5 ( $pass );
        }

        /**
         * -----------------------------------------------------------------
         *
         * Checks if the current visitor is an administrator.
         *
         * -----------------------------------------------------------------
         *
         * Note that in demo mode, any visitor is considered Admin if he
         * visits your site for the first time. We detect this case by
         * matching the admin label against a NULL value.
         *
         * -----------------------------------------------------------------
         *
         * @public
         * @return  bool
         *
         * -----------------------------------------------------------------
         */

        public function amIAdmin ( ) {
            $my    = $this->getMyLabel    ( );
            $label = $this->getAdminLabel ( );
            if ( $label === NULL ) {
                $label = STATICPAGESONLY_DEMO_MODE ? $my
                                                   : '';
                $this->getAdminLabel ( $label );
            }
            return $label === $my;
        }

        /**
         * -----------------------------------------------------------------
         *
         * Reset the namespace simulator if you want to provide an ability
         * to extend this application with child modules that perform
         * various functions.
         *
         * According to the application structure, you will need at least
         * 2 child modules (Database, Helper):
         *
         *     static.pages.only/Database/Database.php  -->  to collect modules that working with the "database"
         *     static.pages.only/Helper/Helper.php      -->  to provide specific routines for site template files
         *
         * -----------------------------------------------------------------
         *
         * @var    string
         * @access protected
         *
         * -----------------------------------------------------------------
         */

        protected $myNodeFile = __FILE__;
    };
