<?php

use Carbon\Carbon;


/**
 * CONTENT MANAGER NAVIGATION CLASS
 * Class for generating navigation for the cms in the frontend templates and backend panels.
 * See more: http://wiki.mtcmedia.co.uk/index.php?title=CMS2#Navigation
 * @copyright MTC media Ltd
 * @author Rihards Silins
 * @version 2 20/08/2015
 */
class CMSNav
{

    /**
     * CMSNav::tree()
     *
     * @param int id
     * @param int limit = PHP_INT_MAX
     * @param mixed[] options = array()
     * @return mixed[][]
     *
     * Generates a array tree with any info needed
     * for a navigation menu. Enter 0 as id to get complete site tree
     */
    public static function tree($id = 0, $limit = PHP_INT_MAX, $options = array())
    {

        if (!isset($options['check_innav'])) {
            $options['check_innav'] = true;
        }

        if (!isset($options['check_published'])) {
            $options['check_published'] = true;
        }

        if (!isset($options['check_searchable'])) {
            $options['check_searchable'] = false;
        }

        if (!isset($options['check_hide_in_cms'])) {
            $options['check_hide_in_cms'] = false;
        }

        if (!isset($options['cache'])) {
            $options['cache'] = TREE_CACHE;
        }

        if (!isset($options['language'])) {
            $options['language'] = "";
            if (defined('CMS_MULTI_LANG') && CMS_MULTI_LANG === true && CMS_MULTI_LANG_OTHER_DEFAULT_TO_P_LANGUAGE === true) {
                global $p;
                if (!empty($p->language)) {
                    $options['language'] = $p->language;
                }
            }
        }

        if ($limit <= 0) {
            return array();
        }


        if (TREE_CACHE && $options['cache']) {

            $setup = array(
                'id' => $id,
                'limit' => $limit,
                'options' => $options
            );

            $setup = serialize($setup);

            $treeCache = \Mtc\Cms\Models\TreeCache::query()
                ->where('setup', $setup)
                ->firstOrNew();

            if (
                !empty($treeCache->id) &&
                (
                    TREE_CACHE_SECONDS === 0 ||
                    (time() - strtotime($treeCache->timestamp)) < TREE_CACHE_SECONDS
                )
            ) {
                return unserialize($treeCache->object);
            }

            $tree = CMSNav::_tree($id, $limit, $options);
            $treeCache->object = serialize($tree);
            $treeCache->setup = $setup;
            $treeCache->timestamp = Carbon::now();
            $treeCache->save();
            return $tree;

        }
        return CMSNav::_tree($id, $limit, $options);
    }

    /**
     * CMSNav::_tree()
     *
     * @param int id
     * @param int limit = PHP_INT_MAX
     * @param mixed[] options = array()
     * @return mixed[][]
     *
     * Generates a array tree with any info needed
     * for a navigation menu. Enter 0 as id to get complete site tree
     *
     */
    public static function _tree($id = 0, $limit = PHP_INT_MAX, $options = array())
    {

        if ($limit <= 0) {
            return array();
        }

        $limit = $limit - 1;
        $pages = \Mtc\Cms\Models\Page::query()
            ->where('sub_id', $id)
            ->where('type', 'default')
            ->orderBy('order')
            ->when(!empty($options['check_innav']), function ($query) {
                $query->where('innav', 1);
            })
            ->when(!empty($options['check_published']), function ($query) {
                $query->where('published', 1);
            })
            ->when(!empty($options['check_searchable']), function ($query) {
                $query->where('searchable', 1);
            })
            ->when(!empty($options['check_hide_in_cms']), function ($query) {
                $query->where('hide_in_cms', 1);
            })
            ->get();

        if ($pages->count() === 0) {
            return [];
        }
        $children = [];

        // It has children, let's get them.
        foreach ($pages as $page) {
            $row = $page->toArray();
            // Add the child to the list of children, and get its subchildren
            $children[$row['id']]['id'] = $row['id'];
            $children[$row['id']]['title'] = $row['title'];

            if (defined('CMS_MULTI_LANG') && CMS_MULTI_LANG === true) {
                if (CMS_MULTI_LANG_PAGE_TITLE_IN_JSON === true) {
                    $children[$row['id']]['title'] = Page::getValueFromLanguageJSON($children[$row['id']]['title'], $options['language']);
                }
            }

            $children[$row['id']]['link'] = Page::generate_url($row['id'], null, $options['language']);
            $children[$row['id']]['sub'] = CMSNav::_tree($row['id'], $limit, $options);
        }
        return $children;
    }

