<?php
/**
 * -------------------------------------------------------------------------
 * Basis for system modules having an umbrella structure.
 *
 * In the simplest case, the application being developed consists of two
 * layers. Such an application represents the imaginary first layer of
 * development. This app is an umbrella node for all callable modules,
 * which are the imaginary second layer.
 *
 * For example:
 *
 *     $someApp ─┬──> someModule1 ──> someMethod()
 *               ├──> someModule2 ──> someMethod()
 *               ├──> someModule3 ──> someMethod()
 *               └──> someModule4 ──> someMethod()
 *
 * These modules are derived from the MimimiModule class. And they are
 * each in their own subfolder, in the same place where the application
 * source file is located.
 *
 * In more complex development cases, it is necessary to be able to make
 * an arbitrary module of the second layer look like an umbrella node.
 *
 * For example:
 *
 *     $someApp ─┬──> someModule1 ──> someMethod()
 *               ├──> someModule2 ─┬──> someModuleA ──> someMethod()
 *               │                 ├──> someModuleB ──> someMethod()
 *               │                 └──> someModuleC ──> someMethod()
 *               ├──> someModule3 ──> someMethod()
 *               └──> someModule4 ──> someMethod()
 *
 * Such a module must derive from the MimimiUmbrellaModuleWithTable or
 * MimimiUmbrellaModule class. And all the modules it calls are located each
 * in its own subfolder, in the same place where the umbrella module source
 * file is located.
 *
 * -------------------------------------------------------------------------
 *
 * Implemented properties below are:
 *     PROTECTED  $myUmbrellaFile
 *
 * Overridden methods below are:
 *     __construct
 *
 * Implemented methods below are:
 *     __get
 *     getUmbrellaPath
 *
 * -------------------------------------------------------------------------
 *
 * @package    MimimiFramework
 * @subpackage Core
 * @copyright  2022 MiMiMi Community
 *             https://mimimi.software/
 * @license    CC BY 4
 *             https://www.creativecommons.org/licenses/by/4.0
 * -------------------------------------------------------------------------
 */

mimimiInclude('Module.php');
class MimimiUmbrellaModule extends MimimiModule {

    /**
     * ---------------------------------------------------------------------
     * Full filename of this script file.
     *
     * This property only applies to umbrella modules. Remember that the
     * property must be reset in the same way in all files declaring the
     * class of the new umbrella module.
     *
     * @var string
     * @access protected
     * ---------------------------------------------------------------------
     */

    protected $myUmbrellaFile = __FILE__;

    /**
     * ---------------------------------------------------------------------
     * Creates this module.
     *
     * First we execute the same method of the parent class. We then clone
     * the HAS module that belongs to the master node (which is the nearest
     * umbrella module). And in this clone, we will reassign that our module
     * are now the master node for all modules nested in its node. That is,
     * we become an umbrella module in relation to child modules.
     *
     * @public
     * @return  void
     * ---------------------------------------------------------------------
     */

    public function __construct ( & $owner = false ) {
        parent::__construct($owner);
        if ($this->umbrella) {
            $this->has = clone $this->umbrella->has;
            $this->has->umbrella = $this;
        }
    }

    /**
     * ---------------------------------------------------------------------
     * Loads the same module into a non-existent property.
     *
     * @public
     * @param   string       $property  Name of the property.
     * @return  object|bool             Reference to the loaded module
     *                                            if success,
     *                                  False if this property exists
     *                                        and it is protected or private.
     * ---------------------------------------------------------------------
     */

    public function __get ( $property ) {
        return isset($this->$property)
               ? false
               : mimimiCreate($property, $this);
    }

    /**
     * ---------------------------------------------------------------------
     * Retrieves the relative directory of this module.
     *
     * @public
     * @param   int     $offcut  ON EXIT: The number of cut left parts
     *                                    from the full directory.
     * @return  string           Relative directory (from the website root).
     * ---------------------------------------------------------------------
     */

    public function getUmbrellaPath ( & $offcut = 0 ) {
        $offcut = 0;
        $path = '';
        $pieces = preg_split('~[/\\\\]~u', $this->myUmbrellaFile);
        if ($pieces) {
            array_pop($pieces);
            if ($pieces) {
                $path = array_pop($pieces) . '/';
                $offcut = count($pieces);
                if ($this->cms) {
                    $this->cms->getUmbrellaPath($offcut);
                    while (count($pieces) > $offcut) {
                        $path = array_pop($pieces) . '/' . $path;
                    }
                }
            }
        }
        return $path;
    }
};