<?php

/**
 * (c) Kitodo. Key to digital objects e.V. <contact@kitodo.org>
 *
 * This file is part of the Kitodo and TYPO3 projects.
 *
 * @license GNU General Public License version 3 or later.
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 */

namespace Kitodo\Dlf\Plugin;

use Kitodo\Dlf\Common\Document;
use Kitodo\Dlf\Common\DocumentList;
use Kitodo\Dlf\Common\Helper;
use Kitodo\Dlf\Common\Indexer;
use Kitodo\Dlf\Common\Solr;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
 * Plugin 'Search' for the 'dlf' extension
 *
 * @author Sebastian Meyer <sebastian.meyer@slub-dresden.de>
 * @author Henrik Lochmann <dev@mentalmotive.com>
 * @author Frank Ulrich Weber <fuw@zeutschel.de>
 * @package TYPO3
 * @subpackage dlf
 * @access public
 */
class Search extends \Kitodo\Dlf\Common\AbstractPlugin
{
    public $scriptRelPath = 'Classes/Plugin/Search.php';

    /**
     * Adds the JS files necessary for search suggestions
     *
     * @access protected
     *
     * @return void
     */
    protected function addAutocompleteJS()
    {
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
            ->getQueryBuilderForTable('tx_dlf_documents');

        // Check if there are any metadata to suggest.
        $result = $queryBuilder
            ->select('tx_dlf_metadata.*')
            ->from('tx_dlf_metadata')
            ->where(
                $queryBuilder->expr()->eq('tx_dlf_metadata.index_autocomplete', 1),
                $queryBuilder->expr()->eq('tx_dlf_metadata.pid', intval($this->conf['pages'])),
                Helper::whereExpression('tx_dlf_metadata')
            )
            ->setMaxResults(1)
            ->execute();

        if ($result->rowCount() == 1) {
            $pageRenderer = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Page\PageRenderer::class);
            $pageRenderer->addJsFooterFile(\TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath($this->extKey)) . 'Resources/Public/Javascript/Search/Suggester.js');
        } else {
            Helper::devLog('No metadata fields configured for search suggestions', DEVLOG_SEVERITY_WARNING);
        }
    }

    /**
     * Adds the current collection's UID to the search form
     *
     * @access protected
     *
     * @return string HTML input fields with current document's UID and parent ID
     */
    protected function addCurrentCollection()
    {
        // Load current collection.
        $list = GeneralUtility::makeInstance(DocumentList::class);
        if (
            !empty($list->metadata['options']['source'])
            && $list->metadata['options']['source'] == 'collection'
        ) {
            // Get collection's UID.
            return '<input type="hidden" name="' . $this->prefixId . '[collection]" value="' . $list->metadata['options']['select'] . '" />';
        } elseif (!empty($list->metadata['options']['params']['filterquery'])) {
            // Get collection's UID from search metadata.
            foreach ($list->metadata['options']['params']['filterquery'] as $facet) {
                $facetKeyVal = explode(':', $facet['query'], 2);
                if (
                    $facetKeyVal[0] == 'collection_faceting'
                    && !strpos($facetKeyVal[1], '" OR "')
                ) {
                    $collectionId = Helper::getUidFromIndexName(trim($facetKeyVal[1], '(")'), 'tx_dlf_collections');
                }
            }
            return '<input type="hidden" name="' . $this->prefixId . '[collection]" value="' . $collectionId . '" />';
        }
        return '';
    }

    /**
     * Adds the current document's UID or parent ID to the search form
     *
     * @access protected
     *
     * @return string HTML input fields with current document's UID
     */
    protected function addCurrentDocument()
    {
        // Load current list object.
        $list = GeneralUtility::makeInstance(DocumentList::class);
        // Load current document.
        if (
            !empty($this->piVars['id'])
            && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->piVars['id'])
        ) {
            $this->loadDocument();
            // Get document's UID
            if ($this->doc->ready) {
                return '<input type="hidden" name="' . $this->prefixId . '[id]" value="' . ($this->doc->uid) . '" />';
            }
        } elseif (!empty($list->metadata['options']['params']['filterquery'])) {
            // Get document's UID from search metadata.
            // The string may be e.g. "{!join from=uid to=partof}uid:{!join from=uid to=partof}uid:2" OR {!join from=uid to=partof}uid:2 OR uid:2"
            // or "collection_faceting:("Some Collection Title")"
            foreach ($list->metadata['options']['params']['filterquery'] as $facet) {
                if (($lastUidPos = strrpos($facet['query'], 'uid:')) !== false) {
                    $facetKeyVal = explode(':', substr($facet['query'], $lastUidPos));
                    if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($facetKeyVal[1])) {
                        $documentId = (int) $facetKeyVal[1];
                    }
                }
            }
            if (!empty($documentId)) {
                return '<input type="hidden" name="' . $this->prefixId . '[id]" value="' . $documentId . '" />';
            }
        }
        return '';
    }

    /**
     * Adds the encrypted Solr core name to the search form
     *
     * @access protected
     *
     * @return string HTML input fields with encrypted core name and hash
     */
    protected function addEncryptedCoreName()
    {
        // Get core name.
        $name = Helper::getIndexNameFromUid($this->conf['solrcore'], 'tx_dlf_solrcores');
        // Encrypt core name.
        if (!empty($name)) {
            $name = Helper::encrypt($name);
        }
        // Add encrypted fields to search form.
        if ($name !== false) {
            return '<input type="hidden" name="' . $this->prefixId . '[encrypted]" value="' . $name . '" />';
        } else {
            return '';
        }
    }

    /**
     * Returns the extended search form and adds the JS files necessary for extended search.
     *
     * @access protected
     *
     * @return string The extended search form or an empty string
     */
    protected function addExtendedSearch()
    {
        $extendedSearch = '';
        // Quit without doing anything if no fields for extended search are selected.
        if (
            empty($this->conf['extendedSlotCount'])
            || empty($this->conf['extendedFields'])
        ) {
            return $extendedSearch;
        }
        // Get operator options.
        $operatorOptions = '';
        foreach (['AND', 'OR', 'NOT'] as $operator) {
            $operatorOptions .= '<option class="tx-dlf-search-operator-option tx-dlf-search-operator-' . $operator . '" value="' . $operator . '">' . htmlspecialchars($this->pi_getLL($operator, '')) . '</option>';
        }
        // Get field selector options.
        $fieldSelectorOptions = '';
        $searchFields = GeneralUtility::trimExplode(',', $this->conf['extendedFields'], true);
        foreach ($searchFields as $searchField) {
            $fieldSelectorOptions .= '<option class="tx-dlf-search-field-option tx-dlf-search-field-' . $searchField . '" value="' . $searchField . '">' . Helper::translate($searchField, 'tx_dlf_metadata', $this->conf['pages']) . '</option>';
        }
        for ($i = 0; $i < $this->conf['extendedSlotCount']; $i++) {
            $markerArray = [
                '###EXT_SEARCH_OPERATOR###' => '<select class="tx-dlf-search-operator tx-dlf-search-operator-' . $i . '" name="' . $this->prefixId . '[extOperator][' . $i . ']">' . $operatorOptions . '</select>',
                '###EXT_SEARCH_FIELDSELECTOR###' => '<select class="tx-dlf-search-field tx-dlf-search-field-' . $i . '" name="' . $this->prefixId . '[extField][' . $i . ']">' . $fieldSelectorOptions . '</select>',
                '###EXT_SEARCH_FIELDQUERY###' => '<input class="tx-dlf-search-query tx-dlf-search-query-' . $i . '" type="text" name="' . $this->prefixId . '[extQuery][' . $i . ']" />'
            ];
            $extendedSearch .= $this->templateService->substituteMarkerArray($this->templateService->getSubpart($this->template, '###EXT_SEARCH_ENTRY###'), $markerArray);
        }
        return $extendedSearch;
    }

    /**
     * Adds the facets menu to the search form
     *
     * @access protected
     *
     * @return string HTML output of facets menu
     */
    protected function addFacetsMenu()
    {
        // Check for typoscript configuration to prevent fatal error.
        if (empty($this->conf['facetsConf.'])) {
            Helper::devLog('Incomplete plugin configuration', DEVLOG_SEVERITY_WARNING);
            return '';
        }
        // Quit without doing anything if no facets are selected.
        if (empty($this->conf['facets']) && empty($this->conf['facetCollections'])) {
            return '';
        }
        // Get facets from plugin configuration.
        $facets = [];
        foreach (GeneralUtility::trimExplode(',', $this->conf['facets'], true) as $facet) {
            $facets[$facet . '_faceting'] = Helper::translate($facet, 'tx_dlf_metadata', $this->conf['pages']);
        }
        // Render facets menu.
        $TSconfig = [];
        $TSconfig['special'] = 'userfunction';
        $TSconfig['special.']['userFunc'] = \Kitodo\Dlf\Plugin\Search::class . '->makeFacetsMenuArray';
        $TSconfig['special.']['facets'] = $facets;
        $TSconfig['special.']['limit'] = max(intval($this->conf['limitFacets']), 1);
        $TSconfig = Helper::mergeRecursiveWithOverrule($this->conf['facetsConf.'], $TSconfig);
        return $this->cObj->cObjGetSingle('HMENU', $TSconfig);
    }

    /**
     * Adds the fulltext switch to the search form
     *
     * @access protected
     *
     * @param int $isFulltextSearch: Is fulltext search activated?
     *
     * @return string HTML output of fulltext switch
     */
    protected function addFulltextSwitch($isFulltextSearch = 0)
    {
        $output = '';
        // Check for plugin configuration.
        if (!empty($this->conf['fulltext'])) {
            $output .= ' <input class="tx-dlf-search-fulltext" id="tx-dlf-search-fulltext-no" type="radio" name="' . $this->prefixId . '[fulltext]" value="0" ' . ($isFulltextSearch == 0 ? 'checked="checked"' : '') . ' />';
            $output .= ' <label for="tx-dlf-search-fulltext-no">' . htmlspecialchars($this->pi_getLL('label.inMetadata', '')) . '</label>';
            $output .= ' <input class="tx-dlf-search-fulltext" id="tx-dlf-search-fulltext-yes" type="radio" name="' . $this->prefixId . '[fulltext]" value="1" ' . ($isFulltextSearch == 1 ? 'checked="checked"' : '') . '/>';
            $output .= ' <label for="tx-dlf-search-fulltext-yes">' . htmlspecialchars($this->pi_getLL('label.inFulltext', '')) . '</label>';
        }
        return $output;
    }

    /**
     * Adds the logical page field to the search form
     *
     * @access protected
     *
     * @return string HTML output of logical page field
     */
    protected function addLogicalPage()
    {
        $output = '';
        // Check for plugin configuration.
        if (!empty($this->conf['showLogicalPageField'])) {
            $output .= ' <label for="tx-dlf-search-logical-page">' . htmlspecialchars($this->pi_getLL('label.logicalPage', '')) . ': </label>';
            $output .= ' <input class="tx-dlf-search-logical-page" id="tx-dlf-search-logical-page" type="text" name="' . $this->prefixId . '[logicalPage]" />';
        }
        return $output;
    }

    /**
     * Creates an array for a HMENU entry of a facet value.
     *
     * @access protected
     *
     * @param string $field: The facet's index_name
     * @param string $value: The facet's value
     * @param int $count: Number of hits for this facet
     * @param array $search: The parameters of the current search query
     * @param string &$state: The state of the parent item
     *
     * @return array The array for the facet's menu entry
     */
    protected function getFacetsMenuEntry($field, $value, $count, $search, &$state)
    {
        $entryArray = [];
        // Translate value.
        if ($field == 'owner_faceting') {
            // Translate name of holding library.
            $entryArray['title'] = htmlspecialchars(Helper::translate($value, 'tx_dlf_libraries', $this->conf['pages']));
        } elseif ($field == 'type_faceting') {
            // Translate document type.
            $entryArray['title'] = htmlspecialchars(Helper::translate($value, 'tx_dlf_structures', $this->conf['pages']));
        } elseif ($field == 'collection_faceting') {
            // Translate name of collection.
            $entryArray['title'] = htmlspecialchars(Helper::translate($value, 'tx_dlf_collections', $this->conf['pages']));
        } elseif ($field == 'language_faceting') {
            // Translate ISO 639 language code.
            $entryArray['title'] = htmlspecialchars(Helper::getLanguageName($value));
        } else {
            $entryArray['title'] = htmlspecialchars($value);
        }
        $entryArray['count'] = $count;
        $entryArray['doNotLinkIt'] = 0;
        // Check if facet is already selected.
        $queryColumn = array_column($search['params']['filterquery'], 'query');
        $index = array_search($field . ':("' . Solr::escapeQuery($value) . '")', $queryColumn);
        if ($index !== false) {
            // Facet is selected, thus remove it from filter.
            unset($queryColumn[$index]);
            $queryColumn = array_values($queryColumn);
            $entryArray['ITEM_STATE'] = 'CUR';
            $state = 'ACTIFSUB';
            //Reset facets
            if ($this->conf['resetFacets']) {
                //remove ($count) for selected facet in template
                $entryArray['count'] = false;
                //build link to delete selected facet
                $entryArray['_OVERRIDE_HREF'] = $this->pi_linkTP_keepPIvars_url(['query' => $search['query'], 'fq' => $queryColumn]);
                $entryArray['title'] = sprintf($this->pi_getLL('resetFacet', ''), $entryArray['title']);
            }
        } else {
            // Facet is not selected, thus add it to filter.
            $queryColumn[] = $field . ':("' . Solr::escapeQuery($value) . '")';
            $entryArray['ITEM_STATE'] = 'NO';
        }
        $entryArray['_OVERRIDE_HREF'] = $this->pi_linkTP_keepPIvars_url(['query' => $search['query'], 'fq' => $queryColumn]);
        return $entryArray;
    }

    /**
     * The main method of the PlugIn
     *
     * @access public
     *
     * @param string $content: The PlugIn content
     * @param array $conf: The PlugIn configuration
     *
     * @return string The content that is displayed on the website
     */
    public function main($content, $conf)
    {
        $this->init($conf);
        // Disable caching for this plugin.
        $this->setCache(false);
        // Quit without doing anything if required variables are not set.
        if (empty($this->conf['solrcore'])) {
            Helper::devLog('Incomplete plugin configuration', DEVLOG_SEVERITY_WARNING);
            return $content;
        }
        if (
            !isset($this->piVars['query'])
            && empty($this->piVars['extQuery'])
        ) {
            // Extract query and filter from last search.
            $list = GeneralUtility::makeInstance(DocumentList::class);
            if (!empty($list->metadata['searchString'])) {
                if ($list->metadata['options']['source'] == 'search') {
                    $search['query'] = $list->metadata['searchString'];
                }
                $search['params'] = $list->metadata['options']['params'];
            }
            // Add javascript for search suggestions if enabled and jQuery autocompletion is available.
            if (!empty($this->conf['suggest'])) {
                $this->addAutocompleteJS();
            }
            // Load template file.
            $this->getTemplate();
            // Configure @action URL for form.
            $linkConf = [
                'parameter' => $GLOBALS['TSFE']->id,
                'forceAbsoluteUrl' => !empty($this->conf['forceAbsoluteUrl']) ? 1 : 0,
                'forceAbsoluteUrl.' => ['scheme' => !empty($this->conf['forceAbsoluteUrl']) && !empty($this->conf['forceAbsoluteUrlHttps']) ? 'https' : 'http']
            ];
            // Fill markers.
            $markerArray = [
                '###ACTION_URL###' => $this->cObj->typoLink_URL($linkConf),
                '###LABEL_QUERY###' => (!empty($search['query']) ? htmlspecialchars($search['query']) : htmlspecialchars($this->pi_getLL('label.query'))),
                '###LABEL_SUBMIT###' => htmlspecialchars($this->pi_getLL('label.submit')),
                '###FIELD_QUERY###' => $this->prefixId . '[query]',
                '###QUERY###' => (!empty($search['query']) ? htmlspecialchars($search['query']) : ''),
                '###FULLTEXTSWITCH###' => $this->addFulltextSwitch($list->metadata['fulltextSearch']),
                '###FIELD_DOC###' => ($this->conf['searchIn'] == 'document' || $this->conf['searchIn'] == 'all' ? $this->addCurrentDocument() : ''),
                '###FIELD_COLL###' => ($this->conf['searchIn'] == 'collection' || $this->conf['searchIn'] == 'all' ? $this->addCurrentCollection() : ''),
                '###ADDITIONAL_INPUTS###' => $this->addEncryptedCoreName(),
                '###FACETS_MENU###' => $this->addFacetsMenu(),
                '###LOGICAL_PAGE###' => $this->addLogicalPage()
            ];
            // Get additional fields for extended search.
            $extendedSearch = $this->addExtendedSearch();
            // Display search form.
            $content .= $this->templateService->substituteSubpart($this->templateService->substituteMarkerArray($this->template, $markerArray), '###EXT_SEARCH_ENTRY###', $extendedSearch);
            return $this->pi_wrapInBaseClass($content);
        } else {
            // Build label for result list.
            $label = htmlspecialchars($this->pi_getLL('search', ''));
            if (!empty($this->piVars['query'])) {
                $label .= htmlspecialchars(sprintf($this->pi_getLL('for', ''), trim($this->piVars['query'])));
            }
            // Prepare query parameters.
            $params = [];
            $matches = [];
            // Set search query.
            if (
                (!empty($this->conf['fulltext']) && !empty($this->piVars['fulltext']))
                || preg_match('/fulltext:\((.*)\)/', trim($this->piVars['query']), $matches)
            ) {
                // If the query already is a fulltext query e.g using the facets
                $this->piVars['query'] = empty($matches[1]) ? $this->piVars['query'] : $matches[1];
                // Search in fulltext field if applicable. Query must not be empty!
                if (!empty($this->piVars['query'])) {
                    $query = 'fulltext:(' . Solr::escapeQuery(trim($this->piVars['query'])) . ')';
                }
            } else {
                // Retain given search field if valid.
                $query = Solr::escapeQueryKeepField(trim($this->piVars['query']), $this->conf['pages']);
            }
            // Add extended search query.
            if (
                !empty($this->piVars['extQuery'])
                && is_array($this->piVars['extQuery'])
            ) {
                $allowedOperators = ['AND', 'OR', 'NOT'];
                $allowedFields = GeneralUtility::trimExplode(',', $this->conf['extendedFields'], true);
                $numberOfExtQueries = count($this->piVars['extQuery']);
                for ($i = 0; $i < $numberOfExtQueries; $i++) {
                    if (!empty($this->piVars['extQuery'][$i])) {
                        if (
                            in_array($this->piVars['extOperator'][$i], $allowedOperators)
                            && in_array($this->piVars['extField'][$i], $allowedFields)
                        ) {
                            if (!empty($query)) {
                                $query .= ' ' . $this->piVars['extOperator'][$i] . ' ';
                            }
                            $query .= Indexer::getIndexFieldName($this->piVars['extField'][$i], $this->conf['pages']) . ':(' . Solr::escapeQuery($this->piVars['extQuery'][$i]) . ')';
                        }
                    }
                }
            }
            // Add filter query for faceting.
            if (!empty($this->piVars['fq'])) {
                foreach ($this->piVars['fq'] as $filterQuery) {
                    $params['filterquery'][]['query'] = $filterQuery;
                }
            }
            // Add filter query for in-document searching.
            if (
                $this->conf['searchIn'] == 'document'
                || $this->conf['searchIn'] == 'all'
            ) {
                if (
                    !empty($this->piVars['id'])
                    && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->piVars['id'])
                ) {
                    // Search in document and all subordinates (valid for up to three levels of hierarchy).
                    $params['filterquery'][]['query'] = '_query_:"{!join from=uid to=partof}uid:{!join from=uid to=partof}uid:' . $this->piVars['id'] . '"' .
                        ' OR {!join from=uid to=partof}uid:' . $this->piVars['id'] .
                        ' OR uid:' . $this->piVars['id'];
                    $label .= htmlspecialchars(sprintf($this->pi_getLL('in', ''), Document::getTitle($this->piVars['id'])));
                }
            }
            // Add filter query for in-collection searching.
            if (
                $this->conf['searchIn'] == 'collection'
                || $this->conf['searchIn'] == 'all'
            ) {
                if (
                    !empty($this->piVars['collection'])
                    && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->piVars['collection'])
                ) {
                    $index_name = Helper::getIndexNameFromUid($this->piVars['collection'], 'tx_dlf_collections', $this->conf['pages']);
                    $params['filterquery'][]['query'] = 'collection_faceting:("' . Solr::escapeQuery($index_name) . '")';
                    $label .= sprintf($this->pi_getLL('in', '', true), Helper::translate($index_name, 'tx_dlf_collections', $this->conf['pages']));
                }
            }
            // Add filter query for collection restrictions.
            if ($this->conf['collections']) {
                $collIds = explode(',', $this->conf['collections']);
                $collIndexNames = [];
                foreach ($collIds as $collId) {
                    $collIndexNames[] = Solr::escapeQuery(Helper::getIndexNameFromUid(intval($collId), 'tx_dlf_collections', $this->conf['pages']));
                }
                // Last value is fake and used for distinction in $this->addCurrentCollection()
                $params['filterquery'][]['query'] = 'collection_faceting:("' . implode('" OR "', $collIndexNames) . '" OR "FakeValueForDistinction")';
            }
            // Set some query parameters.
            $params['query'] = !empty($query) ? $query : '*';
            $params['start'] = 0;
            $params['rows'] = 0;
            $params['sort'] = ['score' => 'desc'];
            // Instantiate search object.
            $solr = Solr::getInstance($this->conf['solrcore']);
            if (!$solr->ready) {
                Helper::devLog('Apache Solr not available', DEVLOG_SEVERITY_ERROR);
                return $content;
            }
            // Set search parameters.
            $solr->cPid = $this->conf['pages'];
            $solr->params = $params;
            // Perform search.
            $list = $solr->search();
            $list->metadata = [
                'label' => $label,
                'thumbnail' => '',
                'searchString' => $this->piVars['query'],
                'fulltextSearch' => (!empty($this->piVars['fulltext']) ? '1' : '0'),
                'options' => $list->metadata['options']
            ];
            $list->save();
            // Clean output buffer.
            ob_end_clean();
            $additionalParams = [];
            if (!empty($this->piVars['logicalPage'])) {
                $additionalParams['logicalPage'] = $this->piVars['logicalPage'];
            }
            // Jump directly to the page view, if there is only one result and it is configured
            if ($list->metadata['options']['numberOfHits'] == 1 && !empty($this->conf['showSingleResult'])) {
                $linkConf['parameter'] = $this->conf['targetPidPageView'];
                $additionalParams['id'] = $list->current()['uid'];
                $additionalParams['highlight_word'] = preg_replace('/\s\s+/', ';', $list->metadata['searchString']);
                $additionalParams['page'] = count($list[0]['subparts']) == 1 ? $list[0]['subparts'][0]['page'] : 1;
            } else {
                // Keep some plugin variables.
                $linkConf['parameter'] = $this->conf['targetPid'];
                if (!empty($this->piVars['order'])) {
                    $additionalParams['order'] = $this->piVars['order'];
                    $additionalParams['asc'] = !empty($this->piVars['asc']) ? '1' : '0';
                }
            }
            $linkConf['forceAbsoluteUrl'] = !empty($this->conf['forceAbsoluteUrl']) ? 1 : 0;
            $linkConf['forceAbsoluteUrl.']['scheme'] = !empty($this->conf['forceAbsoluteUrl']) && !empty($this->conf['forceAbsoluteUrlHttps']) ? 'https' : 'http';
            $linkConf['additionalParams'] = GeneralUtility::implodeArrayForUrl($this->prefixId, $additionalParams, '', true, false);
            // Send headers.
            header('Location: ' . GeneralUtility::locationHeaderUrl($this->cObj->typoLink_URL($linkConf)));
            exit;
        }
    }

    /**
     * This builds a menu array for HMENU
     *
     * @access public
     *
     * @param string $content: The PlugIn content
     * @param array $conf: The PlugIn configuration
     *
     * @return array HMENU array
     */
    public function makeFacetsMenuArray($content, $conf)
    {
        $this->init($conf);
        $menuArray = [];
        // Set default value for facet search.
        $search = [
            'query' => '*',
            'params' => [
                'component' => [
                    'facetset' => [
                        'facet' => []
                    ]
                ]
            ]
        ];
        // Extract query and filter from last search.
        $list = GeneralUtility::makeInstance(DocumentList::class);
        if (!empty($list->metadata['options']['source'])) {
            if ($list->metadata['options']['source'] == 'search') {
                $search['query'] = $list->metadata['options']['select'];
            }
            $search['params'] = $list->metadata['options']['params'];
        }
        // Get applicable facets.
        $solr = Solr::getInstance($this->conf['solrcore']);
        if (!$solr->ready) {
            Helper::devLog('Apache Solr not available', DEVLOG_SEVERITY_ERROR);
            return [];
        }
        // Set needed parameters for facet search.
        if (empty($search['params']['filterquery'])) {
            $search['params']['filterquery'] = [];
        }
        foreach (array_keys($this->conf['facets']) as $field) {
            $search['params']['component']['facetset']['facet'][] = [
                'type' => 'field',
                'key' => $field,
                'field' => $field,
                'limit' => $this->conf['limitFacets'],
                'sort' => isset($this->conf['sortingFacets']) ? $this->conf['sortingFacets'] : 'count'
            ];
        }
        // Set additional query parameters.
        $search['params']['start'] = 0;
        $search['params']['rows'] = 0;
        // Set query.
        $search['params']['query'] = $search['query'];
        // Perform search.
        $selectQuery = $solr->service->createSelect($search['params']);
        $results = $solr->service->select($selectQuery);
        $facet = $results->getFacetSet();

        $facetCollectionArray = [];

        // replace everything expect numbers and comma
        $facetCollections = preg_replace('/[^0-9,]/', '', $this->conf['facetCollections']);

        if (!empty($facetCollections)) {
            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
                ->getQueryBuilderForTable('tx_dlf_collections');

            $result = $queryBuilder
                ->select('tx_dlf_collections.index_name AS index_name')
                ->from('tx_dlf_collections')
                ->where(
                    $queryBuilder->expr()->in(
                        'tx_dlf_collections.uid',
                        $queryBuilder->createNamedParameter(GeneralUtility::intExplode(',', $facetCollections), Connection::PARAM_INT_ARRAY)
                    )
                )
                ->execute();

            while ($collection = $result->fetch()) {
                $facetCollectionArray[] = $collection['index_name'];
            }
        }

        // Process results.
        foreach ($facet as $field => $values) {
            $entryArray = [];
            $entryArray['title'] = htmlspecialchars($this->conf['facets'][$field]);
            $entryArray['count'] = 0;
            $entryArray['_OVERRIDE_HREF'] = '';
            $entryArray['doNotLinkIt'] = 1;
            $entryArray['ITEM_STATE'] = 'NO';
            // Count number of facet values.
            $i = 0;
            foreach ($values as $value => $count) {
                if ($count > 0) {
                    // check if facet collection configuration exists
                    if (!empty($this->conf['facetCollections'])) {
                        if ($field == "collection_faceting" && !in_array($value, $facetCollectionArray)) {
                            continue;
                        }
                    }
                    $entryArray['count']++;
                    if ($entryArray['ITEM_STATE'] == 'NO') {
                        $entryArray['ITEM_STATE'] = 'IFSUB';
                    }
                    $entryArray['_SUB_MENU'][] = $this->getFacetsMenuEntry($field, $value, $count, $search, $entryArray['ITEM_STATE']);
                    if (++$i == $this->conf['limit']) {
                        break;
                    }
                } else {
                    break;
                }
            }
            $menuArray[] = $entryArray;
        }
        return $menuArray;
    }
}