    /**
     * CMSNav::generateMenu()
     *
     * @param mixed[][] tree
     * @param mixed[][] options
     *
     * Generates a basic menu from given page tree
     *
     *     <{container_tag} CLASS="{container_class} ?{first_container_class}?" ?ID="{first_container_id}"?>
     *         {BEFORE ITEM}
     *        <{item_container_tag} CLASS="{item_container_class} {first_item_container_class}?" ID="{item_container_id_prefix}">
     *            <A>
     *                <{title_container_tag}>
     *                    {before_title}
     *                        [title]
     *                    {after_title}
     *                </{title_container_tag}>
     *            </A>
     *        </{item_container_tag}>
     *        {AFTER ITEM}
     *    </{container_tag}>
     *
     * TODO: instead of echoing, store to string
     *
     */
    public static function generateMenu($tree, $options = array())
    {

        // Option Setup

        // HOW DEEP IN SUBS TO GO
        if (!isset($options['limit']) || empty($options['limit'])) {
            $options['limit'] = PHP_INT_MAX;
        }

        // DUE TO DEMAND
        // WEATHER OR NOT TO ADD THE FIRST CONTAINER (<UL>...</UL>)
        // DOES NOT APPLY TO SUB CONAINERS  (<LI><UL>...</UL></LI>...)
        if (!isset($options['hide_first_container']) || empty($options['hide_first_container'])) {
            $options['hide_first_container'] = false;
        }

        // THE ID OF THE FIRST/PARENT CONTAINER (UL) (MIGHT ALSO NOT BE UL)
        if (!isset($options['first_container_id']) || empty($options['first_container_id'])) {
            $options['first_container_id'] = '';
        }

        // THE ID OF THE FIRST/PARENT CONTAINER (UL) (MIGHT ALSO NOT BE UL)
        if (!isset($options['first_container_class']) || empty($options['first_container_class'])) {
            $options['first_container_class'] = '';
        }

        // THE TAG OF THE CONTAINER (DEFAULT: UL)
        if (!isset($options['container_tag']) || empty($options['container_tag'])) {
            $options['container_tag'] = 'ul';
        }

        // THE CLASS OF ALL CONTAINERS (UL) (MIGHT ALSO NOT BE UL)
        if (!isset($options['container_class']) || empty($options['container_class'])) {
            $options['container_class'] = '';
        }

        // THE TAG OF THE around CONTAINER (DEFAULT: "")
        if (!isset($options['around_container_tag']) || empty($options['around_container_tag'])) {
            $options['around_container_tag'] = '';
        }

        // THE CLASS OF ALL around CONTAINERS (DEFAULT: "")
        if (!isset($options['around_container_class']) || empty($options['around_container_class'])) {
            $options['around_container_class'] = '';
        }

        /*
        // THE ID PREFIX OF ALL CONTAINERS (UL) (MIGHT ALSO NOT BE UL)
        if ( !isset($options['container_id_prefix']) || empty($options['container_id_prefix']) ) {
            $options['container_id_prefix'] = '';
        }
        */

        // THE TAG OF ALL THE ITEM CONTAINERS (DEFAULT: LI)
        if (!isset($options['item_container_tag']) || empty($options['item_container_tag'])) {
            $options['item_container_tag'] = 'li';
        }

        // THE CLASS OF ALL THE ITEM CONTAINERS (DEFAULT: LI)
        if (!isset($options['item_container_class']) || empty($options['item_container_class'])) {
            $options['item_container_class'] = '';
        }

        // THE ID PREFIX OF ALL OF THE ITEM CONTAINERS (LI)
        if (!isset($options['item_container_id_prefix']) || empty($options['item_container_id_prefix'])) {
            $options['item_container_id_prefix'] = 'item';
        }


        // THE CLASS OF ALL THE FIRST ( 1ST DEPTH ) ITEM CONTAINERS (LI)
        if (!isset($options['first_item_container_class']) || empty($options['first_item_container_class'])) {
            $options['first_item_container_class'] = '';
        }

        // THE TAG OF TITLE CONTAINERS (MIGHT BE SOMETIHNG LIKE A SPAN)
        if (!isset($options['title_container_tag']) || empty($options['title_container_tag'])) {
            $options['title_container_tag'] = '';
        }


        // THE HTML WITHIN THE <A> BEFORE THE TITLE
        if (!isset($options['before_title']) || empty($options['before_title'])) {
            $options['before_title'] = '';
        }

        // THE HTML WITHIN THE <A> AFTER THE TITLE
        if (!isset($options['after_title']) || empty($options['after_title'])) {
            $options['after_title'] = '';
        }


        // THE HTML BEFORE EACH ITEM CONTAINER (LI)
        if (!isset($options['before_item']) || empty($options['before_item'])) {
            $options['before_item'] = '';
        }

        // THE HTML AFTER EACH ITEM CONTAINER (LI)
        if (!isset($options['after_item']) || empty($options['after_item'])) {
            $options['after_item'] = '';
        }

        // THE HTML BEFORE EACH anchor
        if (!isset($options['before_anchor']) || empty($options['before_anchor'])) {
            $options['before_anchor'] = '';
        }

        // THE HTML AFTER EACH anchor
        if (!isset($options['after_anchor']) || empty($options['after_anchor'])) {
            $options['after_anchor'] = '';
        }

        // THE ID OF THE ACTIVE PAGE <- REALLY SHOULD BE ADDED
        if (!isset($options['active_page_id']) || empty($options['active_page_id'])) {
            $options['active_page_id'] = '';
        }

        // THE TRAIL TO THE ACTIVE PAGE <- REALLY SHOULD BE ADDED
        if (!isset($options['active_page_trail']) || empty($options['active_page_trail'])) {
            $options['active_page_trail'] = array();
        }

        // WETHER TO ECHO THE PRODUCED MENU OR NOT
        if (!isset($options['echo'])) {
            $options['echo'] = false;
        }

        // WETHER TO RETURN HTML
        if (!isset($options['return_html'])) {
            $options['return_html'] = true;
        }

        ob_start();
        self::generateMenuRecursive($tree, 0, $options['limit'], $options);
        $result = ob_get_contents();
        ob_end_clean();
        if ($options['echo'] === true) {
            echo $result;
        }
        if ($options['return_html'] === true) {
            return $result;
        }
    }

