<?php
/**
* @package   Gridbox
* @author    Balbooa http://www.balbooa.com/
* @copyright Copyright @ Balbooa
* @license   http://www.gnu.org/licenses/gpl.html GNU/GPL
*/

namespace Balbooa\Component\Gridbox\Administrator\Helper;

defined('_JEXEC') or die;

use Balbooa\Component\Gridbox\Administrator\Helper\Filesystem\File;
use Balbooa\Component\Gridbox\Site\Enums\Finder\FinderEvents;
use Balbooa\Component\Gridbox\Site\Helper\AssetsHelper;
use Balbooa\Component\Gridbox\Site\Helper\BaseHelper;
use Balbooa\Component\Gridbox\Site\Helper\FileHelper;
use Balbooa\Component\Gridbox\Site\Helper\StoreHelper;
use Balbooa\Component\Gridbox\Site\Service\EventDispatcher;
use Balbooa\Component\Gridbox\Site\Trait\AccessTrait;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Filter\OutputFilter;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Http\HttpFactory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Uri\Uri;
use Balbooa\Component\Gridbox\Site\Trait\DateTrait;
use Balbooa\Component\Gridbox\Site\Trait\LanguageTrait;

include JPATH_ROOT.'/components/com_gridbox/src/Helper/functions.php';

abstract class GridboxHelper extends BaseHelper
{
    use DateTrait;
    use LanguageTrait;
    use AccessTrait;

    public static $installComments;
    public static $installReviews;
    public static $templates;
    public static $path = JPATH_ROOT . '/administrator/components/com_gridbox';

    public static function getGridboxAppsList($parent_id = 0)
    {
        $map = self::getAppsMap($parent_id);
        $items = [];
        foreach ($map as $obj) {
            $item = self::getAppObject($obj);
            if ($item) {
                $item->order_ind = $obj->order_ind;
                $items[] = $item;
            }
        }

        return $items;
    }

    public static function getAppObject($obj)
    {
        $db = Factory::getDbo();
        if ($obj->type == 'app' && $obj->item_id != 0) {
            $query = $db->getQuery(true)
                ->select('id, title, type')
                ->from('#__gridbox_app')
                ->where('id = '.$obj->item_id);
            $db->setQuery($query);
            $item = $db->loadObject();
        } else if ($obj->type == 'app' && $obj->item_id == 0) {
            $item = new \stdClass();
            $item->id = 0;
            $item->title = Text::_('PAGES');
            $item->type = 'single';
        } else {
            $query = $db->getQuery(true)
                ->select('*')
                ->from('#__gridbox_apps_groups')
                ->where('id = '.$obj->item_id);
            $db->setQuery($query);
            $item = $db->loadObject();
            $item->type = 'group';
        }

        return $item;
    }

    public static function getAppsMap($parent_id = 0)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('item_id, type, order_ind')
            ->from('#__gridbox_apps_order_map')
            ->where('parent_id = '.$parent_id)
            ->order('order_ind ASC');
        $db->setQuery($query);
        $map = $db->loadObjectList();

