<?php


use Mnv\Core\Config;
use Mnv\Core\Uploads\ImageSizes;


    /**
     * @method redirect
     * @param $location
     */
    function redirect($location) {
        if(!headers_sent()) {
            header('Location: '.$location);
            exit();
        }

        die('<script type="text/javascript">window.location=\''.$location.'\';</script><noscript><meta http-equiv="refresh" content="0;url='.$location.'" /></noscript>');
    }

    /**
     * Получить логитип из папки (uploads)
     *
     * @param $dir
     * @return array
     */
    function getLogoFile($dir) {
        $files = array();
        if (is_dir($dir)) {
            foreach (glob($dir . '/logo*.*', GLOB_BRACE) as $file) {
                $files[] = basename($file);
            }
        }

        return $files;
    }

    function file_get_contents_ssl($url) {

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_REFERER, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3000); // 3 sec.
        curl_setopt($ch, CURLOPT_TIMEOUT, 10000); // 10 sec.

        $result = curl_exec($ch);

        curl_close($ch);

        return $result;
    }

    /**
     * @param $language
     * @return mixed
     */
    function siteLanguage($language)
    {
        $siteLang = array();
        $siteLanguage = file_get_contents(GLOBAL_ROOT . '/includes/languages/'.$language.'.json');

        if (empty($siteLanguage) || ($siteLanguage == '[]')) return null;

        $siteLanguage = json_decode($siteLanguage, true);
        foreach ($siteLanguage as $key => $datum) {
            if (!empty($datum)) $siteLang[$datum['name']] = $datum['value'];
        }

        return $siteLang;

    }

    /**
     * @param $regex
     * @param $string
     * @return bool
     */
    function pregGetValue($regex, $string) {
		if (preg_match($regex, $string, $matches)) return $matches[1];
		return false;
	}

    /**
     * @param $document
     * @return string
     */
    function stripHtml($document) {
		$search = array ("'<script[^>]*?>.*?</script>'si", "'<[\/\!]*?[^<>]*?>'si", "'([\r\n])[\s]+'", "'&(quot|#34);'i", "'&(amp|#38);'i", "'&(lt|#60);'i", "'&(gt|#62);'i", "'&(nbsp|#160);'i", "'&(iexcl|#161);'i", "'&(cent|#162);'i", "'&(pound|#163);'i", "'&(copy|#169);'i");
		$replace = array ("", " ", "\\1", "\"", "&", "<", ">", " ", chr(161), chr(162), chr(163), chr(169));
		return trim(preg_replace($search, $replace, $document));
	}

    /**
     * @param $string
     * @return string
     */
    function unhtmlentities($string) {
        // replace numeric entities
		$string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string);
		$string = preg_replace('~&#([0-9]+);~e', 'chr("\\1")', $string);
        // replace literal entities
		$trans_tbl = get_html_translation_table(HTML_ENTITIES);
		$trans_tbl = array_flip($trans_tbl);
		return strtr($string, $trans_tbl);
	}

    /**
     * @param $string
     * @param int $length
     * @param string $etc
     * @param bool $break_words
     * @param bool $middlecut
     * @return null|string|string[]
     */
    function stringTruncate($string, $length = 80, $etc = '...', $break_words = false, $middlecut = false){
		if ($length == 0) return '';

		if (strlen($string) > $length){
			if($middlecut){
				$length -= strlen($etc);
				return substr($string, 0, ceil($length/2)).$etc.substr($string, -intval($length/2));
			} else {
				$length -= strlen($etc);
				if (!$break_words) $string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length+1));
				return substr($string, 0, $length).$etc;
			}
		} else {
			return $string;
		}
	}

    /**
     * Удаление елемента из массива
     * @param string $needle
     * @param $array
     * @param bool $all
     */
    function remove_from_array(string $needle, &$array, bool $all = true) {
        if (!$all) {
            if (FALSE !== $key = array_search($needle, $array)) unset($array[$key]);
            return;
        }
        foreach (array_keys($array, $needle) as $key) {
            unset($array[$key]);
        }
    }


    function fetch_products_addFilterConditions($alcohol, $color, $sugar, $year, $mill, $typeAlc) {

        $newArray = [];

        if (!empty($country)) foreach ($country as $co) $newArray[$co] = $co;
        if (!empty($alcohol))  foreach ($alcohol as $alc) $newArray[$alc] = $alc;
        if (!empty($color))  foreach ($color as $col) $newArray[$col] = $col;
        if (!empty($sugar)) foreach ($sugar as $sug) $newArray[$sug] = $sug;
        if (!empty($year))  foreach ($year as $ye) $newArray[$ye] = $ye;

//        if (!empty($mill)) foreach ($mill as $mil) $newArray[$mil] = str_replace(",", ".", str_replace("ml", "", $mil) / 1000);
        if (!empty($mill)) foreach ($mill as $mil) $newArray[$mil] = str_replace(",", ".",  $mil / 1000);
        if (!empty($typeAlc)) foreach ($typeAlc as $tp) $newArray[$tp] = $tp;

//        print_r($newArray);
        if (!empty($newArray)) connect()->in('value', $newArray);

    }


    function fetch_articles_addQueryConditions($query, $match, &$fields, &$orderBy)
    {
        if (empty($query)) return false;

        switch ($match) {
            case 'like':
                if(preg_match_all('/\w+/', $query, $matches)){
                    foreach($matches[0] as $word){
                        connect()->grouped(function($q) use ($word) {
                            $q->like('title', "%$word%")->orLike('content', "%$word%")->orLike('keywords',"%$word%");
                        });
                    }
                }
                break;
            case 'all':
                $filter = preg_replace('/\s+/', ' +', '+'.trim($query));
                connect()->whereAgainst('title, content, keywords',  $filter);
                $fields .= ", MATCH(title, content, keywords) AGAINST ('". $query ."') AS relevance";
                if(empty($orderBy)) connect()->orderBy('relevance DESC');
                break;
            case 'exact':
                connect()->whereAgainst('title, content, keywords',  $query);
                $fields .= ", MATCH(title, content, summary) AGAINST ('". $query."')";
                if(empty($orderBy)) connect()->orderBy('');
                break;
            case 'advanced':
                $relevance = trim(preg_replace('/[\+\-\"\~\(\)\* ]+/', ' ', trim($query)));
                connect()->whereAgainst('title, content, keywords',  $query);
                $fields .= ", MATCH(title, content, summary) AGAINST ('". $relevance."') AS relevance";
                if(empty($orderBy)) connect()->orderBy('relevance DESC');
                break;
            case 'any':
            default:
                $query = substr($query, 0, 64);
                $query = preg_replace("/[^\w\x7F-\xFF\s]/", " ", $query);
                connect()->grouped(function($q) use ($query) {
                    $q->like('title', "%$query%")->orLike('content', "%$query%")->orLike('keywords',"%$query%");
                });
                break;
        }
    }
    function fetch_articles_calculatePopularity($orderBy)
    {
		global $gmNow;

//		print_r($orderBy);

		if (!empty($orderBy) && strpos($orderBy, 'popularity') === false) return false;

       $hour_adjustment = Config::getValue('hour_adjustment');
       $minute_adjustment = Config::getValue('minute_adjustment');
		if (!Config::getValue('statistics_enabled')) return false;

		if (strpos($orderBy, 'popularityLast14days') !== false) {
			/* last 14 days */
			$dateEnd    = gmdate('Y-m-d', strtotime("$hour_adjustment hours $minute_adjustment minutes"));
			$dateStart  = gmdate('Y-m-d', strtotime("-2 week $hour_adjustment hours $minute_adjustment minutes"));
			$period     = 'popularityLast14days';
		} elseif(strpos($orderBy, 'popularityLast30days') !== false){
			/* last 30 days */
			$dateEnd    = gmdate('Y-m-d', strtotime("$hour_adjustment hours $minute_adjustment minutes"));
			$dateStart  = gmdate('Y-m-d', strtotime("-30 days$hour_adjustment hours $minute_adjustment minutes"));
			$period     = 'popularityLast30days';
		} elseif(strpos($orderBy, 'popularityLastMonth') !== false){
			/* last month */
			$dateEnd    = gmdate('Y-m-d', mktime($hour_adjustment, $minute_adjustment, 0, date('n'), 0));
			$dateStart  = gmdate('Y-m-01', strtotime("-1 month $hour_adjustment hours $minute_adjustment minutes"));
			$period     = 'popularityLastMonth';
		} elseif(strpos($orderBy, 'popularityYesterday') !== false){
			/* yesterday */
			$dateEnd    = $dateStart = gmdate('Y-m-d', strtotime("-1 day $hour_adjustment hours $minute_adjustment minutes"));
			$period     = 'popularityYesterday';
		} else {
			/* last 7 days */
			$dateEnd    = gmdate('Y-m-d', strtotime("$hour_adjustment hours $minute_adjustment minutes"));
			$dateStart  = gmdate('Y-m-d', strtotime("-1 week $hour_adjustment hours $minute_adjustment minutes"));
			$period     = 'popularityLast7days';
		}
		/* если последнее обновление было сегодня , то не обновлять */
//        Config::getValue('last_article_'.$period.'_update');
		if (!empty(Config::getValue('last_article_'.$period.'_update')) && Config::getValue('last_article_'.$period.'_update') == adjustTime($gmNow, false, 'Y-m-d'))
		    return false;

		$dateStart = adjustTime($dateStart.' 00:00:00', true);
		$dateEnd   = adjustTime($dateEnd.' 23:59:59', true);

        connect()->between('visitDate', $dateStart, $dateEnd);
        connect()->where('typeId', 3);
        $articles = connect('stats_visits')->usingJoin('stats_article_visits', 'visitId')->select("articleId, COUNT(*) AS $period")
            ->groupBy('articleId')->indexKey('articleId')->valueKey($period)->getAllIndexes();

		/* сбросить все предыдущие счетчики популярности */
        connect('articles')->update([$period => 0]);
		foreach($articles as $articleId => $popularity) {
//            dbRawQuery("UPDATE LOW_PRIORITY $table SET ".implode(", ",$fieldSets)." $where");
//            connect()->query('UPDATE LOW_PRIORITY FROM test WHERE id=?', [10])->exec();
		    // DB_UPDATE_LOW_PRIORITY
            connect('articles')->where('articleId', $articleId)->updateLow([$period => $popularity]);
        }

		/* сохранение даты обновления */
		$setting['codename']            = 'last_article_'.$period.'_update';
		$setting['value']               = adjustTime(gmdate('Y-m-d H:i:s'), false, 'Y-m-d');

        Config::init()->set($setting['codename'], $setting['value']);

        connect()->table('settings')->replace([$setting]);


		return true;
	}
    function fetch_articles_addSectionConditions($section, $noSubsections) {
		global $SECTIONS;

		if(!$section) {
            return false;
        }

		$sectionIds = array();
		$sections = explode(',', $section);

		foreach ($sections as $section) {
			$section = trim($section);
			if (!is_numeric($section)) {
				foreach ($SECTIONS as $sectionItem) {
                    if ($sectionItem['fileName'] == $section) {
                        $section = $sectionItem['sectionId'];
                        break;
                    }
                }
			}
			if (!empty($SECTIONS[$section])) {
				$sectionIds[] = $section;
				if ($noSubsections == false && !empty($SECTIONS[$section]['allChildren'])) {
                    $sectionIds = array_merge($sectionIds, $SECTIONS[$section]['allChildren']);
                }
			}
		}
		if (!empty($sectionIds)) {
            connect()->in('sectionId', $sectionIds);
        }
		return true;
	}
    function fetch_articles_addSkipConditions($skip) {
		global $SECTIONS, $fetchedArticles;

		if(is_null($skip)) {
            return false;
        }
		if(!is_array($skip = explode(',', str_replace(' ', '', $skip)))) {
            return false;
        }

		$skippedSections = array();
		$skippedArticles = array();
		foreach($skip as $skipItem){
			/* пропустить articleID */
			if(is_numeric($skipItem) && empty($fetchedArticles[$skipItem])){
				$skippedArticles[] = $skipItem;

			/* пропустить статью набор */
			} elseif(!empty($fetchedArticles[$skipItem])) {
				$skippedArticles += $fetchedArticles[$skipItem];

			/* Специальный параметр " allPrevious " - пропустить все уже полученные статьи */
			} elseif($skipItem == 'allPrevious' && !empty($fetchedArticles)) {
				foreach($fetchedArticles as $articleSet) {
                    $skippedArticles = array_merge($skippedArticles, $articleSet);
                }

			/* специальный параметр " hiddenSections " - пропустить все статьи в скрытых разделах */
			} elseif($skipItem == 'hiddenSections') {
				foreach($SECTIONS as $sectionItem){
					if ($sectionItem['status'] == 'H') {
						$skippedSections[] = $sectionItem['sectionId'];
						if (!empty($SECTIONS[$skipSectionId]['allChildren'])) {
                            $skippedSections += $SECTIONS[$skipSectionId]['allChildren'];
                        }
					}
				}

			/* пропустить раздел, sectionID , имени или имя fileName (section-X) */
			} elseif(strpos($skipItem, 'section-') !== false) {
				$skipSectionId = str_replace('section-', '', $skipItem);
				if(!is_numeric($skipSectionId)){
					foreach($SECTIONS as $sectionItem) {
                        if ($sectionItem['fileName'] == $skipSectionId) {
                            $skipSectionId = $sectionItem['sectionId'];
                            break;
                        }
                    }
				}
				$skippedSections[] = $skipSectionId;
				if(!empty($SECTIONS[$skipSectionId]['allChildren'])) {
                    $skippedSections += $SECTIONS[$skipSectionId]['allChildren'];
                }

			}
		}
		if (!empty($skippedArticles)) connect()->notIn('articleId', array_unique($skippedArticles));
        if (!empty($skippedSections))  connect()->notIn('sectionId', array_unique($skippedSections));
//		    $where[] = "articleId NOT IN (".implode(',', array_unique($skippedArticles)).")";
//		    $where[] = "sectionId NOT IN (".implode(',', array_unique($skippedSections)).")";
		return true;
	}

    function fetch_articles_filterFields(&$fields) {
		/* освобождая от возможных ошибок */
//		$fields = str_replace(' ', '', $fields);
		$fields = explode(',', $fields);
		$fields = array_flip($fields);

		/* Поля, которые должны представить */
		if (empty($fields['articleId'])) $fields['articleId'] = 1;
		$fields = implode(',', array_keys($fields));
		return $fields;
	}


    function fetch_products_calculatePopularity($orderBy)
    {
        global $gmNow;

        //		print_r($orderBy);

        if (!empty($orderBy) && strpos($orderBy, 'popularity') === false) return false;

        $hour_adjustment = Config::getValue('hour_adjustment');
        $minute_adjustment = Config::getValue('minute_adjustment');
        if (!Config::getValue('statistics_enabled')) return false;

        if (strpos($orderBy, 'popularityLast14days') !== false) {
            /* last 14 days */
            $dateEnd    = gmdate('Y-m-d', strtotime("$hour_adjustment hours $minute_adjustment minutes"));
            $dateStart  = gmdate('Y-m-d', strtotime("-2 week $hour_adjustment hours $minute_adjustment minutes"));
            $period     = 'popularityLast14days';
        } elseif(strpos($orderBy, 'popularityLast30days') !== false){
            /* last 30 days */
            $dateEnd    = gmdate('Y-m-d', strtotime("$hour_adjustment hours $minute_adjustment minutes"));
            $dateStart  = gmdate('Y-m-d', strtotime("-30 days$hour_adjustment hours $minute_adjustment minutes"));
            $period     = 'popularityLast30days';
        } elseif(strpos($orderBy, 'popularityLastMonth') !== false){
            /* last month */
            $dateEnd    = gmdate('Y-m-d', mktime($hour_adjustment, $minute_adjustment, 0, date('n'), 0));
            $dateStart  = gmdate('Y-m-01', strtotime("-1 month $hour_adjustment hours $minute_adjustment minutes"));
            $period     = 'popularityLastMonth';
        } elseif(strpos($orderBy, 'popularityYesterday') !== false){
            /* yesterday */
            $dateEnd    = $dateStart = gmdate('Y-m-d', strtotime("-1 day $hour_adjustment hours $minute_adjustment minutes"));
            $period     = 'popularityYesterday';
        } else {
            /* last 7 days */
            $dateEnd    = gmdate('Y-m-d', strtotime("$hour_adjustment hours $minute_adjustment minutes"));
            $dateStart  = gmdate('Y-m-d', strtotime("-1 week $hour_adjustment hours $minute_adjustment minutes"));
            $period     = 'popularityLast7days';
        }
        /* если последнее обновление было сегодня , то не обновлять */
        //        Config::getValue('last_article_'.$period.'_update');
        if (!empty(Config::getValue('last_article_'.$period.'_update')) && Config::getValue('last_article_'.$period.'_update') == adjustTime($gmNow, false, 'Y-m-d'))
            return false;

        $dateStart = adjustTime($dateStart.' 00:00:00', true);
        $dateEnd   = adjustTime($dateEnd.' 23:59:59', true);

        connect()->between('visitDate', $dateStart, $dateEnd);
        connect()->where('typeId', 9);
        $products = connect('stats_visits')->usingJoin('stats_product_visits', 'visitId')->select("productId, COUNT(*) AS $period")
            ->groupBy('productId')->indexKey('productId')->valueKey($period)->getAllIndexes();

        /* сбросить все предыдущие счетчики популярности */
        connect('products')->update([$period => 0]);
        foreach($products as $productId => $popularity) {
            // dbRawQuery("UPDATE LOW_PRIORITY $table SET ".implode(", ",$fieldSets)." $where");
            connect('products')->where('productId', $productId)->updateLow([$period => $popularity]); // DB_UPDATE_LOW_PRIORITY
        }

        /* сохранение даты обновления */
        $setting['codename']            = 'last_article_'.$period.'_update';
        $setting['value']               = adjustTime(gmdate('Y-m-d H:i:s'), false, 'Y-m-d');

        Config::init()->set($setting['codename'], $setting['value']);

        connect('settings')->replace([$setting]);


        return true;
    }
    function fetch_products_addSkipConditions($skip) {
        global $SECTIONS, $fetchedProducts;

        if(is_null($skip)) {
            return false;
        }
        if(!is_array($skip = explode(',', str_replace(' ', '', $skip)))) {
            return false;
        }

        $skippedSections = array();
        $skippedProducts = array();
        foreach($skip as $skipItem){
            /* пропустить articleID */
            if(is_numeric($skipItem) && empty($fetchedProducts[$skipItem])){
                $skippedProducts[] = $skipItem;

                /* пропустить статью набор */
            } elseif(!empty($fetchedProducts[$skipItem])) {
                $skippedProducts += $fetchedProducts[$skipItem];

                /* Специальный параметр " allPrevious " - пропустить все уже полученные статьи */
            } elseif($skipItem == 'allPrevious' && !empty($fetchedProducts)) {
                foreach($fetchedProducts as $articleSet) {
                    $skippedProducts = array_merge($skippedProducts, $articleSet);
                }

                /* специальный параметр " hiddenSections " - пропустить все статьи в скрытых разделах */
            } elseif($skipItem == 'hiddenSections') {
                foreach($SECTIONS as $skipSectionId => $sectionItem){
                    if ($sectionItem['status'] == 'H') {
                        $skippedSections[] = $sectionItem['sectionId'];
                        if (!empty($SECTIONS[$skipSectionId]['allChildren'])) {
                            $skippedSections += $SECTIONS[$skipSectionId]['allChildren'];
                        }
                    }
                }

                /* пропустить раздел, sectionID , имени или имя fileName (section-X) */
            } elseif(strpos($skipItem, 'section-') !== false) {
                $skipSectionId = str_replace('section-', '', $skipItem);
                if(!is_numeric($skipSectionId)){
                    foreach($SECTIONS as $sectionItem) {
                        if ($sectionItem['fileName'] == $skipSectionId) {
                            $skipSectionId = $sectionItem['sectionId'];
                            break;
                        }
                    }
                }
                $skippedSections[] = $skipSectionId;
                if(!empty($SECTIONS[$skipSectionId]['allChildren'])) {
                    $skippedSections += $SECTIONS[$skipSectionId]['allChildren'];
                }

            }
        }
        if (!empty($skippedProducts)) connect()->notIn('productId', array_unique($skippedProducts));
        if (!empty($skippedProducts))  connect()->notIn('sectionId', array_unique($skippedSections));
        //		    $where[] = "articleId NOT IN (".implode(',', array_unique($skippedArticles)).")";
        //		    $where[] = "sectionId NOT IN (".implode(',', array_unique($skippedSections)).")";
        return true;
    }
    function fetch_products_filterFields(&$fields) {
        /* освобождая от возможных ошибок */
    //		$fields = str_replace(' ', '', $fields);
        $fields = explode(',', $fields);
        $fields = array_flip($fields);

        /* Поля, которые должны представить */
        if (empty($fields['productId'])) $fields['productId'] = 1;
        $fields = implode(',', array_keys($fields));
        return $fields;
    }
	
	 /**
     * @param $query
     * @param $match
     * @param $where
     * @param $fields
     * @param $orderBy
     * @return bool
     */
    function fetch_brands_addQueryConditions($query, $match, &$where, &$fields, &$orderBy)
    {
		if(empty($query)) return false;

		switch ($match) {
			case 'like':
				if (preg_match_all('/\w+/', $query, $matches)) {
					foreach ($matches[0] as $word) {
                        connect()->like('name', "%$word%")->orLike('content', "%$word%")->orLike('keywords',"%$word%");
//						$where[] = "(name LIKE '%".$word."%' OR content LIKE '%".$word."%' OR summary LIKE '%".$word."%')";
					}
				}
			break;
			case 'all':
				$filter = preg_replace('/\s+/', ' +', '+'.trim($query));
                connect()->whereAgainst('name, content, summary',  $filter);
//				$where[] = "MATCH(name, content, summary) AGAINST ('".$filter."' IN BOOLEAN MODE)";
				$fields .= ", MATCH(name, content, summary) AGAINST ('".$query."') AS relevance";
				if(empty($orderBy)) $orderBy = 'relevance DESC';
			break;
			case 'exact':
                connect()->whereAgainst('name, content, summary',  $query);
//				$where[] = "MATCH(name, content, summary) AGAINST ('\"".$query."\"' IN BOOLEAN MODE)";
				$fields .= ", MATCH(name, content, summary) AGAINST ('".$query."')";
				if(empty($orderBy)) $orderBy = '';
			break;
			case 'advanced':
				$relevance = trim(preg_replace('/[\+\-\"\~\(\)\* ]+/', ' ', trim($query)));
                connect()->whereAgainst('name, content, summary',  $query);
//				$where[] = "MATCH(name, content, summary) AGAINST ('".$query."' IN BOOLEAN MODE)";
				$fields .= ", MATCH(name, content, summary) AGAINST ('".$relevance."') AS relevance";
				if(empty($orderBy)) $orderBy = 'relevance DESC';
			break;
			case 'any':
			default:
				$query = substr($query, 0, 64);
				$query = preg_replace("/[^\w\x7F-\xFF\s]/", " ", $query);
//				$where[] = "(name LIKE '%".$query."%' OR content LIKE '%".$query."%' OR summary LIKE '%".$query."%' OR keywords LIKE '%".$query."%')";
                connect()->like('name', "%$query%")->orLike('content', "%$query%")->orLike('keywords',"%$query%");
			break;
		}
	}

    /**
     * @param $key
     * @param $params
     * @param string $default
     * @return bool|string
     */
    function fetch_getParam($key, $params, $default = '') {
        if (!isset($params[$key])) {
            return $default;
        }

        if(!empty($params[$key])) {
            return $params[$key];
        }

        return false;
    }

    /**
     * @param $sectionId
     * @return array
     */
    function getSectionParents($sectionId): array
    {
		global $SECTIONS;
		if (!empty($SECTIONS[$sectionId]['parents'])) {
            foreach ($SECTIONS[$sectionId]['parents'] as $parentId) {
                $sectionParents[] = $SECTIONS[$parentId];
            }
        }
		$sectionParents[] = $SECTIONS[$sectionId];
		return $sectionParents;
	}

    /**
     * @param $sectionId
     * @return array|false|mixed|string|null
     */
    function getSectionParent($sectionId) {
        if (is_numeric($sectionId) && $sectionId > 0) {
            return connect()->table('sections')->select('sectionId, name, url')->where('sectionId', $sectionId)->get('array');
        }

        return null;
    }



    /**
     * @return bool
     */
    function updateLoadTime()
    {
		global $visitId, $scriptStartTime;

		if (!Config::getValue('statistics_enabled')) {
            return false;
        }

		/* экономя время нагрузки */
		$loadTime = getmicrotime() - $scriptStartTime;
        $loadTime =  number_format($loadTime, 4, '.', '');

        connect()->table('stats_visits')->where('visitId', $visitId)->update(['loadTime' => $loadTime]);
	}

    function writeRssVisit($sectionId)
    {
		if (!Config::getValue('statistics_enabled')) {
            return false;
        }
		$visitId = writeVisit(7);
        connect()->table('stats_rss_visits')->insert(['visitId' => $visitId, 'sectionId' => $sectionId]);
	}

	
    /**
     * @param $errorCode
     * @return bool
     */
    function writeErrorVisit($errorCode)
    {
		if (!Config::getValue('statistics_enabled')) {
            return false;
        }

		$visitId = writeVisit(6);
		$requestUri = !empty($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
        $referer = !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';

        $data = [
            'visitId'       => $visitId,
            'errorCode'     => $errorCode,
            'requestUri'    => $requestUri,
            'referer'       => $referer
        ];

        connect('stats_error_visits')->insert($data);
	}

    /**
     * @param $query
     * @param $page
     * @return bool
     */
    function writeSearchVisit($query, $page)
    {

		if (!Config::getValue('statistics_enabled')) {
            return false;
        }
		$visitId = writeVisit(4);
        $data = [
            'visitId'       => $visitId,
            'searchQuery'   => $query,
            'searchPage'    => $page
        ];
        connect('stats_search_visits')->insert($data);
	}

    /**
     * @param $productId
     * @return bool
     */
    function writeProductVisit($productId)
    {
		if (!Config::getValue('statistics_enabled')) {
            return false;
        }
		$visitId = writeVisit(9);
        $data = [
            'visitId'   => $visitId,
            'productId' => $productId,
            'visitorIp' => \Mnv\Core\UserInfo::get_ip()
        ];
        connect('stats_product_visits')->insert($data);
	}

    /**
     * @param $articleId
     * @return bool
     */
    function writeArticleVisit($articleId)
    {
        if (!Config::getValue('statistics_enabled')) {
            return false;
        }
        $visitId = writeVisit(3);
        $data = [
            'visitId'   => $visitId,
            'articleId' => $articleId,
            'visitorIp' => \Mnv\Core\UserInfo::get_ip()
        ];
        connect('stats_article_visits')->insert($data);
    }

    /**
     * @param $articleId
     * @return bool
     */
    function articleViewCounter($articleId)
    {
		global $userIp;
        if (!Config::getValue('statistics_enabled')) {
            return false;
        }
		if ($articleIds = connect('articles')->select('articleId, counter')->where('articleId', $articleId)->get()){
            $article_visit['articleId'] = $articleIds->articleId;
            $article_visit['visitorIp'] = $userIp;
            if (!connect('article_visits')->where('visitorIp', $userIp)->where('articleId', $articleId)->getAll()) {
                if (connect('article_visits')->insert($article_visit)) {
                    connect('articles')->where('articleId', $articleId)->update([
                        'counter' => ($articleIds->counter + 1)
                    ]);
                }
            }
        }
	}

    /**
     * @param $sectionId
     * @param $page
     * @return bool
     */
    function writeSectionVisit($sectionId, $page)
    {

		if(!Config::getValue('statistics_enabled')) return false;
		$visitId = writeVisit(2);
        connect()->table('stats_section_visits')->insert([
            'visitId'   => $visitId,
            'sectionId' => $sectionId,
            'page'      => $page
        ]);
	}

    /**
     * @param $typeId
     * @return bool|int
     */
    function writeVisit($typeId) {
		global $visitorIp, $visitorId, $visitId, $smarty, $scriptStartTime, $gmNow;

		if(!Config::getValue('statistics_enabled')) {
            return false;
        }

		$cookieName = 'VisID';
		$date = gmdate('Y-m-d H:i:s');
		$visitorIp = $_SERVER['REMOTE_ADDR'];
		$isFirst = 0;
		$isBot = 0;
		$userAgentId = 0;
		$userAgent = '';

		if (!empty($_COOKIE[$cookieName])) {
			/* Уже известно, посетитель */
			$visitorId = (int) $_COOKIE[$cookieName];

            $visitorId = connect()->table('stats_visitors')->select('visitorId')->where('visitorId', $visitorId)->getValue();
		}

		if (empty($visitorId)) {
			/* Новый посетитель или бот */
			if (!empty($_SERVER['HTTP_USER_AGENT'])) {
				$userAgent =  substr($_SERVER['HTTP_USER_AGENT'], 0, 255);
				$isBot = (int) preg_match("/(" . Config::getValue('bot_id_regexp') . ")/i", $_SERVER['HTTP_USER_AGENT']);
                if(!($userAgentId = (int) connect('stats_user_agents')->select('userAgentId')->where('userAgent', $userAgent)->getValue())) {
                    connect('stats_user_agents')->insert(['userAgentId' => $userAgentId, 'userAgent' => $userAgent, 'isBot' => $isBot]);
                }
			}

			$referer = !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
			$refId   = preg_match("/refid=(\d+)/i", $_SERVER['REQUEST_URI'], $matches) ? (int) $matches[1] : 0;
			$smarty->assign('referer', $referer);
			if ($isBot) {
				/* Если бот, получить существующих visitorId по userAgentId */
                $visitorId = connect('stats_visitors')->select('visitorId')->where('userAgentId', $userAgentId)->getValue();
			} else {
				/* попытаться получить существующего посетителя , если он имеет отключили */
                $visitorId = connect('stats_visitors')->select('visitorId')
                    ->where('userAgentId', $userAgentId)
                    ->where('visitorIp', $visitorIp)
                    ->where('firstVisitOn','>', "'$gmNow' - INTERVAL 2 HOUR")->getValue();
			}

			/* вставить нового посетителя */
			if (empty($visitorId)) {
                $data = [
                    'firstVisitOn'  => $date,
                    'referer'       => $referer,
                    'refid'         => $refId,
                    'visitorIp'     => $visitorIp,
                    'userAgentId'   => $userAgentId
                ];
                $visitorId = connect()->table('stats_visitors')->insert($data);
				$isFirst = 1;
			}
			setcookie($cookieName, $visitorId, time() + 31104000, SITE_URI.'/'); /* expires in 360 days */
		}

		/* сохранения визит */
		$loadTime = getmicrotime() - $scriptStartTime;
        $data = [
            'visitDate' => $date,
            'visitorId' => $visitorId,
            'typeId'    => $typeId,
            'isFirst'   => $isFirst,
            'loadTime'  => number_format($loadTime, 4, '.', '')
        ];
        $visitId = connect()->table('stats_visits')->insert($data);

		$smarty->assign('visitorId', $visitorId);
		$smarty->assign('visitorIp', $visitorIp);
		$smarty->assign('visitId', $visitId);

		return $visitId;
	}

    // or array version
    function buildTreeFromArray($items, $indexKey, $key, $subArray) {

        $childs = [];

        foreach ($items as &$item) {
            $childs[$item[$indexKey] ?? 0][] = &$item;
        }

        unset($item);

        foreach ($items as &$item) {
            if (isset($childs[$item[$key]])) {
                $item[$subArray] = $childs[$item[$key]];
            }
        }

        return $childs[0] ?? [];
    }

    /**
     * @return mixed
     */
    function unknownUser()
    {
        $user['fullName']  = 'unknown';
        $user['loginName'] = 'unknown';

        return $user;
	}


    /**
     * @param $sections
     * @return mixed
     */
    function prepareSections($sections, $imageType)
    {
		foreach($sections as $i => $section) {
			$sectionIndexes[$section['sectionId']] = $i;
			if(!empty($section['addedOn'])) $sections[$i]['addedOn'] = adjustTime($section['addedOn']);
			if(!empty($section['modifiedOn'])) $sections[$i]['modifiedOn'] = adjustTime($section['modifiedOn']);

			/* добавив информацию о разделе */
			if(!empty($section['sectionId']) && !empty($SECTIONS[$section['sectionId']])) $sections[$i]['section'] = $SECTIONS[$section['sectionId']];
			#if(!empty($section['sectionId'])) $section[$section['sectionId']]->parents = getSectionParents($section['sectionId']);
//
			/* сбор идентификаторы пользователей из addedBy и ModifiedBy */
			if(!empty($section['addedBy']))    $userIDs[$section['addedBy']]    = $section['addedBy'];
			if(!empty($section['modifiedBy'])) $userIDs[$section['modifiedBy']] = $section['modifiedBy'];

		}


		/* получить изображение раздела */
		if (!empty($sectionIndexes)) {
		    $orderBy = $imageType == 'image' ? '' : 'orderBy ASC';
		    if (!empty($imageType) && !is_array($imageType)) {
		        connect()->where('type', $imageType);
		    } else {
		        connect()->in('type', $imageType);
		    }

		    $images = connect()->table('section_images')->orderBy($orderBy)->in('sectionId', array_keys($sectionIndexes))->orderBy('orderBy')->getAll('array');
			foreach ($images as $imageId => $image) {
				$sectionIndex = $sectionIndexes[$image['sectionId']];
                if ($file = connect()->table('files')->select('fileId, directory, path, fileName, size, mime_type')->where('fileId', $image['fileId'])->get('array')) {
                    if ($image['type'] === 'general') {
                        $sections[$sectionIndex]['image'] = ImageSizes::init()->get($image, $file);
                    } elseif ($image['type'] === 'gallery')  {
                        $sections[$sectionIndex]['gallery'][$imageId]  = ImageSizes::init()->get($image, $file);
                    } else {
                        $sections[$sectionIndex]['docs'][$imageId]   = ImageSizes::init()->get($image, $file);
                    }
                }
    		}
		}

//        print_r($sections);

		return $sections;
	}

    /**
     * prepareSection
     *
     * @param $section
     * @return mixed
     */
    function prepareSection($section)
    {
        if(!empty($section['addedOn'])) $section['addedOn'] = adjustTime($section['addedOn']);
        if(!empty($section['modifiedOn'])) $section['modifiedOn'] = adjustTime($section['modifiedOn']);

        /* получении информации о пользователях, которые создали и изменили раздел */
//        if(!empty($section['addedBy'])) $userIDs[] = $section['addedBy'];
//        if(!empty($section['modifiedBy'])) $userIDs[] = $section['modifiedBy'];

//        if(!empty($section['sectionId'])) $section['parents'] = getSectionParents($section['sectionId']);

        /* получить изображение раздела */
        $section['image'] = array();
        $images = connect()->table('section_images')->where('sectionId', $section['sectionId'])->orderBy('orderBy')->getAll('array');
        foreach ($images as $imageId => $image) {
            if ($file = connect()->table('files')->select('fileId, directory, path, fileName, size')->where('fileId', $image['fileId'])->get('array')) {
                if ($image['type'] === 'general') {
                    $section['image'] = ImageSizes::init()->get($image, $file);
                } else if ($image['type'] === 'gallery') {
                    $section['gallery'][$imageId] = ImageSizes::init()->get($image, $file);
                } else {
                    $section['docs'][$imageId] = ImageSizes::init()->get($image, $file);
                }
            }
        }

        /* получение описания раздел и ключевые слова */
        if ($sectionInfo = connect()->table('sections')->select('keywords, description, content')->where('sectionId', $section['sectionId'])->get('array')) {
            $section['keywords']      = $sectionInfo['keywords'];
            $section['description']   = $sectionInfo['description'];
            $section['content']       = $sectionInfo['content'];
        }

//        print_r($section);
        return $section;
    }


    /**
     * prepareArticles
     *
     * @param $articles
     * @param $sectionInfo
     * @param $parentsInfo
     * @param $image
     * @param $image_type
     * @return mixed
     */
    function prepareArticles($articles, $sectionInfo, $parentsInfo, $image, $image_type)
    {
		global $SECTIONS;

		foreach ($articles as $i => $article) {
			$articleIndexes[$article['articleId']] = $i;
			if(!empty($article['addedOn']))    $articles[$i]['addedOn']     = adjustTime($article['addedOn']);
			if(!empty($article['publishedOn'])) $articles[$i]['publishedOn'] = adjustTime($article['publishedOn']);

			/* добавив информацию о разделе если sectionInfo = true */
			if ($sectionInfo && !empty($article['sectionId']) && !empty($SECTIONS[$article['sectionId']])) {
                $articles[$i]['section'] = $SECTIONS[$article['sectionId']];
            }
            
			/* добавление информации о родительских разделах */
            if ($parentsInfo && !empty($article['sectionId'])) {
                $articles[$article['articleId']]['parents'] = getSectionParents($article['sectionId']);
            }
			/* сбор идентификаторы пользователей из addedBy */
			if(!empty($article['addedBy'])) {
			    $articles[$i]['user'] = connect('users')->select('userId, fullName, phone, email')->where('userId', $article['addedBy'])->get('array');
            }
		}

        /* получать изображения в статье*/
        if (!empty($articleIndexes) && $image) {
            $orderBy = $image_type == 'image' ? '' : 'orderBy ASC';
            if (!empty($image_type) && !is_array($image_type)) {
                connect()->where('type',  $image_type);
            } else {
                connect()->in('type', $image_type);
            }

            $images = connect()->table('article_images')->orderBy($orderBy)->in('articleId', array_keys($articleIndexes))->getAll('array');
            foreach ($images as $imageId => $image) {
                $articleIndex = $articleIndexes[$image['articleId']];
                if ($file = connect()->table('files')->select('fileId, directory, path, fileName, size')->where('fileId',  $image['fileId'])->get('array')) {
                    if ($image['type'] === 'general') {
                        $articles[$articleIndex]['image'] = ImageSizes::init()->get($image, $file);
                    } elseif ($image['type'] === 'gallery') {
                        $articles[$articleIndex]['gallery'][$imageId] = ImageSizes::init()->get($image, $file);
                    } else {
                        $articles[$articleIndex]['docs'][$imageId] = ImageSizes::init()->get($image, $file);
                    }
                }
            }
		}

//        print_r($articles);
		return $articles;
	}

    /**
     * prepareArticle
     *
     * @param $article
     * @return mixed
     */
    function prepareArticle($article) {
		global $SECTIONS;

		if(!empty($article['addedOn'])) $article['addedOn'] = adjustTime($article['addedOn']);
		if(!empty($article['modifiedOn'])) $article['modifiedOn'] = adjustTime($article['modifiedOn']);
		if(!empty($article['publishedOn'])) $article['publishedOn'] = adjustTime($article['publishedOn']);

		/* получать статьи изображения */
		if(!empty($article['articleId'])) {
            $images = connect()->table('article_images')->where('articleId', $article['articleId'])->orderBy('orderBy', 'ASC')->getAll('array');
            foreach ($images as $imageId => $image) {
                if ($file = connect()->table('files')->select('fileId, directory, path, fileName, size')->where('fileId', $image['fileId'])->get('array')) {
                    if ($image['type'] === 'general') {
                        $article['image'] = ImageSizes::init()->get($image, $file);
                    } elseif ($image['type'] === 'gallery') {
                        $article['gallery'][$imageId]  = ImageSizes::init()->get($image, $file);
                    } else {
                        $article['docs'][$imageId]  = ImageSizes::init()->get($image, $file);
                    }
                }
            }
        }

		/* получении информации о пользователях, которые создали и изменили статью */
        $article['user'] = connect('users')->select('userId, fullName, phone, email')->where('userId', $article['addedBy'])->get('array');
		/* добавив информацию о статье раздела */
		if(!empty($article['sectionId']) && !empty($SECTIONS[$article['sectionId']])) $article['section'] = $SECTIONS[$article['sectionId']];

		/* добавив информацию о родительских разделах */
		#if(!empty($article->sectionId)) $article->parents = getSectionParents($article->sectionId);


		return $article;
	}



    function getProperties($articleId): array
    {
        if ($result = connect()->table('type_content_field_data')
            ->usingJoin('type_content_fields', 'fileName')
            ->select('articleId, typeId, type, fieldId, fileName, name, value, orderBy')
            ->where('articleId', $articleId)
            ->where('status', 'V')
            ->orderBy('orderBy')
            ->indexKey('fileName')->valueKey('value')->getAllIndexes('array')
        ) {

            return $result;
        }

        return array();
    }


    /**
     * prepareBanner
     *
     * @param $bannerId
     */
    function prepareBanner($bannerId) {
        $userImage = connect()->table('banner_images')->select('fileId')->where('type', 'general')->where('bannerId', $bannerId)->get('array');
        if ($userImage && $file = connect()->table('files')->select('*')->where('fileId', $userImage['fileId'])->get('array')) {
            return ImageSizes::init()->get($userImage, $file);
        }

        return null;
    }

    /**
     * prepareSlider
     *
     * @param $fileId
     */
    function prepareSlider($fileId) {
		if (!empty($fileId)) {
            $file = connect()->table('files')->select('fileId, directory, path, fileName, size')->where('fileId', $fileId)->get('array');
            return ImageSizes::init()->get(null, $file);
		}

		return null;
	}

/**
 * prepareBlocks
 *
 * @param $blocks
 * @param $sectionInfo
 * @return mixed
 */
function prepareBlocks($blocks, $sectionInfo)
{
    global $SECTIONS;

    foreach ($blocks as $i => $block) {
        $blockIndexes[$block['blockId']] = $i;
        if(!empty($block['addedOn'])) {
            $blocks[$i]['addedOn'] = adjustTime($block['addedOn']);
        }
        if(!empty($block['modifiedOn'])) {
            $blocks[$i]['modifiedOn'] = adjustTime($block['modifiedOn']);
        }

        /* добавив информацию о разделе если sectionInfo = true */
        if ($sectionInfo && !empty($block['sectionId']) && !empty($SECTIONS[$block['sectionId']])) {
            $blocks[$i]['section'] = $SECTIONS[$block['sectionId']];
        }
    }

    /* получать изображения в статье*/
    if (!empty($blockIndexes)) {
        $images = connect()->table('block_images')->in('blockId', array_keys($blockIndexes))->getAll('array');
        foreach ($images as $imageId => $image) {
            $articleIndex = $blockIndexes[$image['blockId']];
            if ($file = connect()->table('files')->select('fileId, directory, path, fileName, size')->where('fileId',  $image['fileId'])->get('array')) {
                if ($image['type'] === 'general') {
                    $blocks[$articleIndex]['image'] = ImageSizes::init()->get($image, $file);
                } elseif ($image['type'] === 'gallery') {
                    $blocks[$articleIndex]['gallery'][$imageId] = ImageSizes::init()->get($image, $file);
                } else {
                    $blocks[$articleIndex]['docs'][$imageId] = ImageSizes::init()->get($image, $file);
                }
            }
        }
    }


//        print_r($blocks);
    return $blocks;
}

/**
 * prepareBlock
 *
 * @param $block
 * @return mixed
 */
function prepareBlock($block) {
    global $SECTIONS;

    if(!empty($block['addedOn'])) {
        $block['addedOn'] = adjustTime($block['addedOn']);
    }
    if(!empty($block['modifiedOn'])) {
        $block['modifiedOn'] = adjustTime($block['modifiedOn']);
    }

    /* получать статьи изображения */
    if(!empty($article['articleId'])) {
        $images = connect()->table('block_images')->where('blockId', $block['blockId'])->orderBy('orderBy', 'ASC')->getAll('array');
        foreach ($images as $imageId => $image) {
            if ($file = connect()->table('files')->select('fileId, directory, path, fileName, size')->where('fileId', $image['fileId'])->get('array')) {
                if ($image['type'] === 'general') {
                    $block['image'] = ImageSizes::init()->get($image, $file);
                } elseif ($image['type'] === 'gallery') {
                    $block['gallery'][$imageId]  = ImageSizes::init()->get($image, $file);
                } else {
                    $block['docs'][$imageId]  = ImageSizes::init()->get($image, $file);
                }
            }
        }
    }
    /* добавив информацию о статье раздела */
    if(!empty($block['sectionId']) && !empty($SECTIONS[$block['sectionId']])) {
        $block['section'] = $SECTIONS[$block['sectionId']];
    }

    return $block;
}


/**
     * prepareLettersBrands
     *
     * @param $brands
     * @return mixed
     */
	function prepareLettersBrands($brands) {
		$brandList = array();
        foreach ($brands as $key => $brand) {
            $letter = mb_substr(mb_strtolower($brand['name']), 0, 1);
            $brandList[$letter][] = $brand;
        }
        ksort($brandList);
    
        return $brandList;
	}

/**
 * prepareBrands
 *
 * @param $brands
 * @param $image_type
 * @return mixed
 */
function prepareBrands($brands, $image_type)
{
    foreach ($brands as $i => $brand) {
        $brandIndexes[$brand['brandId']] = $i;
    }

    /* получать изображения в статье*/
    if (!empty($brandIndexes)) {
        $orderBy = $image_type == 'image' ? '' : 'orderBy ASC';
        if (!empty($image_type) && !is_array($image_type)) {
            connect()->where('type',  $image_type);
        } else {
            connect()->in('type', $image_type);
        }

        $images = connect()->table('brand_images')->orderBy($orderBy)->in('brandId', array_keys($brandIndexes))->getAll('array');
        foreach ($images as $imageId => $image) {
            $brandIndex = $brandIndexes[$image['brandId']];
            if ($file = connect()->table('files')->select('fileId, directory, path, fileName, size')->where('fileId',  $image['fileId'])->get('array')) {
                if ($image['type'] === 'general') {
                    $brands[$brandIndex]['image'] = ImageSizes::init()->get($image, $file);
                } elseif ($image['type'] === 'gallery') {
                    $brands[$brandIndex]['gallery'][$imageId] = ImageSizes::init()->get($image, $file);
                }
            }
        }
    }

    return $brands;
}


    function prepareBrand($brand)
    {
        if(!empty($brand['addedOn'])) $brand['addedOn'] = adjustTime($brand['addedOn']);
        if(!empty($brand['modifiedOn'])) $brand['modifiedOn'] = adjustTime($brand['modifiedOn']);
        if(!empty($brand['publishedOn'])) $brand['publishedOn'] = adjustTime($brand['publishedOn']);

        if(!empty($brand['brandId'])) {
            $images = connect('brand_images')->where('brandId',$brand['brandId'])->orderBy('orderBy', 'ASC')->getAll('array');
            foreach ($images as $imageId => $image) {
                if ($file = connect()->table('files')->select('fileId, directory, path, fileName, size')->where('fileId', $image['fileId'])->get('array')) {
                    if ($image['type'] === 'general') {
                        $brand['image'] = ImageSizes::init()->get($image, $file);
                    } elseif ($image['type'] === 'gallery') {
                        $brand['gallery'][$imageId]  = ImageSizes::init()->get($image, $file);
                    }
                }
            }
        }

        return $brand;
    }

    /**
     * prepareProducts
     *
     * @param $products
     * @param $sectionInfo
     * @param $parentsInfo
     * @param $image
     * @param $image_type
     * @return mixed
     */
    function prepareProducts($products, $sectionInfo, $parentsInfo, $image, $image_type)
    {
        global $SECTIONS;
        $userIDs = array();

        foreach ($products as $i => $product) {
            $productIndexes[$product['productId']] = $i;
            if(!empty($product['addedOn']))    $products[$i]['addedOn']     = adjustTime($product['addedOn']);
            if(!empty($product['modifiedOn'])) $products[$i]['modifiedOn']  = adjustTime($product['modifiedOn']);
            if(!empty($product['publishedOn'])) $products[$i]['publishedOn'] = adjustTime($product['publishedOn']);

            /* добавив информацию о разделе если sectionInfo = true */
            if ($sectionInfo && !empty($product['sectionId']) && !empty($SECTIONS[$product['sectionId']])) {
                $products[$i]['section'] = $SECTIONS[$product['sectionId']];
            }

            /* добавление информации о родительских разделах */
            if ($parentsInfo && !empty($product['sectionId'])) {
                $products[$product['productId']]['parents'] = getSectionParents($product['sectionId']);
            }
            /* сбор идентификаторы пользователей из addedBy и ModifiedBy */
            if(!empty($product['addedBy']))    $userIDs[$product['addedBy']]    = $product['addedBy'];
            if(!empty($product['modifiedBy'])) $userIDs[$product['modifiedBy']] = $product['modifiedBy'];
        }

        if (!empty($productIndexes) && $image) {
            $orderBy = $image_type == 'image' ? '' : 'orderBy ASC';
            if (!empty($image_type) && !is_array($image_type)) {
                connect()->where('type',  $image_type);
            } else {
                connect()->in('type', $image_type);
            }

            $images = connect('product_images')->orderBy($orderBy)->in('productId', array_keys($productIndexes))->getAll('array');
            foreach ($images as $imageId => $image) {
                $productIndex = $productIndexes[$image['productId']];
                if ($file = connect('files')->select('fileId, directory, path, fileName, size')->where('fileId',  $image['fileId'])->get('array')) {
                    if ($image['type'] === 'general') {
                        $products[$productIndex]['image'] = ImageSizes::init()->get($image, $file);
                    } elseif ($image['type'] === 'gallery') {
                        $products[$productIndex]['gallery'][$imageId] = ImageSizes::init()->get($image, $file);
                    } else {
                        $products[$productIndex]['docs'][$imageId] = ImageSizes::init()->get($image, $file);
                    }
                }
            }
        }

        /* получении информации о пользователе, который создал и изменил статью */
        /** @noinspection DuplicatedCode */
        if (!empty($userIDs)) {
            $users = connect()->table('users')->select('userId, fullName, loginName, email, accessLevel')->in('userId', $userIDs)->indexKey('userId')->getAllIndexes();
            foreach($products as $productId => $product) {
                $products[$productId]['addedBy'] = empty($users[$product['addedBy']]) ? unknownUser() : $users[$product['addedBy']];
                $products[$productId]['modifiedBy'] = empty($users[$product['modifiedBy']]) ? unknownUser() : $users[$product['modifiedBy']];
            }
        }

    //        print_r($products);
        return $products;
    }
    /**
     * prepareArticle
     *
     * @param $product
     * @return mixed
     */
    function prepareProduct($product) {
        global $SECTIONS;

        if(!empty($product['addedOn'])) $product['addedOn'] = adjustTime($product['addedOn']);
        if(!empty($product['modifiedOn'])) $product['modifiedOn'] = adjustTime($product['modifiedOn']);
        if(!empty($product['publishedOn'])) $product['publishedOn'] = adjustTime($product['publishedOn']);

        /* получать статьи изображения */
        if(!empty($product['productId'])) {
            $images = connect()->table('product_images')->where('productId', $product['productId'])->orderBy('orderBy', 'ASC')->getAll('array');
            foreach ($images as $imageId => $image) {
                if ($file = connect()->table('files')->select('fileId, directory, path, fileName, size')->where('fileId', $image['fileId'])->get('array')) {
                    if ($image['type'] === 'general') {
                        $product['image'] = ImageSizes::init()->get($image, $file);
                    } elseif ($image['type'] === 'gallery') {
                        $product['gallery'][$imageId]  = ImageSizes::init()->get($image, $file);
                    } else {
                        $product['docs'][$imageId]  = ImageSizes::init()->get($image, $file);
                    }
                }
            }

//            $colors = connect('product_colors AS pc')->usingJoin('colors AS c', 'colorId')->select('c.colorId, c.colorName, c.colorCode, pc.imageId, pc.colorId, pc.fileId')->where('pc.productId', $product['productId'])->where('pc.status', 'V')->orderBy('pc.orderBy ASC')->getAll('array');
//            $product['colors'] = collect($colors)->map(function ($item){
//                if ($file = getFileInfo($item['fileId'])) {
//                    $item['image'] = ImageSizes::init()->get($item, $file);
//                }
//
//                return $item;
//            })->all();

        }
        /* добавив информацию о статье раздела */
        if(!empty($product['sectionId']) && !empty($SECTIONS[$product['sectionId']])) $product['section'] = $SECTIONS[$product['sectionId']];

        /* добавив информацию о родительских разделах */
        #if(!empty($product['sectionId'])) $product['parents'] = getSectionParents($article['sectionId']);
        return $product;
    }

    function getProductOptions($product_id)
    {
        $product_options = connect('product_option')
            ->leftJoin('options', 'optionId', '=', 'option_id')
            ->select('option_id, product_id, product_option_id, name, required')
            ->where('product_id', $product_id)
            ->orderBy('orderBy ASC')
            ->getAll('array');

        return collect($product_options)->map(function ($product_option) {
            $product_option['product_option_value'] = connect('product_option_value')
                ->leftJoin('options', 'optionId', '=', 'option_value_id')
                ->select('product_option_value_id, option_value_id, name, quantity, subtract, price, price_prefix')
                ->where('product_option_id', (int)$product_option['product_option_id'])
                ->orderBy('orderBy ASC')->getAll('array');

            return $product_option;
        })->all();

    }


    function getProductBrand($fileName)
    {
        if (!empty($fileName)) {
            return connect()->table('brands')->select('brandId, name, url')->where('fileName', $fileName)->get('array');
        }

        return null;
    }

    function getAllProductFeatures($productId, $sectionId)
    {
        if (!empty($sectionId)) connect()->like('sectionIds', "%$sectionId%");
        $features = connect('product_features')->select('id, parentId, name')->orderBy('orderBy ASC')->where('status', 'V')->getAll('array');
        $features = buildTreeFeaturesArray($features, 'id', 'property');
        return collect($features)->map(function ($feature) use ($productId) {
            if (isset($feature['property'])) {
                $feature['property'] = collect($feature['property'])->map(function ($item) use ($productId) {
                    $property = connect()->table('product_feature_value')->select('value')->where('featureId', $item['id'])->where('productId', $productId)->get('array');
                    if (!empty($property['value'])) {
                        $item['value'] = $property['value'];
                        return $item;
                    }
                    return $item;
                })->all();
            } else {
                $property = connect()->table('product_feature_value')->select('value')->where('featureId', $feature['id'])->where('productId', $productId)->get('array');
                if (!empty($property['value'])) {
                    $feature['value'] = $property['value'];
                    return $feature;
                }
                return $feature;
            }

            return $feature;

        })->all();
    }

    /** работа с массивом  */
    function buildTreeFeaturesArray($items, $id, $subArray)
    {
        $childs = [];

        foreach ($items as &$item) {
            $childs[$item['parentId'] ?? 0][] = &$item;
        }

        unset($item);

        foreach ($items as &$item) {
            if (isset($childs[$item[$id]])) {
                $item[$subArray] = $childs[$item[$id]];
            }
        }

        return $childs[0] ?? [];
    }


    function getProductFeatureValues($productId)
    {
        return connect()->table('product_feature_value')
            ->join('product_features', 'id', '=', 'featureId')
            ->select('productId, featureId, name, value, icon, orderBy')
            ->where('productId', $productId)
            ->where('status', 'V')
            ->orderBy('orderBy')
            ->indexKey('featureId')->getAllIndexes('array');
    }

    function getVariants(?array $filter)
    {
    //        print_r($filter);
        if (!empty($filter['productId'])) {
            return connect()->table('product_variants')->where('productId', $filter['productId'])->orderBy('orderBy')->indexKey('id')->getAllIndexes('array');
        }

        return null;
    }


    /** РАБОТА С ФАЙЛАМИ / ИЗОБРАЖЕНИЕМ */

    /** получить все из таблицы images модели  */
    function getFiles($table, $primaryKey, $sectionId): ?array
    {
        $files = [];
        if ($images = connect($table)->where($primaryKey, $sectionId)->orderBy('orderBy ASC')->getAll('array')) {
            collect($images)->map(function ($item) use (&$files) {
                if ($file = getFileInfo($item['fileId'])) {
                    if ($item['type'] == 'general') {
                        $files['general'] = ImageSizes::init()->get($item, $file);
                    } elseif ($item['type'] == 'gallery') {
                        $files['gallery'][] = ImageSizes::init()->get($item, $file);
                    }
                    else {
                        $files['docs'][] = ImageSizes::init()->get($item, $file);
                    }
                }

                return $files;
            })->toArray();
        }

        return $files;
    }

    function getFileInfo($fileId): ?array
    {
        return connect('files')->where('fileId', $fileId)->get('array');
    }



    /**
     * отрегулируйте время
     * @param string $date
     * @param bool $isReverse
     * @param string $outputFormat
     * @return false|string
     */
    function adjustTime($date = '', $isReverse = false, $outputFormat = 'Y-m-d H:i:s')
    {

		if (empty($date)) $date = gmdate('Y-m-d H:i:s');
		$adjH = Config::getValue('hour_adjustment') * ($isReverse ? -1 : 1);
		$adjM = Config::getValue('minute_adjustment') * ($isReverse ? -1 : 1);
		$time = strtotime("$adjH hours $adjM minutes", strtotime($date));
		//print_r($adjH);
		return date($outputFormat, $time);
	}

    /**
     * @param $totalItems
     * @param $currentPage
     * @param int $itemsPerPage
     * @param int $firstSet
     * @param int $beforeCurrent
     * @param int $afterCurrent
     * @param int $lastSet
     * @param string $path
     * @param bool $rewrite
     * @return array|bool
     */
    function getPageNums($totalItems, $currentPage, $itemsPerPage = 10, $firstSet = 5, $beforeCurrent = 2, $afterCurrent = 2, $lastSet = 5, $path = '', $rewrite = true) {

		$totalPages = ceil($totalItems / $itemsPerPage);
		if ($currentPage > $totalPages) return false;

		$pageNums['totalPages']     = $totalPages;
		$pageNums['totalItems']     = $totalItems;
		$pageNums['currentPage']    = $currentPage;
		$pageNums['startIteration'] = ($currentPage - 1) * $itemsPerPage + 1;
		$pageNums['endIteration']   = $currentPage * $itemsPerPage;
		if ($pageNums['endIteration'] > $totalItems) $pageNums['endIteration'] = $totalItems;

		/* первые X */
		if ($firstSet > 0) for ($i=1; $i <= ($totalPages > $firstSet ? $firstSet : $totalPages); $i++) $pages[$i] = $i;

		/* X справа, X слева */
		for ($i=($currentPage - $beforeCurrent); $i <= ($currentPage + $afterCurrent); $i++){
			if ($i > 0 && $i <= $totalPages) $pages[$i] = $i;
		}

		/* последние X */
		if($lastSet > 0) for($i=($totalPages - $lastSet + 1); $i <= $totalPages; $i++)  if($i > 0) $pages[$i] = $i;

		/* расставляем точки */
		$i = 0;
		if (!empty($pages) && count($pages) > 1){
  			asort($pages);
			$prevPage = 0;
			foreach ($pages as $page) {
				if (($page - $prevPage) > 1 && $i > 0){
					array_splice($pages, $i, 0, '...');
					$i++;
				}
				$prevPage = $page;
				$i++;
			}
  			$pageNums['pages'] = $pages;
		}

		/* следующая страница */
		if(($currentPage + 1) <= $totalPages){
			if(empty($path)){
				$pageNums['nextPage'] = $currentPage + 1;
			} else {
				$pageNums['nextPage']['num'] = $currentPage + 1;
				if($rewrite){
					$pageNums['nextPage']['url'] = $path."/page".($currentPage + 1).".". Config::getValue('file_extension');
				} else {
					$pageNums['nextPage']['url'] = $path."page=".($currentPage + 1);
				}
			}
		}

		/* предыдущая страница */
		if(($currentPage - 1) >= 1){
			if(empty($path)){
				$pageNums['previousPage'] = $currentPage - 1;
			} else {
				$pageNums['previousPage']['num'] = $currentPage - 1;
				if($rewrite){
					if(($currentPage - 1) == 1){
						$pageNums['previousPage']['url'] = $path."/";
					} else {
						$pageNums['previousPage']['url'] = $path."/page".($currentPage - 1).".". Config::getValue('file_extension');
					}
				} else {
					$pageNums['previousPage']['url'] = $path."page=".($currentPage - 1);
				}
			}
		}

		/* первая страница */
		if($currentPage != 1){
			if(empty($path)){
				$pageNums['firstPage'] = $currentPage - 1;
			} else {
				$pageNums['firstPage']['num'] = $currentPage - 1;
				if($rewrite){
					$pageNums['firstPage']['url'] = $path."/";
				} else {
					$pageNums['firstPage']['url'] = $path."page=1";
				}
			}
		}

		/* последняя страница */
		if($currentPage != $totalPages){
			if(empty($path)){
				$pageNums['lastPage'] = $currentPage - 1;
			} else {
				$pageNums['lastPage']['num'] = $currentPage - 1;
				if($rewrite){
					$pageNums['lastPage']['url'] = $path."/page$totalPages.". Config::getValue('file_extension');
				} else {
					$pageNums['lastPage']['url'] = $path."page=$totalPages";
				}
			}
		}

		if(!empty($pageNums)){
			if(!empty($path) && !empty($pageNums['pages'])) foreach($pageNums['pages'] as $i=>$page) {
				$pageNums['pages'][$i] = array();
				$pageNums['pages'][$i]['num'] = $page;
				if($rewrite){
					if($page == 1){
						$pageNums['pages'][$i]['url'] = $path."/";
					} else {
						$pageNums['pages'][$i]['url'] = $path."/page$page.". Config::getValue('file_extension');
					}
				} else {
					$pageNums['pages'][$i]['url'] = $path."page=$page";
				}
			}
			return $pageNums;
		} else {
			return array();
		}
	}

//    /**
//     * @param string $varName  / название переменной
//     * @param string $defaultVal / значение по умолчанию
//     * @param bool $noEscape    // true - можно получать массив / false массив запрещен
//     * @param bool $checkCookie  / устанавливать значение в куки
//     * @return array|bool|string
//     */
//    function getRequestVar($varName = '', $defaultVal = '', $noEscape = false, $checkCookie = false)
//    {
//		global $smarty;
//
//		if ($varName) {
//			if (isset($_POST[$varName])) {
//				$varValue = $_POST[$varName];
//			} elseif (isset($_GET[$varName])) {
//				$varValue = $_GET[$varName];
//			} elseif (isset($_COOKIE[$varName]) && $checkCookie) {
//				$varValue = $_COOKIE[$varName];
//			}
//		} elseif (!empty($_POST)) {
//			$varValue = $_POST;
//		} elseif (!empty($_GET)) {
//			$varValue = $_GET;
//		} elseif (!empty($_COOKIE) && $checkCookie) {
//			$varValue = $_COOKIE;
//		}
//
//        if (isset($varValue)) {
//            $smarty->assign($varName, $varValue);
//            return $noEscape ? $varValue : arrAddSlashes($varValue);
//        }
//
//        if (!empty($defaultVal)) {
//            $smarty->assign($varName, $defaultVal);
//            return $noEscape ? $defaultVal : arrAddSlashes($defaultVal);
//        }
//
//        return false;
//    }

    function getRequestFiles(): array
    {
        $result = array();

        if (is_array($_FILES)) {
            foreach($_FILES as $name => $fileArray) {
                $row = array();
                foreach ($fileArray as $key => &$data) {
                    findNoArrayElementAndReplace($data, $key);
                    $row = array_merge_recursive($row, $data);
                }
                $result[$name] = $row;
            }
        }

        return $result;
    }

    function findNoArrayElementAndReplace(&$array, $key)
    {
        if (is_array($array)) {
            foreach ($array as &$item) {
                findNoArrayElementAndReplace($item, $key);
            }
        } else {
            $array = array(
                $key => $array
            );
        }
    }

    function multipleFiles(array $_files, $top = TRUE): array
    {
        $files = array();
        foreach($_files as $name=>$file){
            if($top) $sub_name = $file['name'];
            else    $sub_name = $name;

            if(is_array($sub_name)){
                foreach(array_keys($sub_name) as $key){
                    $files[$name][$key] = array(
                        'name'     => $file['name'][$key],
                        'type'     => $file['type'][$key],
                        'tmp_name' => $file['tmp_name'][$key],
                        'error'    => $file['error'][$key],
                        'size'     => $file['size'][$key],
                    );
                    $files[$name] = multipleFiles($files[$name], FALSE);
                }
            }else{
                $files[$name] = $file;
            }
        }
        return $files;
    }


    /**
     * @param $var
     * @return array|string
     */
    function array_preg_quote($var) {
		if (is_array($var)) {
			return array_map('array_preg_quote', $var);
		} else {
			return preg_quote($var, '/');
		}
	}


function xml2array(SimpleXMLElement $xml): array
{
    $array = (array)$xml;

    foreach ( array_slice($array, 0) as $key => $value ) {
        if ( $value instanceof SimpleXMLElement ) {
            $array[$key] = empty($value) ? NULL : xml2array($value);
        }
    }
    return $array;
}

    /**
     * @return float
     */
    function getMicroTime() {
		list($usec, $sec) = explode(' ', microtime());
		return ((float)$usec + (float)$sec);
	}

    function br2nl($string)
    {
        return preg_replace('/\<br(\s*)?\/?\>/i', "\n", $string);
    }

	function rss_get_template($tpl_name, &$tpl_source, &$smarty_obj) {
		$tpl_source = '{$smarty_function_fetch_rss_data nofilter}';
		return true;
	}
	function rss_get_timestamp($tpl_name, &$tpl_timestamp, &$smarty_obj) {
		$tpl_timestamp = 0;
		return true;
	}
	function rss_get_secure($tpl_name, &$smarty_obj) {
	    return true;
	}
	function rss_get_trusted($tpl_name, &$smarty_obj) {
	    // not used for templates
	}

    
    function file_read($file) {
    	$buffer = "";
    	if(is_file($file)) {
    		$buffer .= file_get_contents($file);
    	}
    	return $buffer;
    }

    function isValidEmail($email) {
        if (is_array($email) || is_numeric($email) || is_bool($email) || is_float($email) || is_file($email) || is_dir($email) || is_int($email)) {
            return false;
        }

        $email = strtolower(trim($email));
        if (filter_var($email, FILTER_VALIDATE_EMAIL) !== false) {
            return $email;
        }

        $pattern = '/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iD';
        return (preg_match($pattern, $email) === 1) ? $email : false;
    }

    function formatsize($file_size) {

        if( !$file_size OR $file_size < 1) return '0 b';

        $prefix = array("b", "Kb", "Mb", "Gb", "Tb");
        $exp = floor(log($file_size, 1024)) | 0;

        return round($file_size / (pow(1024, $exp)), 2).' '.$prefix[$exp];
    }

    function mnvStrlen($value, $charset ) {

        if ( strtolower($charset) == "utf-8") {
            if (function_exists( 'mb_strlen' )) {
                return mb_strlen( $value, "utf-8" );

            }

            if(function_exists( 'iconv_strlen' )) {
                return iconv_strlen($value, "utf-8");
            }
        }

        return strlen($value);

    }