    /**
     * CMSNav::generateMenuRecursive()
     *
     * @param Array[][] tree, int limit
     *
     * Recursive function that is called by CMSNav::generateMenu()
     */
    public static function generateMenuRecursive($tree, $depth, $limit, $options)
    {

        if (count($tree) > 0 && $limit > 0) {

            $depth = $depth + 1;
            $limit = $limit - 1;

            echo '
';

            if (!empty($options['around_container_tag'])) {
                /// The wrapper around container ///
                // By default ""
                $tag = $options['around_container_tag'];

                // By defaut $options['around_container_class'] empty
                $class = "";
                $class .= $options['around_container_class'];

                echo '<' . $tag . ' ' . (!empty($class) ? 'class="' . $class . '"' : '') . '>';
            }

            /// The list container
            // By default <ul>
            $tag = $options['container_tag'];

            // Containers by default have empty id
            // unless its the first container && options['first_container_id'] is set
            $id = "";
            if ($depth === 1) {
                $id .= $options['first_container_id'];
            }

            // By defaut $options['container_class'];
            // Also $options['first_container_class'] if first container and not empty
            $class = "";
            $class .= $options['container_class'];
            if ($depth === 1) {
                if (!empty($class)) {
                    $class .= " ";
                }
                $class .= $options['first_container_class'];
            }

            if ($depth > 1 || $options['hide_first_container'] === false) {
                echo '<' . $tag . ' ' . (!empty($id) ? 'id="' . $id . '"' : '') . ' ' . (!empty($class) ? 'class="' . $class . '"' : '') . '>';
            }

            foreach ($tree as $item) {

                // WHATEVER USER WISHES TO ADD BEFORE <LI>
                echo $options['before_item'];

                /// The list item ///
                // By default <li>
                $tag = $options['item_container_tag'];

                // Containers by default have item_{$item_id} id
                // unless $options['item_container_id_prefix'] is empty
                $id = "";
                if (!empty($options['item_container_id_prefix'])) {
                    $id .= $options['item_container_id_prefix'] . "_" . $item['id'];
                }

                // By defaut $options['container_class'];
                // Also $options['first_container_class'] if first container and not empty
                $class = "";
                if ($options['active_page_id'] == $item['id']) {
                    $class .= "active";
                }
                if ($depth === 1) {
                    if (!empty($class)) {
                        $class .= " ";
                    }
                    $class .= $options['first_item_container_class'];
                }
                if (!empty($options['active_page_trail']) && Page::id_in_trail($item['id'], $options['active_page_trail'])) {
                    if (!empty($class)) {
                        $class .= " ";
                    }
                    $class .= "childActive";
                }
                if (!empty($item['sub'])) {
                    if (!empty($class)) {
                        $class .= " ";
                    }
                    $class .= "hasChildren";
                }
                if (!empty($class)) {
                    $class .= " ";
                }
                $class .= $options['item_container_class'];

                echo '
    ';

                echo '<' . $tag . ' ' . (!empty($id) ? 'id="' . $id . '"' : '') . ' ' . (!empty($class) ? 'class="' . $class . '"' : '') . '>';

                // Before anchor
                echo $options['before_anchor'];

                if (!empty($item['link'])) {

                    /// THE <A> (LINK/ACHOR) ///
                    $id = "";
                    if (!empty($options['item_container_id_prefix'])) {
                        $id .= $options['item_container_id_prefix'] . "_" . $item['id'] . "_a";
                    }

                    $class = "";
                    if ($options['active_page_id'] == $item['id']) {
                        $class .= "active";
                    }
                    if (!empty($options['active_page_trail']) && Page::id_in_trail($item['id'], $options['active_page_trail'])) {
                        if (!empty($class)) {
                            $class .= " ";
                        }
                        $class .= "childActive";
                    }

                    echo '
        ';

                    $additional_anchor_attributes = "";
                    if (!empty($item['anchor_attributes'])) {
                        foreach ($item['anchor_attributes'] as $attribute => $attribute_value) {
                            $additional_anchor_attributes .= ' ' . $attribute . '="' . $attribute_value . '" ';
                        }
                    }

                    echo '<a ' . (!empty($id) ? 'id="' . $id . '"' : '') . ' ' . (!empty($class) ? 'class="' . $class . '"' : '') . ' title="' . strip_tags($item['title']) . '" href="' . $item['link'] . '" ' . $additional_anchor_attributes . ' >';


                    echo '
            ';

                }

                // SOMETHING LIKE A <SPAN> OR SOMETHING ELSE THAT MIGHT BE ARROUND THE TITLE/NAME
                if (!empty($options['title_container_tag'])) {
                    echo "<" . $options['title_container_tag'] . ">";
                }


                echo $options['before_title']; // SOMETHING LIKE AN ARROW OR SOMETHING ELSE YOU MIGHT WANT TO PUT RIGHT  B E F O R E  TITLE WITHIN <A> AND <SPAN>

                if (isset($item['replacement_title'])) {

                    echo $item['replacement_title'];

                } else {

                    echo $item['title']; // THE TITLE ITSELF

                }

                echo $options['after_title']; // SOMETHING LIKE AN ARROW OR SOMETHING ELSE YOU MIGHT WANT TO PUT RIGHT  A F T E R  TITLE WITHIN <A> AND <SPAN>


                // SOMETHING LIKE A <SPAN> OR SOMETHING ELSE THAT MIGHT BE ARROUND THE TITLE/NAME
                if (!empty($options['title_container_tag'])) {
                    echo "</" . $options['title_container_tag'] . ">";
                }

                // end of THE <A></A>
                if (!empty($item['link'])) {

                    echo '
        ';
                    echo "</a>";
                }

                // After anchor
                echo $options['after_anchor'];

                // IF CHILDREN - INSERT SUBMENU WITH ALL ITS <UL><LI></LI><LI></LI>....
                if (count($item['sub']) > 0) {
                    self::generateMenuRecursive($item['sub'], $depth, $limit, $options);
                }

                /// The list item ///
                // By default <li>
                $tag = $options['item_container_tag'];
                // end of THE <LI></LI> (MIGHT ALSO NOT BE SPECIFICALLY LI)
                echo '
    ';
                echo "</" . $tag . ">";

                // WHATEVER USER WISHES TO ADD AFTER <LI>
                echo $options['after_item'];

            }


            $tag = $options['container_tag'];
            echo '
';

            if ($depth > 1 || $options['hide_first_container'] === false) {
                // end of THE <UL> (MIGHT ALSO NOT BE SPECIFICALLY UL)
                /// The list container ///
                // By default <ul>
                echo "</" . $tag . ">";
            }

            if (!empty($options['around_container_tag'])) {
                /// The wrapper around container ///
                // By default ""
                $tag = $options['around_container_tag'];

                echo '</' . $tag . '>';
            }

        }

    }