        return $map;
    }

    public static function getAppItemIcon($item)
    {
        if (!is_array(self::$templates)) {
            self::$templates = [];
        }
        if (!isset(self::$templates['gridbox-app-item-icon'])) {
            $path = JPATH_COMPONENT.'/tmpl/layouts/gridbox-app-item-icon.php';
            self::$templates['gridbox-app-item-icon'] = FileHelper::readFile($path);
        }
        $user = Factory::getUser();
        $str = self::$templates['gridbox-app-item-icon'];
        if ($item->id == 0) {
            $canEdit = $user->authorise('core.edit', 'com_gridbox');
        } else {
            $canEdit = $user->authorise('core.edit', 'com_gridbox.app.'.$item->id);
        }
        $str = str_replace('[item-type]', $item->type, $str);
        $str = str_replace('[item-id]', $item->id, $str);
        $str = str_replace('[item-icon]', self::getIcon($item), $str);
        if ($canEdit) {
            $str = str_replace('[draggable-helper]', ' draggable-helper', $str);
        } else {
            $str = str_replace('[draggable-helper]', '', $str);
        }

        return $str;
    }

    public static function checkAppsOrder()
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true);
        $query->select('id')
            ->from('#__gridbox_app')
            ->where('type <> '.$db->quote('system_apps'))
            ->order('id ASC');
        $db->setQuery($query);
        $items = $db->loadObjectList();
        $pages = new \stdClass();
        $pages->id = 0;
        array_unshift($items, $pages);
        $query = $db->getQuery(true)
            ->select('MAX(order_ind)')
            ->where('parent_id = 0')
            ->from('#__gridbox_apps_order_map');
        $db->setQuery($query);
        $ind = $db->loadResult();
        $ind = $ind ? ++$ind : 1;
        foreach ($items as $item) {
            $query = $db->getQuery(true)
                ->select('id')
                ->from('#__gridbox_apps_order_map')
                ->where('type = '.$db->quote('app'))
                ->where('item_id = '.$item->id);
            $db->setQuery($query);
            $map = $db->loadResult();
            if (!$map) {
                $obj = new \stdClass();
                $obj->item_id = $item->id;
                $obj->order_ind = $ind++;
                $obj->type = 'app';
                $db->insertObject('#__gridbox_apps_order_map', $obj);
            }
        }
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__gridbox_apps_order_map')
            ->where('type = '.$db->quote('group'))
            ->where('parent_id <> 0');
        $db->setQuery($query);
        $groups = $db->loadObjectList();
        foreach ($groups as $group) {
            $group->parent_id = 0;
            $group->order_ind = $ind++;
            $db->updateObject('#__gridbox_apps_order_map', $group, 'id');
        }
    }

    public static function getProductExtraOptions($str)
    {
        $str = !empty($str) ? $str : '{}';
        $options = json_decode($str);
        $db = Factory::getDbo();
        $extra_options = new \stdClass();
        foreach ($options as $id => $option) {
            $query =  $db->getQuery(true)
                ->select('*')
                ->from('#__gridbox_store_products_fields')
                ->where('id = '.$option->id);
            $db->setQuery($query);
            $field = $db->loadObject();
            if (!$field) {
                continue;
            }
            $obj = new \stdClass();
            $obj->title = $field->title;
            $obj->type = $field->field_type;
            $obj->required = $field->required;
            $obj->items = new \stdClass();
            $items = json_decode($field->options);
            if ($field->field_type == 'file') {
                $obj->file = json_decode($field->file_options);
            }
            if (isset($option->items->{0})) {
                $obj->items->{0} = $option->items->{0};
            }
            foreach ($items as $key => $item) {
                if (isset($option->items->{$item->key})) {
                    $object = $option->items->{$item->key};
                    $object->title = $item->title;
                    $item->price = $object->price;
                    $item->default = $object->default;
                    $item->weight = isset($object->weight) ? $object->weight : '';
                    $obj->items->{$item->key} = $item;
                }
            }
            $extra_options->{$field->id} = $obj;
        }
        
        return $extra_options;
    }

    public static function getStatuses()
    {
        $data = (object)[
            'undefined' => (object)[
                'title' => 'Undefined',
                'color' => '#f10000'
            ]
        ];
        foreach (self::$store->statuses as $status) {
            $data->{$status->key} = $status;
        }

        return $data;
    }

    public static function getProductCategoryId($id)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true);
        $query->select('page_category')
            ->from('#__gridbox_pages')
            ->where('id = '.$id);
        $db->setQuery($query);
        $category = $db->loadResult();
        $array = array($category);
        $array2 = self::getProductCategoryIdPath($category);
        $result = array_merge($array, $array2);
        
        return $result;
    }

    public static function getProductCategoryIdPath($id)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true);
        $query->select('parent')
            ->from('#__gridbox_categories')
            ->where('`id` = '.$id * 1);
        $db->setQuery($query);
        $obj = $db->loadObject();
        $array1 = array($obj->parent);
        if ($obj->parent != 0) {
            $array2 = self::getProductCategoryIdPath($obj->parent);
        } else {
            $array2 = [];
        }
        $result = array_merge($array1, $array2);
        
        return $result;
    }

    public static function getUsers()
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('u.id, u.name, u.username')
            ->from('`#__users` AS u');
        $db->setQuery($query);
        $users = $db->loadObjectList();
        foreach ($users as $user) {
            $query = $db->getQuery(true)
                ->select('g.title')
                ->from('#__user_usergroup_map AS m')
                ->where('m.user_id = '.$user->id)
                ->leftJoin('#__usergroups AS g ON '.$db->quoteName('g.id').' = '.$db->quoteName('m.group_id'));
            $db->setQuery($query);
            $user->groups = $db->loadObjectList();
        }
        
        return $users;
    }

    public static function checkCommentUserBanStatus($value, $table, $key)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('id')
            ->from($table)
            ->where($key.' = '.$db->quote($value));
        $db->setQuery($query);
        $result = $db->loadResult();

        return $result;
    }

    public static function checkSystemApp($type)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('COUNT(id)')
            ->from('#__gridbox_app')
            ->where('type = '.$db->quote('system_apps'))
            ->where('title = '.$db->quote($type));
        $db->setQuery($query);
        $count = $db->loadResult();

        return $count > 0;
    }

    public static function checkSubscriptions()
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('COUNT(id)')
            ->from('#__gridbox_store_subscriptions');
        $db->setQuery($query);
        $count = $db->loadResult();

        return $count > 0;
    }

    public static function deleteComment($id)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->delete('#__gridbox_comments')
            ->where('id = '.$id);
        $db->setQuery($query)
            ->execute();
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__gridbox_comments_attachments')
            ->where('comment_id = '.$id);
        $db->setQuery($query);
        $files = $db->loadObjectList();
        foreach ($files as $file) {
            self::removeTmpAttachment($file->id, $file->filename);
        }
        $query = $db->getQuery(true)
            ->delete('#__gridbox_comments_likes_map')
            ->where('comment_id = '.$id);
        $db->setQuery($query)
            ->execute();
        $query = $db->getQuery(true)
            ->select('id')
            ->from('#__gridbox_comments')
            ->where('parent = '.$id);
        $db->setQuery($query);
        $childs = $db->loadObjectList();
        foreach ($childs as $key => $child) {
            self::deleteComment($child->id);
        }
    }

    public static function deleteReview($id)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->delete('#__gridbox_reviews')
            ->where('id = '.$id);
        $db->setQuery($query)
            ->execute();
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__gridbox_reviews_attachments')
            ->where('comment_id = '.$id);
        $db->setQuery($query);
        $files = $db->loadObjectList();
        foreach ($files as $file) {
            self::removeTmpReviewsAttachment($file->id, $file->filename);
        }
        $query = $db->getQuery(true)
            ->delete('#__gridbox_reviews_likes_map')
            ->where('comment_id = '.$id);
        $db->setQuery($query)
            ->execute();
        $query = $db->getQuery(true)
            ->select('id')
            ->from('#__gridbox_reviews')
            ->where('parent = '.$id);
        $db->setQuery($query);
        $childs = $db->loadObjectList();
        foreach ($childs as $key => $child) {
            self::deleteReview($child->id);
        }
    }

    public static function getUnreadCount($table, $where = '', $isBooking = false)
    {
        $db = Factory::getDbo();
        $table .= ' AS t';
        $query = $db->getQuery(true)
            ->select('COUNT(t.id)')
            ->from($table)
            ->where('t.unread = 1');
        if (!empty($where)) {
            $query->where($where);
        }
        if ($isBooking) {
            $query->leftJoin('#__gridbox_store_orders AS o ON o.id = t.order_id')
                ->where('o.published = 1');
        }
        $db->setQuery($query);
        $count  = $db->loadResult();

        return $count;
    }

    public static function getEditorLink($type = '')
    {
        $user = Factory::getUser();
        $link = Uri::root().'index.php?option=com_gridbox&view=editor&tmpl=component&name=';
        $link .= urlencode($user->username).'&pwd='.urlencode($user->password);
        if ($type == 'products') {
            $link .= '&product_type={product_type}';
        }

        return $link;
    }

    public static function assetsCheckPermission($id, $type, $action, $name = '')
    {
        $assets = new AssetsHelper($id, $type);

        return $assets->checkPermission($action, $name);
    }

    public static function checkUserEditLevel($id = '', $type = '')
    {
        $action = 'com_gridbox';
        if (!empty($id)) {
            $action .= '.'.$type.'.'.$id;
        }
        if (!Factory::getUser()->authorise('core.edit', $action)) {
            exit;
        }
    }

    public static function movePageFields($id, $app_id)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true)
            ->select('app_id')
            ->from('#__gridbox_pages')
            ->where('id = '.$id);
        $db->setQuery($query);
        $result = $db->loadResult();
        if ($result != $app_id) {
            self::deletePageFields([$id]);
        }

        return $result;
    }

    public static function afterDeleteAction($cid)
    {
        self::deletePageCss($cid);
        self::deleteTagsLink($cid);
        self::deletePageFields($cid);
        self::deleteProductData($cid);
        EventDispatcher::getInstance()->dispatch(FinderEvents::Delete, $cid, 'finder');
    }

    public static function deleteProductData($cid)
    {
        $db = Factory::getDbo();
        foreach ($cid as $id) {
            $query = $db->getQuery(true)
                ->delete('#__gridbox_store_product_variations_map')
                ->where('product_id = '.$id);
            $db->setQuery($query)
                ->execute();
            $query = $db->getQuery(true)
                ->delete('#__gridbox_store_product_data')
                ->where('product_id = '.$id);
            $db->setQuery($query)
                ->execute();
        }
    }

    public static function deletePageFields($cid)
    {
        $db = Factory::getDbo();
        foreach ($cid as $id) {
            $query = $db->getQuery(true)
                ->delete('#__gridbox_page_fields')
                ->where('page_id = '.$id);
            $db->setQuery($query)
                ->execute();
            $query = $db->getQuery(true)
                ->select('*')
                ->from('#__gridbox_fields_desktop_files')
                ->where('page_id = '.$id);
            $db->setQuery($query);
            $files = $db->loadObjectList();
            $desktopArray = [];
            foreach ($files as $file) {
                $desktopArray[] = $file->id;
                $dir = JPATH_ROOT.'/components/com_gridbox/assets/uploads/app-'.$file->app_id.'/';
                $path = $dir.$file->filename;
                if (File::exists($path)) {
                    File::delete($path);
                }
            }
            if (!empty($desktopArray)) {
                $desktopStr = implode(',', $desktopArray);
                $query = $db->getQuery(true)
                        ->delete('#__gridbox_fields_desktop_files')
                        ->where('id IN ('.$desktopStr.')');
                    $db->setQuery($query)
                        ->execute();
            }
            $query = $db->getQuery(true)
                ->delete('#__gridbox_category_page_map')
                ->where('page_id = '.$id);
            $db->setQuery($query)
                ->execute();
        }
    }

    public static function setGridboxFilters($ordering, $direction, $context)
    {
        if ($ordering == 'order_list') {
            $direction = 'ASC';
        }
        $db = Factory::getDbo();
        $user = Factory::getUser();
        $query = $db->getQuery(true)
            ->select('id, name')
            ->from('#__gridbox_filter_state')
            ->where('name = '.$db->quote($context.'.list.ordering').' OR name = '.$db->quote($context.'.list.direction'))
            ->where('user = '.$user->id);
        $db->setQuery($query);
        $array = $db->loadObjectList();
        if (!empty($array)) {
            foreach ($array as $obj) {
                if ($obj->name == $context.'.list.ordering') {
                    $obj->value = $ordering;
                } else {
                    $obj->value = $direction;
                }
                $db->updateObject('#__gridbox_filter_state', $obj, 'id');
            }
        } else {
            $obj = new \stdClass();
            $obj->user = $user->id;
            $obj->name = $context.'.list.ordering';
            $obj->value = $ordering;
            $db->insertObject('#__gridbox_filter_state', $obj);
            $obj->name = $context.'.list.direction';
            $obj->value = $direction;
            $db->insertObject('#__gridbox_filter_state', $obj);
        }
    }

    public static function getGridboxFilters($context)
    {
        $db = Factory::getDbo();
        $user = Factory::getUser();
        $query = $db->getQuery(true)
            ->select('id, name, value')
            ->from('#__gridbox_filter_state')
            ->where('name = '.$db->quote($context.'.list.ordering').' OR name = '.$db->quote($context.'.list.direction'))
            ->where('user = '.$user->id);
        $db->setQuery($query);
        $array = $db->loadObjectList();

        return $array;
    }
    
    public static function getThemes()
    {
        $url = 'http://www.balbooa.com/updates/gridbox/themes/themes.xml';
        $curl = self::getContentsCurl($url);
        $xml = simplexml_load_string($curl);
        $themes = [];
        foreach ($xml->themes->theme as $theme) {
            $obj = new \stdClass();
            $obj->id = trim((string)$theme->id);
            $obj->title = trim((string)$theme->title);
            $obj->image = trim((string)$theme->image);
            $themes[] = $obj;
        }

        return $themes;
    }

    public static function getTemplate()
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true);
        $query->select('id')
            ->from('#__template_styles')
            ->where('`template`=' .$db->quote('gridbox'))
            ->order('home desc');
        $db->setQuery($query);
        $id = $db->loadResult();

        return $id;
    }

    public static function deleteTagsLink($pages)
    {
        $db = Factory::getDbo();
        foreach ($pages as $value) {
            $query = $db->getQuery(true)
                ->select('tag_id')
                ->from('#__gridbox_tags_map')
                ->where('`page_id` = '. $value);
            $db->setQuery($query);
            $tags = $db->loadObjectList();
            $query = $db->getQuery(true)
                ->delete('#__gridbox_tags_map')
                ->where('`page_id` = '. $value);
            $db->setQuery($query)
                ->execute();
            if (!empty($tags) && is_array($tags)) {
                foreach ($tags as $tag) {
                    $query = $db->getQuery(true)
                        ->select('COUNT(id)')
                        ->from('#__gridbox_tags_map')
                        ->where('`tag_id` = '. $tag->tag_id);
                    $db->setQuery($query);
                    $count = $db->loadResult();
                    if (empty($count)) {
                        $query = $db->getQuery(true)
                            ->delete('#__gridbox_tags')
                            ->where('`id` = '. $tag->tag_id);
                        $db->setQuery($query)
                            ->execute();
                    }
                }
            }
            $query = $db->getQuery(true)
                ->select('id')
                ->from('#__gridbox_comments')
                ->where('`page_id` = '. $value);
            $db->setQuery($query);
            $comments = $db->loadObjectList();
            foreach ($comments as $comment) {
                self::deleteComment($comment->id);
            }
            $query = $db->getQuery(true)
                ->select('id')
                ->from('#__gridbox_reviews')
                ->where('`page_id` = '. $value);
            $db->setQuery($query);
            $reviews = $db->loadObjectList();
            foreach ($reviews as $review) {
                self::deleteReview($review->id);
            }
        }
    }

    public static function findGridboxLinks($html, $items, $apps, $categories, $pages)
    {
        error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_WARNING);
        foreach ($items as $item) {
            if ($item->type == 'logo' || $item->type == 'image' || $item->type == 'icon' || $item->type == 'button') {
                $item->link->link = self::importGridboxLinks($item->link->link, $apps, $categories, $pages);
            } else if ($item->type == 'column' && isset($item->link)) {
                $item->link->link = self::importGridboxLinks($item->link->link, $apps, $categories, $pages);
            } else if ($item->type == 'slideshow' || $item->type == 'slideset' || $item->type == 'carousel') {
                foreach ($item->desktop->slides as $slide) {
                    if (isset($slide->link) && !empty($slide->link)) {
                        $slide->link = self::importGridboxLinks($slide->link, $apps, $categories, $pages);
                    }
                }
            } else if ($item->type == 'content-slider') {
                foreach ($item->slides as $slide) {
                    $slide->link->href = self::importGridboxLinks($slide->link->href, $apps, $categories, $pages);
                }
            } else if ($item->type == 'icon-list') {
                foreach ($item->list as $listValue) {
                    $listValue->link = self::importGridboxLinks($listValue->link, $apps, $categories, $pages);
                }
            }
        }
        include_once JPATH_ROOT.'/components/com_gridbox/libraries/php/phpQuery/phpQuery.php';
        $dom = \phpQuery::newDocument($html);
        foreach (pq('.ba-item-text .content-text a[href]') as $value) {
            $link = pq($value)->attr('href');
            $link = self::importGridboxLinks($link, $apps, $categories, $pages);
            pq($value)->attr('href', $link);
        }
        $obj = new \stdClass();
        $obj->html = $dom->htmlOuter();
        $obj->items = $items;

        return $obj;
    }

    public static function importGridboxLinks($link, $apps, $categories, $pages)
    {
        if (strpos($link, 'option=com_gridbox')) {
            $link = str_replace('index.php?', '', $link);
            parse_str($link, $array);
            if (isset($array['app']) && isset($apps[$array['app']])) {
                $array['app'] = $apps[$array['app']];
            }
            if (isset($array['blog']) && isset($apps[$array['blog']])) {
                $array['blog'] = $apps[$array['blog']];
            }
            if ($array['view'] == 'page') {
                if (isset($array['category']) && isset($categories[$array['category']])) {
                    $array['category'] = $categories[$array['category']];
                }
                if (isset($array['id']) && isset($pages[$array['id']])) {
                    $array['id'] = $pages[$array['id']];
                }
            } else if ($array['view'] == 'blog') {
                if (isset($array['id']) && isset($categories[$array['id']])) {
                    $array['id'] = $categories[$array['id']];
                }
            }
            $data = [];
            foreach ($array as $key => $value) {
                $data[] = $key.'='.$value;
            }
            $link = implode('&', $data);
            $link = 'index.php?'.$link;
        }

        return $link;
    }

    public static function importBlogContent($obj, $apps, $categories)
    {
        error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_WARNING);
        include_once JPATH_ROOT.'/components/com_gridbox/libraries/php/phpQuery/phpQuery.php';
        $dom = \phpQuery::newDocument($obj->html);
        foreach (pq('.ba-item-event-calendar, .ba-item-fields-filter, .ba-item-google-maps-places') as $value) {
            $id = pq($value)->attr('id');
            if (!empty($obj->items->{$id}->app) && isset($apps[$obj->items->{$id}->app])) {
                $obj->items->{$id}->app = $apps[$obj->items->{$id}->app];
            }
        }
        if (!self::$installComments) {
            foreach (pq('.ba-item-comments-box') as $key => $value) {
                self::$installComments = true;
                break;
            }
        }
        if (!self::$installReviews) {
            foreach (pq('.ba-item-reviews') as $key => $value) {
                self::$installReviews = true;
                break;
            }
        }
        $tags = pq('.ba-item-tags');
        foreach ($tags as $value) {
            $app = pq($value)->attr('data-app');
            $cat = pq($value)->attr('data-category');
            $id = pq($value)->attr('id');
            pq($value)->attr('data-app', $apps[$app] ?? 0);
            $item = $obj->items->{$id};
            $item->app = $apps[$app] ?? 0;
            if (!empty($cat)) {
                $catList = explode(',', $cat);
                $object = new \stdClass();
                foreach ($catList as $category) {
                    if (!isset($categories[$category])) {
                        continue;
                    }
                    $catObj = new \stdClass();
                    $catObj->id = $categories[$category];
                    $catObj->title = $item->categories->{$category}->title;
                    $object->{$catObj->id} = $catObj;
                    $category = $categories[$category];
                }
                $item->categories = $object;
                $cat = implode(',', $catList);
                pq($value)->attr('data-category', $cat);
            }
        }
        $itemCategories = pq('.ba-item-categories');
        foreach ($itemCategories as $value) {
            $app = pq($value)->attr('data-app');
            $id = pq($value)->attr('id');
            pq($value)->attr('data-app', $apps[$app] ?? 0);
            $obj->items->{$id}->app = $apps[$app] ?? 0;
        }
        $recent = pq('.ba-item-recent-posts');
        foreach ($recent as $value) {
            $app = pq($value)->attr('data-app');
            $cat = pq($value)->attr('data-category');
            $id = pq($value)->attr('id');
            pq($value)->attr('data-app', $apps[$app] ?? 0);
            $obj->items->{$id}->app = $apps[$app] ?? 0;
            $item = $obj->items->{$id};
            $item->app = $apps[$app] ?? 0;
            if (!empty($cat)) {
                $catList = explode(',', $cat);
                $object = new \stdClass();
                $newCats = [];
                foreach ($catList as $category) {
                    if (!isset($categories[$category])) {
                        continue;
                    }
                    $catObj = new \stdClass();
                    $catObj->id = $categories[$category];
                    $catObj->title = $item->categories->{$category}->title;
                    $object->{$catObj->id} = $catObj;
                    $newCats[] = $categories[$category];
                }
                $item->categories = $object;
                $cat = implode(',', $newCats);
                pq($value)->attr('data-category', $cat);
            }
        }
        foreach (pq('.ba-item-recent-posts-slider') as $value) {
            $id = pq($value)->attr('id');
            if (empty($id) || !isset($obj->items->{$id})) {
                continue;
            }
            $item = $obj->items->{$id};
            if (empty($item->app) || !is_numeric($item->app) || !isset($apps[$item->app])) {
                continue;
            }
            $item->app = $apps[$item->app];
            
            $object = new \stdClass();
            foreach ($item->categories as $key => $category) {
                if (!isset($categories[$key])) {
                    continue;
                }
                $category->id = $categories[$key];
                $object->{$key} = $category;
            }
            $item->categories = $object;
        }
        $related = pq('.ba-item-related-posts');
        foreach ($related as $value) {
            $app = pq($value)->attr('data-app');
            $id = pq($value)->attr('id');
            pq($value)->attr('data-app', $apps[$app] ?? 0);
        }

        $obj->html = $dom->htmlOuter();

        return $obj;

    }
    
    public static function getLanguagesList()
    {
        $url = 'http://www.balbooa.com/updates/gridbox/language/language.xml';
        $curl = self::getContentsCurl($url);
        $xml = simplexml_load_string($curl);
        $array = [];
        if (isset($xml->languages)) {
            foreach ($xml->languages->language as $language) {
                $obj = new \stdClass();
                $obj->flag = 'http://www.balbooa.com/updates/gridbox/language/flags/'.trim((string)$language->flag);
                $obj->title = trim((string)$language->title);
                $obj->code = trim((string)$language->tag);
                $obj->url = trim((string)$language->url);
                $array[] = $obj;
            }
        }

        return $array;
    }

    public static function deletePageCss($cid)
    {
        foreach ($cid as $id) {
            $file = JPATH_ROOT. '/components/com_gridbox/assets/css/storage/style-'.$id.'.css';
            File::delete($file);
        }
    }

    public static function deleteThemeCss($cid)
    {
        foreach ($cid as $id) {
            $file = JPATH_ROOT. '/templates/gridbox/css/storage/code-editor-'.$id.'.css';
            self::deleteFile($file);
            $file = JPATH_ROOT. '/templates/gridbox/css/storage/style-'.$id.'.css';
            self::deleteFile($file);
            $file = JPATH_ROOT. '/templates/gridbox/js/storage/code-editor-'.$id.'.js';
            self::deleteFile($file);
        }
    }

    public static function deleteFile($file)
    {
        if (File::exists($file)) {
            File::delete($file);
        }
    }

    public static function getApps()
    {
        if (isset(self::$cacheData->apps->list)) {
            return self::$cacheData->apps->list;
        }
        $db = Factory::getDbo();
        $query = $db->getQuery(true);
        $query->select('id, title, alias, theme, type, published, access,
            language, image, meta_title, schema_markup, meta_description,
            share_image, share_title, share_description, meta_keywords,
            description, robots, sitemap_include, changefreq, priority')
            ->from('#__gridbox_app')
            ->where('type <> '.$db->quote('system_apps'))
            ->order('id ASC');
        $db->setQuery($query);
        $items = $db->loadObjectList();
        self::addCacheData($items, 'apps', 'list');
        
        return $items;
    }

    public static function copyThemeFiles($pk, $id)
    {
        $file = JPATH_ROOT. '/templates/gridbox/css/storage/code-editor-'.$pk.'.css';
        if (File::exists($file)) {
            $target = JPATH_ROOT. '/templates/gridbox/css/storage/code-editor-'.$id.'.css';
            File::copy($file, $target);
        }
        $file = JPATH_ROOT. '/templates/gridbox/js/storage/code-editor-'.$pk.'.js';
        if (File::exists($file)) {
            $target = JPATH_ROOT. '/templates/gridbox/js/storage/code-editor-' . $id . '.js';
            File::copy($file, $target);
        }
    }

    public static function copyCss($pk, $id)
    {
        $file = JPATH_ROOT. '/components/com_gridbox/assets/css/storage/style-' . $pk . '.css';
        $target = JPATH_ROOT. '/components/com_gridbox/assets/css/storage/style-' . $id . '.css';
        File::copy($file, $target);
    }
    
    public static function checkActive($app)
    {
        $active = '';
        $input = Factory::getApplication()->input;
        $id = $input->get('id', 0, 'int');
        $view = $input->get('view', 'pages', 'string');
        $type = gettype($app);
        $appslist = ['pages', 'apps', 'single'];
        $store = ['paymentmethods', 'shipping', 'storesettings', 'promocodes',
            'productoptions', 'orders', 'subscriptions', 'bookingcalendar'];
        $viewFlag = $type == 'string' && ($app == $view || ($app == 'appslist'
            && in_array($view, $appslist)));
        $storeFlag = $type == 'string' && $app == 'store' && in_array($view, $store);
        if ($viewFlag || $storeFlag || ($type != 'string' && $app->id == $id)) {
            $active = 'active';
        }

        return $active;
    }

    public static function getUrl($app)
    {
        if ($app->type == 'group') {
            $url = '#';
        } else if ($app->id != 0) {
            $view = $app->type == 'single' ? 'single' : 'apps';
            $url = 'index.php?option=com_gridbox&view='.$view.'&id='.$app->id;
        } else {
            $url = 'index.php?option=com_gridbox&view=pages';
        }

        return $url;
    }

    public static function getIcon($item) :string
    {
        if (isset($item->product_type)) {
            $type = $item->product_type == 'booking' ? 'booking' : 'products';
        } else {
            $type = $item->type != 'system_apps' ? $item->type : $item->title;
        }

        $icons = (object) [
            'group' => 'zmdi zmdi-folder',
            'blog' => 'zmdi zmdi-format-color-text',
            'blank' => 'zmdi zmdi-crop-free',
            'products' => 'zmdi zmdi-shopping-basket',
            'booking' => 'zmdi zmdi-calendar-check',
            'portfolio' => 'zmdi zmdi-camera',
            'hotel-rooms' => 'zmdi zmdi-hotel',
            'comments' => 'zmdi zmdi-comment-more',
            'reviews' => 'zmdi zmdi-ticket-star',
            'photo-editor' => 'zmdi zmdi-camera-alt',
            'code-editor' => 'zmdi zmdi-code-setting',
            'performance' => 'zmdi zmdi-time-restore-setting',
            'preloader' => 'zmdi zmdi-spinner',
            'canonical' => 'zmdi zmdi-link',
            'sitemap' => 'zmdi zmdi-device-hub',
            'single' => 'zmdi zmdi-file'
        ];

        return $icons->{$type} ?? $icons->single;
    }
    
    public static function ajaxReload($text, $type = '')
    {
        echo $type.Text::_($text);
        exit;
    }

    public static function getCategories($map)
    {
        $array = [];
        if (!empty($map)) {
            $db = Factory::getDbo();
            $pks = implode(', ', $map);
            $query = $db->getQuery(true)
                ->select('c.id, c.title, c.image')
                ->from('#__gridbox_categories AS c')
                ->leftJoin('#__gridbox_app AS a ON c.app_id = a.id')
                ->where('a.type = '.$db->quote('products'))
                ->where('c.id IN ('.$pks.')');
            $db->setQuery($query);
            $array = $db->loadObjectList();
        }

        return $array;
    }

    public static function preparePrice($price, $symbol = null, $position = null)
    {
        if ($symbol == null) {
            $symbol = self::$store->currency->symbol;
            $position = self::$store->currency->position;
        }
        $decimals = self::$store->currency->decimals;
        $separator = self::$store->currency->separator;
        $thousand = self::$store->currency->thousand;
        $price = round(floatval($price), $decimals);
        $price = number_format($price, $decimals, $separator, $thousand);
        if ($position == '') {
            $value = $symbol.' '.$price;
        } else {
            $value = $price.' '.$symbol;
        }

        return $value;
    }

    public static function prepareGridbox()
    {
        $db = Factory::getDbo();
        $balbooa = self::getGridboxApi('balbooa');
        if (!$balbooa) {
            $obj = new \stdClass();
            $obj->key = '{}';
            $obj->service = 'balbooa';
            $db->insertObject('#__gridbox_api', $obj);
        }
        $balbooa = self::getGridboxApi('balbooa_activation');
        if (!$balbooa) {
            $obj = new \stdClass();
            $obj->key = self::checkGridboxState();
            $obj->service = 'balbooa_activation';
            $db->insertObject('#__gridbox_api', $obj);
        }
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__gridbox_website')
            ->where('1');
        $db->setQuery($query);
        $website = $db->loadObject();
        $params = ComponentHelper::getParams('com_gridbox');
        $image_path = $params->get('image_path', '');
        if (!empty($image_path)) {
            $website->image_path = $params->get('image_path', '');
            $website->file_types = $params->get('file_types', '');
            $website->email_encryption = $params->get('email_encryption', 0);
            $db->updateObject('#__gridbox_website', $website, 'id');
            $query = $db->getQuery(true)
                ->update('#__extensions')
                ->set('params = '.$db->quote('{}'))
                ->where('element = '.$db->quote('com_gridbox'))
                ->where('type = '.$db->quote('component'));
            $db->setQuery($query)
                ->execute();
        }
        if (empty($website->image_path)) {
            $website->image_path = 'images';
        }
        if (empty($website->file_types)) {
            $website->file_types = 'csv, doc, gif, ico, jpg, jpeg, pdf, png, txt, xls, svg, mp4, webp, json';
        }
        self::$website = $website;
        self::$dateFormat = $website->date_format;
        $array = [
            'service = '.$db->quote('google_maps'),
            'service = '.$db->quote('openweathermap'),
            'service = '.$db->quote('yandex_maps')
        ];
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__gridbox_api')
            ->where('('.implode(' OR ', $array).')')
            ->where('type = '.$db->quote(''));
        $db->setQuery($query);
        $array = $db->loadObjectList();
        foreach ($array as $obj) {
            $obj->type = 'integration';
            $obj->title = $obj->service == 'google_maps' ? 'Google Maps'
                : ($obj->service == 'yandex_maps' ? 'Yandex Maps' : 'OpenWeatherMap');
            $db->updateObject('#__gridbox_api', $obj, 'id');
        }
        $array = [
            'service = '.$db->quote('google_login'),
            'service = '.$db->quote('facebook_login'),
            'service = '.$db->quote('vk_login')
        ];
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__gridbox_api')
            ->where('('.implode(' OR ', $array).')');
        $db->setQuery($query);
        $array = $db->loadObjectList();
        if (empty($array)) {
            $key = $website->comments_google_login_key != '' ? $website->comments_google_login_key : $website->reviews_google_login_key;
            self::setIntegration($db, 'google_login', 'Google Login', $key);
            $key = $website->comments_facebook_login_key != '' ? $website->comments_facebook_login_key : $website->reviews_facebook_login_key;
            self::setIntegration($db, 'facebook_login', 'Facebook Login', $key);
            $key = $website->comments_vk_login_key != '' ? $website->comments_vk_login_key : $website->reviews_vk_login_key;
            self::setIntegration($db, 'vk_login', 'VK Login', $key);
        }
        $array = ['service = '.$db->quote('hypercomments'), 'service = '.$db->quote('disqus'),
            'service = '.$db->quote('facebook_comments'), 'service = '.$db->quote('vk_comments')];
        $query = $db->getQuery(true)
            ->select('*')
            ->from('#__gridbox_api')
            ->where('('.implode(' OR ', $array).')');
        $db->setQuery($query);
        $array = $db->loadObjectList();
        if (empty($array)) {
            $key = self::getCommentsKey($db, 'ba-item-facebook-comments', 'facebook-comments', 'app_id');
            self::setIntegration($db, 'facebook_comments', 'Facebook Comments', $key);
            $key = self::getCommentsKey($db, 'ba-item-hypercomments', 'hypercomments', 'app_id');
            self::setIntegration($db, 'hypercomments', 'Hypercomments', $key);
            $key = self::getCommentsKey($db, 'ba-item-vk-comments', 'vk-comments', 'app_id');
            self::setIntegration($db, 'vk_comments', 'VK Comments', $key);
            $key = self::getCommentsKey($db, 'ba-item-disqus', 'disqus', 'subdomen');
            self::setIntegration($db, 'disqus', 'Disqus', $key);
        }
        self::$storeHelper = new StoreHelper();
        self::$store = self::$storeHelper->getSettings();
        $rates = new \stdClass();
        $rates->categories = [];
        $rates->empty = [];
        foreach (self::$store->tax->rates as $key => $rate) {
            $rate->key = $key;
            if (!empty($rate->categories)) {
                $rates->categories[] = $rate;
            } else {
                $rates->empty[] = $rate;
            }
        }
        self::$taxRates = $rates;
        self::checkAppsOrder();
    }

    public static function calculateSalePrice($sales, $price, $sale_price, $id, $variation)
    {
        return self::prepareSalePrice($sales, $price, $sale_price, $id, $variation, []);
    }

    public static function prepareCartPrice($price, $thousand, $separator, $decimals, $rate = null)
    {
        return parent::prepareProductPrice($price, $thousand, $separator, $decimals, $rate);
    }

    public static function getCommentsKey($db, $plugin, $type, $ind)
    {
        $key = '';
        $items = self::searchComents($db, '#__gridbox_app', 'page_items', 'page_layout', $plugin);
        if (empty($items)) {
            $items = self::searchComents($db, '#__gridbox_pages', 'style', 'params', $plugin);
        }
        if (!empty($items)) {
            $data = json_decode($items);
            foreach ($data as $obj) {
                if ($obj->type != $type) {
                    continue;
                }
                $key = $obj->{$ind};
                break;
            }
        }

        return $key;
    }

    public static function searchComents($db, $table, $select, $column, $search)
    {
        $query = $db->getQuery(true)
            ->select($select)
            ->from($table)
            ->where($column.' LIKE '.$db->quote('%'.$search.'%'));
        $db->setQuery($query);
        $items = $db->loadResult();

        return $items;
    }

    public static function setIntegration($db, $service, $title, $key)
    {
        $obj = new \stdClass();
        $obj->type = 'integration';
        $obj->service = $service;
        $obj->title = $title;
        $obj->key = $key;
        $db->insertObject('#__gridbox_api', $obj);
    }

    public static function getNewPageAlias($type, $orig)
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true);
        $query->select('id')
            ->from('#__gridbox_pages')
            ->where('`page_alias` = '.$db->quote($type));
        $db->setQuery($query);
        $id = $db->loadResult();
        if (!empty($id)) {
            if (empty($orig)) {
                $type = self::increment($type);
            } else {
                $type = self::increment($orig);
            }
            $orig = $type;
            $type = self::stringURLSafe($type);
            if (empty($type)) {
                $type = $orig;
                $type = self::replace($type);
                $type = OutputFilter::stringURLSafe($type);
            }
            if (empty($type)) {
                $type = date('Y-m-d-H-i-s');
            }
            $type = self::getNewPageAlias($type, $orig);
        }

        return $type;
    }
    
    public static function getContentsCurl($url)
    {
        $http = HttpFactory::getHttp();
        $body = '';
        $host = 'balbooa.com';
        if($socket =@ fsockopen($host, 80, $errno, $errstr, 30)) {
            $data = $http->get($url);
            $body = $data->body;
            fclose($socket);
        }
        
        return $body;
    }
    
    public static function getSystemPlugin()
    {
        $flag = PluginHelper::isEnabled('system', 'gridbox');
        
        return $flag;
    }
    
    public static function getGlobal($body, $array)
    {
        if (!$body) {
            return $array;
        }
        $regex = '/\[global item=+(.*?)\]/i';
        preg_match_all($regex, $body, $matches, PREG_SET_ORDER);
        $db = Factory::getDBO();
        foreach ($matches as $match) {
            $query = $db->getQuery(true)
                ->select('*')
                ->from('#__gridbox_library')
                ->where('`global_item` = ' . $db->quote($match[1]));
            $db->setQuery($query);
            $result = $db->loadObject();
            $array[] = $result;
        }
        
        return $array;
    }

    public static function getBaforms($body, $array)
    {
        if (!$body) {
            return $array;
        }
        $regex = '/\[forms ID=+(.*?)\]/i';
        preg_match_all($regex, $body, $matches, PREG_SET_ORDER);
        $db = Factory::getDbo();
        $query = 'SHOW TABLES LIKE '.$db->quote('%baforms_forms');
        $db->setQuery($query);
        $result = $db->loadResult();
        if (!empty($result)) {
            foreach ($matches as $match) {
                if (!array_key_exists($match[1], $array)) {
                    $id = $match[1];
                    $obj = new \stdClass();
                    $query = $db->getQuery(true)
                        ->select('*')
                        ->from('#__baforms_forms')
                        ->where('`id` = ' .$db->quote($id));
                    $db->setQuery($query);
                    $obj->forms = $db->loadObject();
                    if (empty($obj)) {
                        continue;
                    }
                    $query = $db->getQuery(true)
                        ->select('*')
                        ->from('#__baforms_items')
                        ->where('`form_id` = ' .$db->quote($id));
                    $db->setQuery($query);
                    $obj->items = $db->loadObjectList();
                    $query = $db->getQuery(true)
                        ->select('*')
                        ->from('#__baforms_columns')
                        ->where('`form_id` = ' .$db->quote($id));
                    $db->setQuery($query);
                    $obj->columns = $db->loadObjectList();
                    $query = 'SHOW TABLES LIKE '.$db->quote('%baforms_forms_settings');
                    $db->setQuery($query);
                    $settings = $db->loadResult();
                    if (!empty($settings)) {
                        $query = $db->getQuery(true)
                            ->select('*')
                            ->from('#__baforms_forms_settings')
                            ->where('`form_id` = ' .$db->quote($id));
                        $db->setQuery($query);
                        $obj->settings = $db->loadObjectList();
                        $query = $db->getQuery(true)
                            ->select('*')
                            ->from('#__baforms_pages')
                            ->where('`form_id` = ' .$db->quote($id));
                        $db->setQuery($query);
                        $obj->pages = $db->loadObjectList();
                    }
                    $array[$id] = $obj;
                }
            }
        }
        
        return $array;
    }

    public static function getMainMenu($body, $array)
    {
        if (!$body) {
            return $array;
        }
        $regex = '/\[main_menu=+(.*?)\]/i';
        preg_match_all($regex, $body, $matches, PREG_SET_ORDER);
        if ($matches) {
            foreach ($matches as $match) {
                if (!array_key_exists($match[1], $array)) {
                    $id = $match[1];
                    $obj = new \stdClass();
                    $db = Factory::getDBO();
                    $query = $db->getQuery(true)
                        ->select('*')
                        ->from('#__modules')
                        ->where('module = '.$db->quote('mod_menu'))
                        ->where('`id` = ' .$db->quote($id));
                    $db->setQuery($query);
                    $obj->module = $db->loadObject();
                    if (empty($obj->module)) {
                        $query = $db->getQuery(true)
                            ->select('*')
                            ->from('#__modules')
                            ->where('client_id = 0')
                            ->where('published = 1')
                            ->where('position = '.$db->quote('main-menu'))
                            ->where('module = '.$db->quote('mod_menu'));
                        $db->setQuery($query);
                        $obj->module = $db->loadObject();
                        if (empty($obj->module)) {
                            $query = $db->getQuery(true)
                                ->select('*')
                                ->from('#__modules')
                                ->where('client_id = 0')
                                ->where('published = 1')
                                ->where('module = '.$db->quote('mod_menu'));
                            $db->setQuery($query);
                            $obj->module = $db->loadObject();
                        }
                    }
                    if (empty($obj->module)) {
                        continue;
                    }
                    $query = $db->getQuery(true)
                        ->select('*')
                        ->from('#__assets')
                        ->where('`id` = ' .$db->quote($obj->module->asset_id));
                    $db->setQuery($query);
                    $obj->asset = $db->loadObject();
                    $query = $db->getQuery(true)
                        ->select('*')
                        ->from('#__modules_menu')
                        ->where('`moduleid` = ' .$db->quote($obj->module->id));
                    $db->setQuery($query);
                    $obj->module_menu = $db->loadObject();
                    $params = $obj->module->params;
                    $params = json_decode($params);
                    $query = $db->getQuery(true);
                    $query->select("extension_id");
                    $query->from("#__extensions");
                    $query->where("type=" .$db->quote('component'))
                        ->where('element=' .$db->quote('com_gridbox'));
                    $db->setQuery($query);
                    $com_id = $db->loadResult();
                    
                    $query = $db->getQuery(true)
                        ->select('*')
                        ->from('#__menu_types')
                        ->where('`menutype` = ' .$db->quote($params->menutype));
                    $db->setQuery($query);
                    $obj->menu = $db->loadObject();
                    $query = $db->getQuery(true)
                        ->select('*')
                        ->from('#__menu')
                        ->where('`menutype` = ' .$db->quote($params->menutype))
                        ->where('`component_id` = ' .$db->quote($com_id))
                        ->order('`id` DESC');
                    $db->setQuery($query);
                    $obj->menu_items = $db->loadObjectList();
                    $array[$id] = $obj;
                }
            }
        }
        
        return $array;
    }

    public static function getTags()
    {
        $db = Factory::getDbo();
        $query = $db->getQuery(true);
        $query->select('*')
            ->from('#__gridbox_tags');
        $db->setQuery($query);
        $tags = $db->loadObjectList();

        return $tags;
    }

    public static function renderBootstrapModal($id, $title, $url)
    {
        $data = 'data-bs';
        $btn = '<button type="button" class="btn" '.$data.'-dismiss="modal">';
        $btn .= Text::_('JLIB_HTML_BEHAVIOR_CLOSE').'</button>';
        $params = ['title' => Text::_($title), 'url' => $url, 'height' => '400px',
            'width' => '800px', 'bodyHeight' => 70, 'modalWidth' => 80, 'footer' => $btn];
        
        $html = HTMLHelper::_(
            'bootstrap.renderModal',
            $id,
            $params
        );

        return $html;
    }

    public static function renderBootstrapModalBtn($target)
    {
        $data = 'data-bs';
        $btn = '<span '.$data.'-target="#'.$target.'" class="btn btn-primary" '.$data.'-toggle="modal">';
        $btn .= '<span class="icon-file"></span> '.Text::_('JSELECT').'</span>';

        return $btn;
    }
}

GridboxHelper::prepareGridbox();