<?php
/**
 * @version     $Id$
 * @author      JoomlaUX
 * @package     Joomla.Site
 * @subpackage  mod_jux_easy_megamenu
 * @copyright   Copyright (C) 2008 - 2018 JoomlaUX. All rights reserved.
 * @license     License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
 */

use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Helper\ModuleHelper;
defined('_JEXEC') or die('Restricted access');

require_once dirname(__FILE__).'/menu.tpl.php';

if (!class_exists('JoomlaMenu')) {
    class JoomlaMenu
    {   
        protected $menu_template;
        protected $children = array();
        protected $order = array();
        protected $_items = array();
        protected $menuHtml = '';
        protected $optionHTML = '';
        protected $params = null;
        protected $settings = null;
        protected $options = null;
        protected $top_level_caption = false;
        protected $_isFrontEnd = false;
        protected $_active = null;
        protected $_enable_bs3 = 0;
        protected $vars = array();
        public $menu_type;

        function __construct($menuType, $params, $_enable_bs3 = 0, $_isFrontEnd = false, $vars = array())
        {
            $this->menu_type = $menuType;
            $this->params = $params;
            $this->_isFrontEnd = $_isFrontEnd;
            $this->_enable_bs3 = $_enable_bs3;
            $order = json_decode($this->params->get('mega_order', ''), true);
            $this->order = isset($order[$this->menu_type]) ? $order[$this->menu_type] : '';
            $this->menu_template = new JoomlaMenuTpl($this->menu_type, $this->params, $this->_enable_bs3, $this->_isFrontEnd);
            $this->vars = $vars;
        }

        /**
         * Get joomla menu
         * @return object
         */
        function fetchMenu()
        {
            $app = Factory::getApplication();
            $menu = $app->getMenu('site');
            $component = ComponentHelper::getComponent('com_content');
            $menu = $menu->getItems('component_id', $component->id);
            return $menu;
        }

        /**
         * Get menu types
         * @return object
         */
        public function getMenuTypes()
        {
            $db = Factory::getDbo();
            $query = $db->getQuery(true);
            $query->select('*')
                ->from($db->quoteName('#__menu_types'));
            $db->setQuery($query);
            $result = $db->loadObjectList();
            return $result;
        }

        /**
         * Get top level of joomla menu
         * @return array
         */
        public function getParentMenuItems()
        {
            $db         = Factory::getDbo();
            $app        = Factory::getApplication();
            $user       = $app->getIdentity();
            if ($user !== null) {
                $access = $user->getAuthorisedViewLevels();
            } else {
                $access = []; // Default to an empty array or other default action
            }
            $query  = $db->getQuery(true);
            $query->select(array('m.id, m.title, m.browserNav, m.type, m.alias, m.parent_id, m.link, m.level, m.params'))
                ->from('#__menu AS m')
                ->where('m.menutype = '.$db->quote($this->menu_type))
                ->where('m.published = 1')
                ->order('m.lft ASC');
                if(isset($access[0]) && $access[0] == '9' ){
                    $query->where(' m.access  != 2');      
                }
                // Filter by language
                if ($app->isClient('site') && $app->getLanguageFilter()) {
                    $query->where('m.language in (' . $db->Quote(Factory::getLanguage()->getTag()) . ',' . $db->Quote('*') . ')');
                }

            $db->setQuery($query);
            $result = $db->loadObjectList('id');

            $children = array();
            if ($result) {
                foreach ($result as $v) {
                    $v->tree = $v->id;
                    $v->title = $v->title;
                    $v->parent_id = $v->parent_id;
                    $pt = $v->parent_id;
                    $list = @$children[$pt] ? $children[$pt] : array();
                    array_push($list, $v);
                    $children[$pt] = $list;
                }
            }

            $lists = $this->treerecurse(1, array(), $children, 9999, 0);
            return $lists;
        }

        /**
         * @param $id integer
         * @param $list array
         * @param $children array
         * @param $maxlevel integer
         * @param $level integer
         * @return array
         */
        function treerecurse($id, $list, &$children, $maxlevel = 9999, $level = 0)
        {
            if(isset($children[$id])){
                if (is_array($children[$id])  &&  @$children[$id] && $level <= $maxlevel) {
                    $count = count($children[$id]);
                    foreach ($children[$id] as $v) {
                        $id = $v->id;
                        $list[$id] = $v;
                        $list[$id]->children = $count;
                        $list[$id]->level = $level;
                        $list = $this->treerecurse($id, $list, $children, $maxlevel, $level + 1);
                    }
                }
            }
            return $list;
        }

        public function parseMenu()
        {
            $app = Factory::getApplication();

            $uri = Uri::getInstance();

            $items = array();
            $items = $this->getParentMenuItems();
            $orderItems = array();
            $unorderItems = array();

            if($this->order != "") {
                foreach($this->order as $orderKey => $orderItem) {
                    $orderId = explode('_', $orderKey);
                    foreach ($items as $itemKey => &$item) {
                        if($orderId[1] == $itemKey)
                            $orderItems[$itemKey] = $item;
                    }
                }
                foreach ($items as $itemKey => &$item) {
                    if(!array_key_exists($itemKey,$orderItems)) {
                        $unorderItems[$itemKey] = $item;
                    }
                }
                $orderItems = array_merge($orderItems, $unorderItems);
            } else {
                $orderItems = $items;
            }

            $settings = json_decode($this->params->get('mega_config', ''), true);
            if (isset($settings[$this->menu_type])) {
                $this->settings = $settings[$this->menu_type];
            } else {
                $this->settings = '';
            }

            foreach ($orderItems as &$item) {
                $parent_tree = array();
                if (isset($items[$item->parent_id])) {
                    $parent_tree  = $items[$item->parent_id]->tree;
                }
                $parent_tree[] = $item->id;
                $item->tree = $parent_tree;
                $item->level = $item->level + 1;

                $active = $this->getActive($this->vars, $item);
                $active_id = $active ? $active->id : 0 ;
                $active_tree = $active ? $active->tree : array();

                $parent = isset($this->children[$item->parent_id]) ? $this->children[$item->parent_id] : array();
                $parent[] = $item;
                $this->children[$item->parent_id] = $parent;

                $this->_items[$item->id] = $item;
            }

            $i = 0;
            foreach ($orderItems as &$item) {

                $key = $item->id;
                $itemParams   = ($item->params);

                $itemParams = json_decode($itemParams, true);

                $setting = isset($this->settings[''.$key]) ? $this->settings[''.$key] : array();


                // decode html tag
                if (isset($setting['caption']) && $setting['caption']) {
                    $setting['caption'] = str_replace(array('[lt]','[gt]'), array('<','>'), $setting['caption']);
                }
                if ($item->level == 1 && isset($setting['caption']) && $setting['caption']) {
                    $this->top_level_caption = true;
                }
                //active and current
                $class = '';
                if ($item->id == $active_id) {
                    $class .= ' current ';
                }
                if (in_array($item->id, $active_tree)) {
                    $class .= ' active ';
                }

                $item->class = $class;
                $item->mega = 0;
                $item->group = 0;
                $item->dropdown = 0;
                $item->display = 1;
                $item->active = 0;


                if (isset($setting['display'])) {
                    $item->display = $setting['display'];
                }

                if (isset($setting['group'])) {
                    $item->group = 1;
                } else {
                    if ($this->_isFrontEnd) {
                        if ((isset($this->children[$item->id]) && (!isset($setting['hidesub']))) || isset($setting['sub'])) {
                            $item->dropdown = 1;
                        }
                    } else {
                        if ((isset($this->children[$item->id]) ) || isset($setting['sub'])) {
                            $item->dropdown = 1;
                        }
                    }
                }


                $item->mega = $item->group || $item->dropdown;


                if ($item->mega) {
                    if (!isset($setting['sub'])) {
                        $setting['sub'] = array();
                    }
                    if (isset($this->children[$item->id]) && (!isset($setting['sub']['rows']) || !count($setting['sub']['rows']))) {
                        $c = $this->children[$item->id][0]->id;
                        $setting['sub'] = array('rows'=>array(array(array('width'=>12, 'item'=>$c))));
                    }
                }

                $item->setting = $setting;
                // Reverted back for CMS version 2.5.6

                switch ($item->type) {
                    case 'separator':
                        break;

                    case 'heading':
                         break;

                    case 'url':
                        if ((strpos($item->link, 'index.php?') === 0) && (strpos($item->link, 'Itemid=') === false)) {
                            // If this is an internal Joomla link, ensure the Itemid is set.
                            $item->link = $item->link . '&Itemid=' . $item->id;
                        } 
                        break;

                    case 'alias':

                        $item->link = 'index.php?Itemid=' . $itemParams['aliasoptions'];

                        // Get the language of the target menu item when site is multilingual
                        if (Multilanguage::isEnabled()) {
                            $newItem = Factory::getApplication()->getMenu()->getItem((int) $itemParams['aliasoptions']);

                            // Use language code if not set to ALL
                            if ($newItem != null && $newItem->language && $newItem->language !== '*') {
                                $item->link .= '&lang=' . $newItem->language;
                            }
                        }
                        break;

                    default:
                        $item->link.= '&Itemid='.$item->id;
                        break;
                }
                $item->flink = ($item->link);

                $i++;
            }
        }

        public function render($isFrontEnd = false)
        {
            $this->_isFrontEnd = $isFrontEnd;
            $this->parseMenu();


            $this->menuHtml = '';
            $this->menuHtml .= $this->__('beginmenu');
            $keys = array_keys($this->_items);

            if (count($keys)) {
                $this->menuHtml .= $this->nav(null, $keys[0]);
                if ($this->_isFrontEnd) {
                    $this->menuHtml .= $this->nav(null, $keys[0], 9999, true);
                }
            }
            $this->menuHtml .= $this->__('endmenu');

            $this->optionHTML = '';
            $this->optionHTML .= $this->__('beginOptionTabs');
            $this->optionHTML .= $this->__('beginOptionTabsContent');
            $this->optionHTML .= $this->optionTabsContent();
            $this->optionHTML .= $this->__('endOptionTabsContent');

            $this->options =json_decode($this->params->get('mega_options', ''), true);
            $option = isset($this->options[$this->menu_type]) ? $this->options[$this->menu_type] : array();
            //return array($this->menuHtml, $this->optionHTML, json_encode($this->children_order));
            return [
                  $this->menuHtml,
                  $this->optionHTML,
                  [
                      'menu_type' => $this->menu_type,
                      'rtl' => isset($option['rtl']) && $option['rtl'] == 1 ? $option['rtl'] : 0,
                      'menu_orientation' => isset($option['menu_orientation']) ? $option['menu_orientation'] : 'horizontal',
                      'sm_horizontal_drop'=> isset($option['sm_horizontal_drop']) ? $option['sm_horizontal_drop'] : 'down',
                      'sm_vertical_drop' => isset($option['sm_vertical_drop']) ? $option['sm_vertical_drop'] : 'left',
                      'menubar_align' =>  isset($option['menubar_align']) ? $option['menubar_align'] : 'left'
                  ]
              ];
        }

        public function optionTabsContent()
        {
            $this->options =json_decode($this->params->get('mega_options', ''), true);
            $option = isset($this->options[$this->menu_type]) ? $this->options[$this->menu_type] : array();
            //General Tab Content Template
            $generalTabContent = $this->__('generalTabContent', $option);
            //Menu Bar Content Template
            $menubarTabContent = $this->__('menubarTabContent', $option);
            //Top Menu Content Template
            $topmenuTabContent = $this->__('topmenuTabContent', $option);
            //Top Menu Hover Content Template
            $topmenuHoverTabContent = $this->__('topmenuHoverTabContent', $option);
            //Sub Menu Content Template
            $submenuTabContent = $this->__('submenuTabContent', $option);
            //Sub Menu Hover Content Template
            $submenuHoverTabContent = $this->__('submenuHoverTabContent', $option);
            //Mobile Menu Content Template
            $mobileMenuTabContent = $this->__('mobilemenuTabContent', $option);
            //Advanced Content Template
            $advancedTabContent = $this->__('advancedTabContent', $option);

            $tabsContentTpl = $generalTabContent .
              $menubarTabContent .
              $topmenuTabContent .
              $topmenuHoverTabContent .
              $submenuTabContent .
              $submenuHoverTabContent .
              $mobileMenuTabContent .
              $advancedTabContent;
            return $tabsContentTpl;
        }

        public function nav($pitem, $start = 0, $end = 0, $mobile = false)
        {
            if ($start > 0) {
                if (!isset($this->_items[$start])) {
                    return;
                }
                $pid     = $this->_items[$start]->parent_id;
                $items   = array();
                $started = false;
                foreach ($this->children[$pid] as $item) {
                    if ($started) {
                        if ($item->id == $end) {
                            break;
                        }
                        $items[] = $item;
                    } else {
                        if ($item->id == $start) {
                            $started = true;
                            $items[] = $item;
                        }
                    }
                }
                if (!count($items)) {
                    return;
                }
            } elseif ($start === 0) {
                $pid = $pitem->id;
                if (!isset($this->children[$pid])) {
                    return;
                }
                $items = $this->children[$pid];
            } else {
                //empty menu
                return;
            }

            $beginnav = $this->__('beginnav', array(
              'item' => $pitem,
              'show_items'=>$this->getParam('show_items', 1),
              'mobile' => $mobile
            ));
            $itemHtml = '';

            foreach ($items as $item) {
                $setting = $item->setting;
                if ($this->_isFrontEnd && isset($setting['display']) && $setting['display'] == -1) {
                    continue;
                }
                $itemHtml .= $this->item($item, $mobile);
            }

            $endnav = $this->__('endnav', array(
              'item' => $pitem
            ));
            if ($itemHtml == '') {
                return '';
            }
            return $beginnav.$itemHtml.$endnav;
        }

        public function item($item, $mobile = false)
        {
            // item content
            $setting = $item->setting;

            $megaHtml = '';

            if ($item->mega) {
                if ($mobile) {
                    if (!isset($setting['hidewcol'])) {
                        $megaHtml .= $this->mega_mobile($item);
                    }
                } else {
                    $megaHtml .= $this->mega($item);
                }
            }
            if ($megaHtml == '') {
                $item->group = 0;
                $item->dropdown = 0;
                $item->mega = 0;
            }

            $html = $this->__('beginitem', array ('item'=>$item, 'setting'=>$setting, 'mobile' => $mobile));
            $itemHtml = $this->__('item', array ('item'=>$item, 'setting'=>$setting, 'mobile' => $mobile));
            $html .= $itemHtml;
            if ($megaHtml != '') {
                $html .= $megaHtml;
            }
            $html .= $this->__('enditem', array ('item'=>$item));
            return $html;
        }

        public function getParam($name, $default = null)
        {
            if (!$this->params) {
                return $default;
            }

            return $this->params->get($name, $default);
        }

        public function _($tmpl, $vars = array())
        {
            $vars ['menu'] = $this;
            $vars['menu_type'] = $this->menu_type;
            if (method_exists('JoomlaMenuTpl', $tmpl)) {
                $this->menuHtml .= JoomlaMenuTpl::$tmpl($this->vars)."\n";
            } else {
                $this->menuHtml .= "$tmpl\n";
            }
        }

        public function __($tmpl, $vars = array())
        {
            $vars ['menu'] = $this;
            $vars['menu_type'] = $this->menu_type;
            if (method_exists('JoomlaMenuTpl', $tmpl)) {
                return JoomlaMenuTpl::$tmpl($vars)."\n";
            } else {
                return "$tmpl\n";
            }
        }

        public function compareOrder($old, $new)
        {
            foreach ($old as $k => $v) {
                if ((!isset($new[$k])) || (isset($new[$k]) && $new[$k] != $v)) {
                    return false;
                }
            }
            return true;
        }

        public function getActive($vars, $item)
        {
            return $this->_active;
        }

        public function get($prop)
        {
            if (isset($this->$prop)) {
                return $this->$prop;
            }
            return null;
        }

        protected function mega($item)
        {

            $key       = 'item-' . $item->id;
            $setting   = $item->setting;
            $sub       = $setting['sub'];
            $items     = isset($this->children[$item->id]) ? $this->children[$item->id] : array();
            $firstitem = count($items) ? $items[0]->id : 0;
            $endItems = array();
            $k1       = $k2 = 0;
            foreach ($sub['rows'] as $row) {
                foreach ($row as $col) {
                    if (!isset($col['position'])) {
                        if ($k1) {
                            $k2 = $col['item'];
                            if (!isset($this->_items[$k2]) || $this->_items[$k2]->parent_id != $item->id) {
                                break;
                            }
                            $endItems[$k1] = $k2;
                        }
                        $k1 = $col['item'];
                    }
                }
            }

            $html = '';
            $endItems[$k1] = 0;
            $beginmega = $this->__('beginmega', array(
              'item' => $item,
               'mobile' => false,
            ));
            $firstitemscol = true;
            $rowHtml = '';

            foreach ($sub['rows'] as $row) {
                $beginrow = $this->__('beginrow');
                $colHtml = '';


                foreach ($row as $k => $col) {
                    if (isset($col['position'])) {
                        $colHtml .= $this->__('begincol', array(
                          'setting' => $col
                        ));
                        $colHtml .= $this->module($col['position']);
                        $colHtml .= $this->__('endcol');
                    } else {
                        if (!isset($endItems[$col['item']])) {
                            continue;
                        }

                        $begincol = $this->__('begincol', array(
                          'setting' => $col
                        ));
                        $toitem    = $endItems[$col['item']];
                        $startitem = $firstitemscol ? $firstitem : $col['item'];
                        $subNav = $this->nav($item, $startitem, $toitem);
                        $firstitemscol = false;
                        $endcol = $this->__('endcol');
                        if ($subNav != '') {
                            $colHtml .= $begincol.$subNav.$endcol;
                        }
                    }
                }
                $endrow = $this->__('endrow');
                if ($colHtml != '') {
                    $rowHtml .= $beginrow.$colHtml.$endrow;
                }
            }
            $endmega =$this->__('endmega');
            if ($rowHtml == '') {
                return '';
            }
            return $beginmega.$rowHtml.$endmega;
        }

        protected function mega_mobile($item)
        {

            $key       = 'item-' . $item->id;
            $setting   = $item->setting;
            $sub       = $setting['sub'];
            $items     = isset($this->children[$item->id]) ? $this->children[$item->id] : array();
            $firstitem = count($items) ? $items[0]->id : 0;


            $endItems = array();
            $k1       = $k2 = 0;
            foreach ($sub['rows'] as $row) {
                foreach ($row as $col) {
                    if (!isset($col['position'])) {
                        if ($k1) {
                            $k2 = $col['item'];
                            if (!isset($this->_items[$k2]) || $this->_items[$k2]->parent_id != $item->id) {
                                break;
                            }
                            $endItems[$k1] = $k2;
                        }
                        $k1 = $col['item'];
                    }
                }
            }

            $html = '';
            $endItems[$k1] = 0;
            $beginmega = $this->__('beginmega', array(
              'item' => $item,
              'mobile' => true
            ));
            $firstitemscol = true;
            $rowHtml = '';
            foreach ($sub['rows'] as $row) {
               // $beginrow = $this->__('beginrow');
                $colHtml = '';
                foreach ($row as $col) {
                    if (isset($col['position'])) {
                        $colHtml .= $this->__('begincol', array(
                          'setting' => $col,
                          'mobile' => true
                        ));
                        $colHtml .= $this->module($col['position']);
                        $colHtml .= $this->__('endcol');
                    } else {
                        if (!isset($endItems[$col['item']])) {
                            continue;
                        }

                        $begincol = $this->__('begincol', array(
                          'setting' => $col,
                          'mobile' => true
                        ));
                        $toitem    = $endItems[$col['item']];
                        $startitem = $firstitemscol ? $firstitem : $col['item'];
                        $subNav = $this->nav($item, $startitem, $toitem, true);
                        $firstitemscol = false;
                        $endcol = $this->__('endcol');
                        if ($subNav != '') {
                            $colHtml .= $begincol.$subNav.$endcol;
                        }
                    }
                }
                //$endrow = $this->__('endrow');
                if ($colHtml != '') {
                    $rowHtml .= $colHtml;
                }
            }
            $endmega =$this->__('endmega');
            if ($rowHtml == '') {
                return '';
            }
            return $beginmega.$rowHtml.$endmega;
        }

        public function module($position)
        {

            if ($this->_isFrontEnd) {
                $id = intval($position);
                $db = Factory::getDbo();
                $query = $db->getQuery(true);
                $query->select('m.id, m.title, m.module, m.position, m.content, m.showtitle, m.params');
                $query->from('#__modules AS m');
                $query->where('m.id = '.$id);
                $query->where('m.published = 1');
                $db->setQuery($query);
                $module = $db->loadObject();
                if ($module && $module->id) {
                    $content = ModuleHelper::renderModule($module, array('style'=>'xhtml'));
                    return $content."\n";
                }
            }
            return '';
        }
    }
}