    /**
     * CMSNav::generateBreadcrumbs()
     *
     * @param mixed[][] trail,
     * @param mixed[][] options
     *
     * Generates a breadgrumbs from given page array
     *
     * TODO: instead of echoing, store to string
     *
     */
    public static function generateBreadcrumbs($trail, $options = array())
    {

        // Option Setup

        if (!isset($options['container_tag']) || empty($options['container_tag'])) {
            $options['container_tag'] = 'ul';
        }

        if (!isset($options['container_class']) || empty($options['container_class'])) {
            $options['container_class'] = '';
        }

        if (!isset($options['container_id']) || empty($options['container_id'])) {
            $options['container_id'] = '';
        }


        if (!isset($options['item_container_tag']) || empty($options['item_container_tag'])) {
            $options['item_container_tag'] = 'li';
        }

        if (!isset($options['item_container_class']) || empty($options['item_container_class'])) {
            $options['item_container_class'] = '';
        }

        if (!isset($options['item_container_id_prefix']) || empty($options['item_container_id_prefix'])) {
            $options['item_container_id_prefix'] = 'crumb';
        }


        if (!isset($options['title_container_tag']) || empty($options['title_container_tag'])) {
            $options['title_container_tag'] = '';
        }

        if (!isset($options['title_container_class']) || empty($options['title_container_class'])) {
            $options['title_container_class'] = '';
        }

        if (!isset($options['title_container_id_prefix']) || empty($options['title_container_id_prefix'])) {
            $options['title_container_id_prefix'] = '';
        }


        if (!isset($options['after_title']) || empty($options['after_title'])) {
            $options['after_title'] = '';
        }

        if (!isset($options['before_title']) || empty($options['before_title'])) {
            $options['before_title'] = '';
        }


        if (!isset($options['after_item']) || empty($options['after_item'])) {
            $options['after_item'] = '';
        }

        if (!isset($options['before_item']) || empty($options['before_item'])) {
            $options['before_item'] = '';
        }


        if (!isset($options['active_page_id']) || empty($options['active_page_id'])) {
            $options['active_page_id'] = '';
        }


        if (!isset($options['include_redchild']) || empty($options['include_redchild'])) {
            $options['include_redchild'] = true;
        }

        if (!isset($options['echo']) || empty($options['echo'])) {
            $options['echo'] = false;
        }


        // HTML Build Start

        $html = "";

        $html .= "<" . $options['container_tag'] . " id='" . $options['container_id'] . "' class='" . $options['container_class'] . "' >";

        $depth = 0;

        foreach ($trail as $item) {

            if (!$options['include_redchild'] && $item->redchild == 1) {
                continue;
            }

            $html .= $options['before_item'];

            $html .= "<" . $options['item_container_tag'] . " class='" . $options['item_container_class'] . ($options['active_page_id'] == $item->id ? ' active' : '') . "' id='" . $options['item_container_id_prefix'] . "_" . $item->id . "'>";

            $html .= "<a class='" . ($options['current_page_id'] == $item->id ? 'active' : '') . "' id='" . $options['item_container_id_prefix'] . "_" . $item->id . "' title='" . $item->title . "' href='" . $item->get_url() . "'>";

            $html .= $options['before_title'];

            if (!empty($options['title_container_tag'])) {
                $html .= "<" . $options['title_container_tag'] . " class='" . $options['title_container_class'] . ($options['active_page_id'] == $item->id ? ' active' : '') . "' id='" . $options['title_container_id_prefix'] . "_" . $item->id . "'>";
            }

            $html .= $item->title;

            if (!empty($options['title_container_tag'])) {
                $html .= "</" . $options['title_container_tag'] . ">";
            }

            $html .= $options['after_title'];

            $html .= "</a>";

            $html .= "</" . $options['item_container_tag'] . ">";

            $html .= $options['after_item'];

            $depth++;

        }

        $html .= "</" . $options['container_tag'] . ">";

        // RESULT

        if ($options['echo']) {
            echo $html;
        }

        return $html;

    }


    /**
     * CMSNav::siteTree()
     *
     * @param int id
     * @param int limit = PHP_INT_MAX
     * @param mixed[] options = array()
     * @return mixed[][]
     *
     * Generates a array siteTree with any info needed
     * for a navigation menu. Enter 0 as id to get complete site siteTree
     *
     */
    public static function siteTree($id = 0, $limit = PHP_INT_MAX, $options = array())
    {

        if (!isset($options['check_innav'])) {
            $options['check_innav'] = true;
        }

        if (!isset($options['check_published'])) {
            $options['check_published'] = true;
        }

        if (!isset($options['buttons'])) {
            $options['buttons'] = true;
        }

        if ($limit <= 0) {
            return [];
        }
        $limit = $limit - 1;

        $pages = \Mtc\Cms\Models\Page::query()
            ->where('sub_id', $id)
            ->where('type', '!=', 'temp')
            ->where('type', '!=', 'history')
            ->when($options['check_innav'], function ($query) {
                $query->where('innav', 1);
            })
            ->when($options['check_published'], function ($query) {
                $query->where('published', 1);
            })
            ->when($options['buttons'], function ($query) {
                $query->where('type', '!=', 'button');
            })
            ->orderBy('order')
            ->get();

        if ($pages->count() === 0) {
            return [];
        }

        $children = [];

        // It has children, let's get them.
        foreach ($pages as $page) {
            $row = $page->toArray();
            // Add the child to the list of children, and get its subchildren
            $children[$row['id']]['id'] = $row['id'];
            $children[$row['id']]['type'] = $row['type'];
            $children[$row['id']]['slug'] = $row['slug'];
            $children[$row['id']]['listing_container'] = $row['listing_container'];
            $children[$row['id']]['hide_in_cms'] = $row['hide_in_cms'];
            $children[$row['id']]['published'] = $row['published'];
            $children[$row['id']]['lock'] = $row['lock'];
            $children[$row['id']]['frontpage'] = $row['frontpage'];
            $children[$row['id']]['title'] = $row['title'];
            $children[$row['id']]['data3'] = $row['data3'];
            if (defined('CMS_MULTI_LANG') && CMS_MULTI_LANG === true) {
                if (CMS_MULTI_LANG_PAGE_TITLE_IN_JSON === true) {
                    $children[$row['id']]['title'] = Page::getValueFromLanguageJSON($children[$row['id']]['title'], "");
                }
            }
            $children[$row['id']]['link'] = Page::generate_url($row['id']);
            $children[$row['id']]['sub'] = CMSNav::siteTree($row['id'], $limit, $options);
        }
        return $children;
    }

    /**
     * CMSNav::generateSiteTreeMenu()
     *
     * @param mixed[][] tree
     * @param mixed[] options
     *
     * Generates a basic menu from given page tree
     *
     *     <{container_tag} CLASS="{container_class}" ID="{container_id_prefix} OR {first_container_id}">
     *         {BEFORE ITEM}
     *        <{item_container_tag} CLASS="{item_container_class} {first_item_container_class}?" ID="{item_container_id_prefix}">
     *            <A>
     *                <{title_container_tag}>
     *                    {before_title}
     *                        [title]
     *                    {after_title}
     *                </{title_container_tag}>
     *            </A>
     *        </{item_container_tag}>
     *        {AFTER ITEM}
     *    </{container_tag}>
     *
     * TODO: instead of echoing, store to string
     *
     */
    public static function generateSiteTreeMenu($tree, $options = array(), $listing_container = false)
    {
        // Option Setup

        // HOW DEEP IN SUBS TO GO
        if (!isset($options['limit']) || empty($options['limit'])) {
            $options['limit'] = PHP_INT_MAX;
        }

        // THE ID OF THE FIRST/PARENT CONTAINER (UL) (MIGHT ALSO NOT BE UL)
        if (!isset($options['first_container_id']) || empty($options['first_container_id'])) {
            $options['first_container_id'] = '';
        }

        // THE TAG OF THE CONTAINER (DEFAULT: UL)
        if (!isset($options['container_tag']) || empty($options['container_tag'])) {
            $options['container_tag'] = 'ul';
        }

        // THE CLASS OF ALL CONTAINERS (UL) (MIGHT ALSO NOT BE UL)
        if (!isset($options['container_class']) || empty($options['container_class'])) {
            $options['container_class'] = '';
        }

        // THE ID PREFIX OF ALL CONTAINERS (UL) (MIGHT ALSO NOT BE UL)
        if (!isset($options['container_id_prefix']) || empty($options['container_id_prefix'])) {
            $options['container_id_prefix'] = '';
        }

        // THE TAG OF ALL THE ITEM CONTAINERS (DEFAULT: LI)
        if (!isset($options['item_container_tag']) || empty($options['item_container_tag'])) {
            $options['item_container_tag'] = 'li';
        }

        // THE CLASS OF ALL THE ITEM CONTAINERS (DEFAULT: LI)
        if (!isset($options['item_container_class']) || empty($options['item_container_class'])) {
            $options['item_container_class'] = '';
        }

        // THE ID PREFIX OF ALL OF THE ITEM CONTAINERS (LI)
        if (!isset($options['item_container_id_prefix']) || empty($options['item_container_id_prefix'])) {
            $options['item_container_id_prefix'] = 'item';
        }


        // THE CLASS OF ALL THE FIRST ( 1ST DEPTH ) ITEM CONTAINERS (LI)
        if (!isset($options['first_item_container_class']) || empty($options['first_item_container_class'])) {
            $options['first_item_container_class'] = '';
        }

        // THE TAG OF TITLE CONTAINERS (MIGHT BE SOMETIHNG LIKE A SPAN)
        if (!isset($options['title_container_tag']) || empty($options['title_container_tag'])) {
            $options['title_container_tag'] = '';
        }


        // THE HTML WITHIN THE <A> BEFORE THE TITLE
        if (!isset($options['before_title']) || empty($options['before_title'])) {
            $options['before_title'] = '';
        }

        // THE HTML WITHIN THE <A> AFTER THE TITLE
        if (!isset($options['after_title']) || empty($options['after_title'])) {
            $options['after_title'] = '';
        }


        // THE HTML BEFORE EACH ITEM CONTAINER (LI)
        if (!isset($options['before_item']) || empty($options['before_item'])) {
            $options['before_item'] = '';
        }

        // THE HTML AFTER EACH ITEM CONTAINER (LI)
        if (!isset($options['after_item']) || empty($options['after_item'])) {
            $options['after_item'] = '';
        }

        // THE ID OF THE ACTIVE PAGE <- REALLY SHOULD BE ADDED
        if (!isset($options['active_page_id']) || empty($options['active_page_id'])) {
            $options['active_page_id'] = '';
        }


        // THE ID OF THE ACTIVE PAGE <- REALLY SHOULD BE ADDED
        if (!isset($options['is_admin']) || empty($options['is_admin'])) {
            $options['is_admin'] = false;
        }


        /*
        NOT IMPELMENTED YET
        // WETHER TO ECHO THE PRODUCED MENU OR NOT
        if ( !isset($options['echo']) || empty($options['echo']) ) {
            $options['echo'] = false;
        }
        */

        CMSNav::generateSiteTreeMenuRecursive($tree, 0, $options['limit'], $options, $listing_container);

    }

    /**
     * CMSNav::generateSiteTreeMenuRecursive()
     *
     * @param mixed[][] tree
     * @param int depth
     * @param int limt
     * @param mixed[] options
     * @param listing_container = false
     *
     * Recursive function that is called by CMSNav::generateSiteTreeMenu()
     */
    public static function generateSiteTreeMenuRecursive($tree, $depth, $limit, $options, $listing_container = false)
    {
        if (count($tree) > 0 && $limit > 0) {

            $depth = $depth + 1;
            $limit = $limit - 1;

            // THE <UL> (MIGHT ALSO NOT BE SPECIFICALLY UL)
            echo "<" . $options['container_tag'] . " " . ($depth == 1 ? "id='" . $options['first_container_id'] . "'" : "") . " class='" . ($listing_container ? 'listing_container' : '') . "'>";

            foreach ($tree as $item) {

                // skip if has no title - because that means that its a 'new page'
                if ($item['title'] == "" || $item['hide_in_cms'] && !$options['is_admin']) {
                    continue;
                }

                // WHATEVER USER WISHES TO ADD BEFORE <LI>
                echo $options['before_item'];

                // THE <LI> (MIGHT ALSO NOT BE SPECIFICALLY LI)
                $id = "";
                $id = $options['item_container_id_prefix'] . "_" . $item['id'];

                $class = "";
                if ($options['active_page_id'] == $item['id']) {
                    $class = "cms-page-active";
                }
                if ($depth == 1) {
                    $class .= " " . $options['first_item_container_class'];
                }
                if ($options['active_page_id'] == $item['id']) {
                    $class .= " cms-page-active";
                }
                $class .= " " . $options['item_container_class'];

                if (!empty($item['sub']) && $options['active_page_id'] != $item['id'] && !page_id_in_page_tree($options['active_page_id'], $item['sub'])) {
                    $class = " hide-submenu";
                }
                echo "<" . $options['item_container_tag'] . "
                            " . (!empty($id) ? "id='" . $id . "'" : "") . "
                            " . (!empty($class) ? "class='" . $class . "'" : "") . "
                          >";


                // THE <A> (LINK)
                if (!empty($item['link'])) {
                    echo "<a
                                     id     = '" . $options['item_container_id_prefix'] . "_" . $item['id'] . "_a'
                                     class  = '" . ($options['active_page_id'] == $item['id'] ? ' cms-page-active' : '') . " " . ($item['type'] == "button" && $options['is_admin'] ? ' cms-buttom-page cms-trigger-page' : '') . "'
                                     title  = '" . clean_page($item['title']) . "'
                                     href   = './?page=" . $item['id'] . "'
                                  >";
                }


                echo "<span class='level_indent_holder'>";
                for ($j = 0; $j < $depth; $j++) {

                    echo "<span class='level_indent'></span>";

                }
                echo "</span>";

                // SOMETHING LIKE A <SPAN> OR SOMETHING ELSE THAT MIGHT BE ARROUND THE TITLE/NAME
                if (!empty($options['title_container_tag'])) {
                    $icon_padding_class = "";
                    if ($options['is_admin']) {
                        if ($item['lock'] && $item['hide_in_cms']) {
                            $icon_padding_class = " twoIconPadding";
                        } elseif ($item['lock'] || $item['hide_in_cms']) {
                            $icon_padding_class = " oneIconPadding";
                        }
                    }
                    ?>
                    <<?= $options['title_container_tag'] ?> class='title_container<?= $icon_padding_class ?>'>
                    <?php
                }

                if ($options['is_admin']) {
                    ?><i class="fa fa-ellipsis-v menu-handle"></i><?php
                }

                echo $options['before_title']; // SOMETHING LIKE AN ARROW OR SOMETHING ELSE YOU MIGHT WANT TO PUT RIGHT  B E F O R E  TITLE WITHIN <A> AND <SPAN>

                if ($item['frontpage']) {

                    echo '<i class="type-icon fa fa-home"></i>';

                } elseif ($item['slug'] == "404") {

                    echo '<i class="type-icon fa fa-exclamation-triangle"></i>';

                } elseif ($item['type'] == "default" && !empty($item['published'])) {

                    echo '<i class="type-icon fa fa-file"></i>';

                } elseif ($item['type'] == "default" && empty($item['published'])) {

                    echo '<i class="type-icon fa fa-file-o"></i>';

                } elseif ($item['type'] == "button") {

                    echo '<i class="type-icon fa fa-plus-circle"></i>';

                }

                if ($options['is_admin'] && $item['lock'] && $item['hide_in_cms']) {
                    ?>
                    <i class="type-icon fa fa-eye-slash firstIconIndent"
                       title="Page hidden from view to client in admin area."></i>
                    <i class="type-icon fa fa-lock secondIconIndent" title="Page cannot be edited by client."></i>
                    <?php
                } elseif ($options['is_admin'] && $item['lock']) {
                    ?>
                    <i class="type-icon fa fa-lock firstIconIndent" title="Page cannot be edited by client."></i>
                    <?php
                } elseif ($options['is_admin'] && $item['hide_in_cms']) {
                    ?>
                    <i class="type-icon fa fa-eye-slash firstIconIndent"
                       title="Page hidden from view to client in admin area."></i>
                    <?php
                }

                echo clean_page($item['title']); // THE TITLE ITSELF

                echo $options['after_title']; // SOMETHING LIKE AN ARROW OR SOMETHING ELSE YOU MIGHT WANT TO PUT RIGHT  A F T E R  TITLE WITHIN <A> AND <SPAN>

                if (count($item['sub']) > 0 && $options['active_page_id'] == $item['id'] || page_id_in_page_tree(array('id' => $options['active_page_id']), $item['sub'])) {

                    echo '<i class="submenu-button fa fa-chevron-circle-up"></i>';

                } elseif (count($item['sub']) > 0) {

                    echo '<i class="submenu-button fa fa-chevron-circle-down"></i>';

                }


                // SOMETHING LIKE A <SPAN> OR SOMETHING ELSE THAT MIGHT BE ARROUND THE TITLE/NAME
                if (!empty($options['title_container_tag'])) {
                    echo "</" . $options['title_container_tag'] . ">";
                }

                // end of THE <A></A>
                if (!empty($item['link'])) {
                    echo "</a>";
                }


                // IF CHILDREN - INSERT SUBMENU WITH ALL ITS <UL><LI></LI><LI></LI>....
                if (count($item['sub']) > 0) {
                    CMSNav::generateSiteTreeMenuRecursive($item['sub'], $depth, $limit, $options, $item['listing_container']);
                }


                // end of THE <LI></LI> (MIGHT ALSO NOT BE SPECIFICALLY LI)
                echo "</" . $options['item_container_tag'] . ">";

                // WHATEVER USER WISHES TO ADD AFTER <LI>
                echo $options['after_item'];

            }

            // end of THE <UL> (MIGHT ALSO NOT BE SPECIFICALLY UL)
            echo "</" . $options['container_tag'] . ">";

        }
    }
}
