<?php
/**
 * This Software is the property of Data Development and is protected
 * by copyright law - it is NOT Freeware.
 *
 * Any unauthorized use of this software without a valid license
 * is a violation of the license agreement and will be prosecuted by
 * civil and criminal law.
 *
 * http://www.shopmodule.com
 *
 * @copyright © Dł Data Development, Thomas Dartsch
 * @author    Dł Data Development - Daniel Seifert <ds@shopmodule.com>
 * @link      http://www.oxidmodule.com
 */

class d3_xlist_extsearch
{
    private $_sModId = 'd3_extsearch'; // in ModCfg used module ident
    protected $_oaListController;
    public $oD3SearchHandler = null;
    public $oD3OwnSearchHandler = null;
    /** @var oxCategoryList */
    public $oSearchCategoriesList;
    /** @var oxVendorList */
    public $oSearchVendorList;
    /** @var oxManufacturerList */
    public $oSearchManufacturerList;
    public $aPriceSteps;
    public $aPriceSelector;
    public $sPriceSelector;
    protected $_sSearchCategory;
    protected $_sSearchVendor;
    protected $_sSearchManufacturer;
    protected $_sD3AdditionalParams = null;
    protected $_aSelectedAttributes;
    protected $_aSelectedCategoryMultiFilter;
    protected $_aSelectedVendorMultiFilter;
    protected $_aSelectedManufacturerMultiFilter;
    protected $_aD3AdditionalSearchParams = array('filterparam', 'searchcnid', 'searchmanufacturer', 'searchvendor');
    private $_blUseAlistFilter;
    public $aSearchAttribList = array();

    public function __construct(aList $oListController)
    {
        $this->_oaListController = $oListController;
    }

    public function render()
    {
        if ($this->_d3UseAlistFilters()) {
            $this->_d3AddAllTplParams();
        }
    }

    /**
     * @param oxCategory|oxmanufacturer $oCategory
     */
    public function addAListFilters($oCategory)
    {
        if (false == $this->_d3UseAlistFilters()) {
            return;
        }
        
        if (false == method_exists($oCategory, 'isPriceCategory')  // in case of manufacturerlist class
            || false == $oCategory->isPriceCategory()
        ) {
            $sControllerClassName = strtolower($this->getaListController()->getClassName());

            if ($sControllerClassName == 'alist') {
                $_POST["searchcnid"] = oxRegistry::getConfig()->getRequestParameter('cnid');
            } elseif ($sControllerClassName == 'manufacturerlist') {
                $_POST["searchmanufacturer"] = oxRegistry::getConfig()->getRequestParameter('mnid');
            } elseif ($sControllerClassName == 'vendorlist') {
                $sActCat = oxRegistry::getConfig()->getRequestParameter('cnid');
                /** @var oxStrMb $oStrMb */
                $oStrMb = getStr();
                $_POST["searchvendor"] = ($oStrMb->preg_match('/^v_.?/i', $sActCat)) ? str_replace(
                    'v_',
                    '',
                    $sActCat
                ) : null;
            } elseif ($sControllerClassName == 'tag') {
                // ToDo: add tag parameter for article list filter in search and articlelists
            }

            if ($sControllerClassName != 'alist') {
                $this->_d3GetCategoryList();
            }
            if ($sControllerClassName != 'vendorlist') {
                $this->_d3GetVendorList();
            }
            if ($sControllerClassName != 'manufacturerlist') {
                $this->_d3GetManufacturerList();
            }
            /*
                        if (strtolower($this->getClassName()) != 'alist') {
            // ToDo: add category selection
                            $this->_getCategoryList();
                        }
            */

            $this->_d3GetAttributeList();
            $this->d3GeneratePriceSteps();

            $this->getaListController()->addTplParam('blD3ShowFilters', $this->d3GetShowFilters());
            $this->getaListController()->addTplParam('blD3HasSelectedFilters', $this->d3HasSelectedFilters());
        } elseif (method_exists($oCategory, 'isPriceCategory')  // in case of manufacturerlist class
            && $oCategory->isPriceCategory()
        ) {
            $aPriceSelector = array(
                'min' => $oCategory->getFieldData('oxpricefrom'),
                'max' => $oCategory->getFieldData('oxpriceto')
            );
            $aPSOV = array(
                'min' => $oCategory->getFieldData('oxpricefrom') * 100,
                'max' => $oCategory->getFieldData('oxpriceto') * 100
            );
            $_POST["d3psov"] = $aPSOV;
            $_POST["priceselector"] = $aPriceSelector;
            $this->_d3GetVendorList();
            $this->_d3GetManufacturerList();
            $this->_d3GetAttributeList();

            $this->getaListController()->addTplParam('blD3ShowFilters', $this->d3GetShowFilters());
            $this->getaListController()->addTplParam('blD3HasSelectedFilters', $this->d3HasSelectedFilters());
        }
    }

    protected function _d3AddAllTplParams()
    {
        // set TPL parameter, if category and vendor selectlists on frontends left side shouldn't changed
        if (false == strstr($this->getaListController()->getViewDataElement('additionalparams'), '&amp;isextsearch=') //
            && ($sExtSearchFlag = oxRegistry::getConfig()->getRequestParameter('isextsearch')) //
        ) {
            $this->getaListController()->addTplParam(
                'additionalparams',
                $this->getaListController()->getViewDataElement('additionalparams') . '&isextsearch='.$sExtSearchFlag
            );
            $this->getaListController()->addTplParam('isextsearch', $sExtSearchFlag);
        }

        // set price selection params
        $this->d3GetPriceSelectors();

        if (($sSearchCategory = $this->getaListController()->getSearchCategory())) {
            $this->getaListController()->addTplParam(
                'additionalparams',
                $this->getaListController()->getViewDataElement('additionalparams') . "&amp;searchcnid=" . urlencode(
                    $sSearchCategory
                )
            );
        }

        if (($sSearchVendor = $this->getaListController()->getSearchVendor())) {
            $this->getaListController()->addTplParam(
                'additionalparams',
                $this->getaListController()->getViewDataElement('additionalparams') . "&amp;searchvendor=" . urlencode(
                    $sSearchVendor
                )
            );
        }

        if (($sSearchManufacturer = $this->getaListController()->getSearchManufacturer())) {
            $this->getaListController()->addTplParam(
                'additionalparams',
                $this->getaListController()->getViewDataElement('additionalparams') . "&amp;searchmanufacturer=" . urlencode(
                    $sSearchManufacturer
                )
            );
        }

        // add price selectors parameter to url variables
        $this->d3GetAttributeFilters();

        // send browser plugin status to smarty
        $this->getaListController()->addTplParam('blSearchPluginLink', $this->d3GetSet()->getValue('blExtSearch_enablePluginLink'));
    }

    /**
     * @return bool
     */
    public function d3HasSelectedFilters()
    {
        if ($this->_d3UseAlistFilters()
            && (
                $this->getaListController()->getSearchManufacturer()
                || $this->getaListController()->getSearchVendor()
                || $this->_d3HasPriceSteps()
                || $this->_d3HasAttributeValues()
            )
        ) {
            return true;
        }

        return false;
    }

    /**
     * @return bool
     */
    protected function _d3HasPriceSteps()
    {
        $aPriceSteps = $this->d3getPriceSteps();
        if ($this->d3HasjQuerySlider()) {
            $blPriceStepSet = (isset($aPriceSteps['min']) && $aPriceSteps['min'] != 0)
                || (isset($aPriceSteps['max']) && $aPriceSteps['max'] != 0);
        } else {
            $blPriceStepSet = (bool) count($aPriceSteps);
        }

        return $blPriceStepSet;
    }

    /**
     * @return bool
     */
    protected function _d3HasAttributeValues()
    {
        $aSessionAttribs = oxRegistry::getSession()->getVariable('d3searchattrib');
        $aSessionMultiAttribs = oxRegistry::getSession()->getVariable('d3searchattribmulti');
        /** @var d3_alist_extsearch $oActView */
        $oActView = oxRegistry::getConfig()->getActiveView();

        $aAttribMultiSelector = oxRegistry::getConfig()->getRequestParameter('d3searchattribmultiselector');
        if (false == is_array($aAttribMultiSelector)) {
            $aAttribMultiSelector = array();
        }

        $sFilterPageId = method_exists($oActView, 'd3getFilterPageId') ?
            $oActView->d3getFilterPageId() :
            $this->d3getFilterPageId();

        $aSearchAttrib = oxRegistry::getConfig()->getRequestParameter('d3searchattrib');
        $aSessionSearchAttrib = $aSessionAttribs[$sFilterPageId];
        if (isset($aSearchAttrib) && is_array($aSearchAttrib)) {
            foreach ($aSearchAttrib as $sId => $sValue) {
                if ((count($aAttribMultiSelector)
                        && isset($aAttribMultiSelector[$sId])
                        && $aAttribMultiSelector[$sId] == 'on')
                    || ($sValue == '' || $sValue == $this->d3GetSearchHandler()->d3GetDeselectValue())
                ) {
                    unset($aSearchAttrib[$sId]);
                    unset($aSessionSearchAttrib[$sId]);
                }
            }
        }

        $aMultiSearchAttrib = oxRegistry::getConfig()->getRequestParameter('d3searchattribmulti');
        $aSessionMultiSearchAttrib = $aSessionMultiAttribs[$sFilterPageId];
        if (isset($aMultiSearchAttrib) && is_array($aMultiSearchAttrib)) {
            foreach ($aMultiSearchAttrib as $sId => $aValues) {
                if (false == count($aAttribMultiSelector)
                    || false == isset($aAttribMultiSelector[$sId])
                    || $aAttribMultiSelector[$sId] != 'on'
                    || false == is_array($aValues)
                    || false == count($aValues)
                ) {
                    unset($aMultiSearchAttrib[$sId]);
                    unset($aSessionMultiSearchAttrib[$sId]);
                } else {
                    foreach ($aValues as $sValueId => $sValue) {
                        if ($sValue == '' || $sValue == $this->d3GetSearchHandler()->d3GetDeselectValue()) {
                            unset($aMultiSearchAttrib[$sId][$sValueId]);
                            unset($aSessionMultiSearchAttrib[$sId][$sValueId]);
                        }
                    }
                }

                if (false == count($aMultiSearchAttrib[$sId])) {
                    unset($aMultiSearchAttrib[$sId]);
                    unset($aSessionMultiSearchAttrib[$sId]);
                }
            }
        }

        return count($aSearchAttrib)
        || count($aSessionSearchAttrib)
        || count($aMultiSearchAttrib)
        || count($aSessionMultiSearchAttrib);
    }

    /**
     * @return bool
     */
    public function d3GetShowFilters()
    {
        if ($this->d3GetSet()->isActive()
            && $this->_d3UseAlistFilters()
            && (
                in_array(
                    strtolower($this->getaListController()->getClassName()),
                    array('alist', 'manufacturerlist', 'vendorlist')
                )
                // || strtolower($this->getClassName()) == 'tag'
            )
            && (
                count($this->d3getVendorList())
                || $this->getaListController()->getSearchVendor()
                || count($this->d3getManufacturerList())
                || $this->getaListController()->getSearchManufacturer()
                || $this->d3GetPriceSteps()
                || $this->d3GetAttributeList()
            )
        ) {
            return true;
        }

        return false;
    }

    protected function _d3GetCategoryList()
    {
        if (false == $this->d3GetSet()->isActive()
            || false == $this->_d3UseAlistFilters()
            || false == $this->d3GetSet()->getValue('blExtSearch_showCatList')
        ) {
            return;
        }

        // if not all vendors were shown, set state in session (shop wide access required)
        if (oxRegistry::getConfig()->getRequestParameter('showall_categories') == '1') {
            oxRegistry::getSession()->setVariable('showall_categories', '1');
        } elseif (oxRegistry::getConfig()->getRequestParameter('showall_categories') == '0') {
            oxRegistry::getSession()->setVariable('showall_categories', '0');
        }

        if ($this->d3GetSet()->d3getLog()
            && $this->d3GetSet()->getValue('oxismodulelog')
        ) {
            $this->d3GetSet()->d3getLog()->log(
                d3log::INFO,
                __CLASS__,
                __FUNCTION__,
                __LINE__,
                "",
                "generating categories list"
            );
        }

        // calls database query execution
        $this->oSearchCategoriesList = $this->d3GetSearchHandler()->getSearchCategories();

        // decides, if an "extend" button (or a "less" button) is required for vendor list view
        if ($this->getaListController()->getSearchViewListType() == 'linklist'
            && $this->oSearchCategoriesList
            && $this->oSearchCategoriesList->count() == $this->d3GetSet()->getValue('iExtSearch_smallListItems')
        ) {
            // "more" button required
            $this->getaListController()->addTplParam('limitedVendorSearch', true);
        } elseif ($this->getaListController()->getSearchViewListType() == 'linklist'
            && $this->oSearchCategoriesList
            && $this->oSearchCategoriesList->count() > $this->d3GetSet()->getValue('iExtSearch_smallListItems')
        ) {
            // "less" button required
            $this->getaListController()->addTplParam('limitedCategoryButton', true);
        }

        // get vendors name, if one is selected
        if ($this->getaListController()->getSearchCategory()) {
            $this->getaListController()->addTplParam(
                'sSelectedCategory',
                $this->d3GetOwnSearchHandler()->getCategoryTitle($this->getaListController()->getSearchCategory())
            );

            $this->getaListController()->addTplParam('sSelectedCategoryId', $this->getaListController()->getSearchCategory());
        }
    }

    public function d3GetCategoryMultiFilter()
    {
        if (null == $this->_aSelectedCategoryMultiFilter
            && $this->_d3UseAlistFilters()
        ) {
            $this->_aSelectedCategoryMultiFilter = $this->d3GetSearchHandler()->getCategoryFilter();

            if (oxRegistry::getConfig()->getRequestParameter('d3searchcategorymultiselector')) {
                if (is_array($this->_aSelectedCategoryMultiFilter) && count($this->_aSelectedCategoryMultiFilter)) {
                    foreach($this->_aSelectedCategoryMultiFilter as $sValue) {
                        if (strlen(trim($sValue))) {
                            $sAddStr = "&amp;d3searchcategorymulti[" . urlencode(trim($sValue)) . "]=" . urlencode(trim($sValue));
                            $this->_sD3AdditionalParams .= $sAddStr;
                        }
                    }
                }

                $sAddStr = "&amp;d3searchcategorymultiselector=" .
                    urlencode(trim(oxRegistry::getConfig()->getRequestParameter('d3searchcategorymultiselector')));
                $this->_sD3AdditionalParams .= $sAddStr;
            }
        }

        return $this->_aSelectedCategoryMultiFilter;
    }

    /**
     * generates a hit related vendor list and its further informations (counters etc.)
     */
    protected function _d3GetVendorList()
    {
        if (false == $this->d3GetSet()->isActive()
            || false == $this->_d3UseAlistFilters()
            || false == $this->d3GetSet()->getValue('blExtSearch_showVendorList')
        ) {
            return;
        }

        // if not all vendors were shown, set state in session (shop wide access required)
        if (oxRegistry::getConfig()->getRequestParameter('showall_vendors') == '1') {
            oxRegistry::getSession()->setVariable('showall_vendors', '1');
        } elseif (oxRegistry::getConfig()->getRequestParameter('showall_vendors') == '0') {
            oxRegistry::getSession()->setVariable('showall_vendors', '0');
        }

        if ($this->d3GetSet()->d3getLog()
            && $this->d3GetSet()->getValue('oxismodulelog')
        ) {
            $this->d3GetSet()->d3getLog()->log(
                d3log::INFO,
                __CLASS__,
                __FUNCTION__,
                __LINE__,
                "",
                "generating vendor list"
            );
        }

        // calls database query execution
        $this->oSearchVendorList = $this->d3GetSearchHandler()->getSearchVendors();

        // decides, if an "extend" button (or a "less" button) is required for vendor list view
        if ($this->getaListController()->getSearchViewListType() == 'linklist'
            && $this->oSearchVendorList
            && $this->oSearchVendorList->count() == $this->d3GetSet()->getValue('iExtSearch_smallListItems')
        ) {
            // "more" button required
            $this->getaListController()->addTplParam('limitedVendorSearch', true);
        } elseif ($this->getaListController()->getSearchViewListType() == 'linklist'
            && $this->oSearchVendorList
            && $this->oSearchVendorList->count() > $this->d3GetSet()->getValue('iExtSearch_smallListItems')
        ) {
            // "less" button required
            $this->getaListController()->addTplParam('limitedVendorButton', true);
        }

        // get vendors name, if one is selected
        if ($this->getaListController()->getSearchVendor()) {
            $this->getaListController()->addTplParam(
                'sSelectedVendor',
                $this->d3GetOwnSearchHandler()->getVendorTitle($this->getaListController()->getSearchVendor())
            );

            $this->getaListController()->addTplParam('sSelectedVendorId', $this->getaListController()->getSearchVendor());
        }
    }

    public function d3GetVendorMultiFilter()
    {
        if (null == $this->_aSelectedVendorMultiFilter
            && $this->_d3UseAlistFilters()
        ) {
            $this->_aSelectedVendorMultiFilter = $this->d3GetSearchHandler()->getVendorFilter();

            if (oxRegistry::getConfig()->getRequestParameter('d3searchvendormultiselector')) {
                if (is_array($this->_aSelectedVendorMultiFilter) && count($this->_aSelectedVendorMultiFilter)) {
                    foreach($this->_aSelectedVendorMultiFilter as $sValue) {
                        if (strlen(trim($sValue))) {
                            $sAddStr = "&amp;d3searchvendormulti[" . urlencode(trim($sValue)) . "]=" . urlencode(trim($sValue));
                            $this->_sD3AdditionalParams .= $sAddStr;
                        }
                    }
                }

                $sAddStr = "&amp;d3searchvendormultiselector=" .
                    urlencode(trim(oxRegistry::getConfig()->getRequestParameter('d3searchvendormultiselector')));
                $this->_sD3AdditionalParams .= $sAddStr;
            }
        }

        return $this->_aSelectedVendorMultiFilter;
    }

    /**
     * generates a hit related manufacturer list and its further informations (counters etc.)
     */
    protected function _d3GetManufacturerList()
    {
        if (false == $this->d3GetSet()->isActive()
            || false == $this->_d3UseAlistFilters()
            || false == $this->d3GetSet()->getValue('blExtSearch_showManufacturerList')
        ) {
            return;
        }

        // if not all manufacturers were shown, set state in session (shop wide access required)
        if (oxRegistry::getConfig()->getRequestParameter('showall_manufacturers') == '1') {
            oxRegistry::getSession()->setVariable('showall_manufacturers', '1');
        } elseif (oxRegistry::getConfig()->getRequestParameter('showall_manufacturers') == '0') {
            oxRegistry::getSession()->setVariable('showall_manufacturers', '0');
        }

        if ($this->d3GetSet()->d3getLog() && $this->d3GetSet()->getFieldData('oxismodulelog')) {
            $this->d3GetSet()->d3getLog()->log(
                d3log::INFO,
                __CLASS__,
                __FUNCTION__,
                __LINE__,
                "",
                "generating manufacturer list"
            );
        }

        // calls database query execution
        $this->oSearchManufacturerList = $this->d3GetSearchHandler()->getSearchManufacturers();

        // decides, if an "extend" button (or a "less" button) is required for manufacturer list view
        if ($this->getaListController()->getSearchViewListType() == 'linklist'
            && $this->oSearchManufacturerList
            && $this->oSearchManufacturerList->count() == $this->d3GetSet()->getValue('iExtSearch_smallListItems')
        ) {
            // "more" button required
            $this->getaListController()->addTplParam('limitedManufacturerSearch', true);
        } elseif ($this->getaListController()->getSearchViewListType() == 'linklist'
            && $this->oSearchManufacturerList
            && $this->oSearchManufacturerList->count() > $this->d3GetSet()->getValue('iExtSearch_smallListItems')
        ) {
            // "less" button required
            $this->getaListController()->addTplParam('limitedManufacturerButton', true);
        }

        // get manufacturers name, if one is selected
        if ($this->getaListController()->getSearchManufacturer()) {
            $this->getaListController()->addTplParam(
                'sSelectedManufacturer',
                $this->d3GetOwnSearchHandler()->getManufacturerTitle($this->getaListController()->getSearchManufacturer())
            );
            $this->getaListController()->addTplParam(
                'sSelectedManufacturerId',
                $this->getaListController()->getSearchManufacturer()
            );
        }
    }

    public function d3GetManufacturerMultiFilter()
    {
        if (null == $this->_aSelectedManufacturerMultiFilter
            && $this->_d3UseAlistFilters()
        ) {
            $this->_aSelectedManufacturerMultiFilter = $this->d3GetSearchHandler()->getManufacturerFilter();

            if (oxRegistry::getConfig()->getRequestParameter('d3searchmanufacturermultiselector')) {
                if (is_array($this->_aSelectedManufacturerMultiFilter) && count($this->_aSelectedManufacturerMultiFilter)) {
                    foreach($this->_aSelectedManufacturerMultiFilter as $sValue) {
                        if (strlen(trim($sValue))) {
                            $sAddStr = "&amp;d3searchmanufacturermulti[" . urlencode(trim($sValue)) . "]=" . urlencode(trim($sValue));
                            $this->_sD3AdditionalParams .= $sAddStr;
                        }
                    }
                }
                $sAddStr = "&amp;d3searchmanufacturermultiselector=" .
                    urlencode(trim(oxRegistry::getConfig()->getRequestParameter('d3searchmanufacturermultiselector')));
                $this->_sD3AdditionalParams .= $sAddStr;
            }
        }

        return $this->_aSelectedManufacturerMultiFilter;
    }

    /**
     * generates a hit related attribute list
     */
    protected function _d3GetAttributeList()
    {
        if (false == $this->d3GetSet()->isActive()
            || false == $this->_d3UseAlistFilters()
            || false == $this->d3GetSet()->getValue('blExtSearch_showAttributeList')
        ) {
            return;
        }

        if ($this->d3GetSet()->d3getLog()
            && $this->d3GetSet()->getFieldData('oxismodulelog')
        ) {
            $this->d3GetSet()->d3getLog()->log(
                d3log::INFO,
                __CLASS__,
                __FUNCTION__,
                __LINE__,
                "",
                "generating attribute list"
            );
        }

        // calls database query execution
        $this->aSearchAttribList = $this->d3GetSearchHandler()->getSearchAttributes();
    }

    /**
     * @return array
     */
    public function d3GetAttributeFilters()
    {
        if (null == $this->_aSelectedAttributes
            && $this->_d3UseAlistFilters()
        ) {
            $this->_aSelectedAttributes = $this->d3GetSearchHandler()->getAttributeFilters();

            foreach ($this->_aSelectedAttributes as $sKey => $mValue) {
                if (is_array($mValue) && count($mValue)) {
                    foreach ($mValue as $iIdent => $sValue) {
                        $sAddStr = "&amp;d3searchattribmulti[$sKey][$iIdent]=" . urlencode(trim($sValue));
                        $this->_sD3AdditionalParams .= $sAddStr;
                    }
                } elseif (is_string($mValue) && trim($mValue)) {
                    $sAddStr = "&amp;d3searchattrib[$sKey]=" . urlencode(trim($mValue));
                    $this->_sD3AdditionalParams .= $sAddStr;
                }
            }

            $this->getaListController()->addTplParam('aD3AttribFilters', $this->_aSelectedAttributes);
        }

        return $this->_aSelectedAttributes;
    }

    /**
     * @return array
     */
    public function d3GetPriceSelectors()
    {
        if (false == $this->_d3UseAlistFilters()) {
            return array();
        }

        $mPriceSelectors = oxRegistry::getConfig()->getRequestParameter('priceselector');

        if (is_array($mPriceSelectors)) {
            $this->aPriceSelector['min'] = $mPriceSelectors['min'];
            $this->aPriceSelector['max'] = $mPriceSelectors['max'];
            foreach ($this->aPriceSelector as $sKey => $sValue) {
                $this->aPriceSelector[$sKey] = str_replace(',', '.', $sValue);
            }
        } else {
            $this->sPriceSelector = str_replace(',', '.', $mPriceSelectors);
        }

        $this->_d3SetPriceSelectorValues();

        return array(
            'sPriceSelector' => $this->sPriceSelector,
            'aPriceSelector' => $this->aPriceSelector
        );
    }

    /**
     * set url extensions and smarty variables, if price selector is chosen
     */
    protected function _d3SetPriceSelectorValues()
    {
        // price selectors original values
        if ($this->d3HasjQuerySlider()
            && oxRegistry::getConfig()->getRequestParameter('priceselector')
            && ($aPSOV = oxRegistry::getConfig()->getRequestParameter('d3psov'))
        ) {
            if (isset($aPSOV) && is_array($aPSOV)) {
                foreach ($aPSOV as $sKey => $sValue) {
                    $this->_sD3AdditionalParams .= "&amp;d3psov[".$sKey."]=" . urlencode($sValue);
                    $this->getaListController()->addTplParam(
                        'additionalparams',
                        $this->getaListController()->getViewDataElement('additionalparams') .
                        "&amp;d3psov[".$sKey."]=" . urlencode($sValue)
                    );
                };
            }
        }

        if ($this->d3HasjQuerySlider()
            && is_array($this->aPriceSelector)
        ) {
            $this->getaListController()->addTplParam(
                'submpriceselectors',
                array('min' => $this->aPriceSelector['min'] * 100, 'max' => $this->aPriceSelector['max'] * 100)
            );
            $this->getaListController()->addTplParam('priceselector', implode('-', $this->aPriceSelector));
            $this->_sD3AdditionalParams .= "&amp;priceselector=" . urlencode(implode('-', $this->aPriceSelector));
            $this->getaListController()->addTplParam(
                'additionalparams',
                $this->getaListController()->getViewDataElement('additionalparams') .
                "&amp;priceselector=" . urlencode(
                    implode('-', $this->aPriceSelector)
                )
            );
        } elseif ($this->sPriceSelector) {
            $this->getaListController()->addTplParam('priceselector', $this->sPriceSelector);
            $this->_sD3AdditionalParams .= "&amp;priceselector=" . urlencode($this->sPriceSelector);
            $this->getaListController()->addTplParam(
                'additionalparams',
                $this->getaListController()->getViewDataElement('additionalparams') .
                "&amp;priceselector=" . urlencode($this->sPriceSelector)
            );
        }
    }

    /**
     * @return array
     */
    public function d3GetPriceFilters()
    {
        return $this->d3GetSearchHandler()->getPriceSelectors();
    }

    /**
     * @return d3_cfg_mod
     */
    public function d3GetSet()
    {
        $oSet = d3_cfg_mod::get($this->_d3getModId());
        // set "allow search without searchparam"
        $oSet->setValue('blExtSearch_emptySearch', true);

        return $oSet;
    }

    /**
     * @return string
     */
    private function _d3getModId()
    {
        return $this->_sModId;
    }

    /**
     * performance, use a class wide instance
     *
     * @return d3_oxsearch_extsearch
     */
    public function d3GetSearchHandler()
    {
        if (!$this->oD3SearchHandler) {
            $this->oD3SearchHandler = oxNew('oxsearch');
        }

        return $this->oD3SearchHandler;
    }

    /**
     * @deprecated , use d3GetSearchHandler instead
     * @return mixed
     */
    protected function _d3GetSearchHandler()
    {
        return $this->d3GetSearchHandler();
    }

    /**
     * performance, use a class wide instance
     *
     * @return d3_search
     */
    public function d3GetOwnSearchHandler()
    {
        if (!$this->oD3OwnSearchHandler) {
            $this->oD3OwnSearchHandler = oxNew('d3_search');
        }

        return $this->oD3OwnSearchHandler;
    }

    /**
     * @deprecated , use d3GetOwnSearchHandler instead
     * @return d3_search
     */
    protected function _d3GetOwnSearchHandler()
    {
        return $this->d3GetOwnSearchHandler();
    }

    /**
     * Template variable getter. Returns hits related vendor list (generating in $this->_getVendorList() above)
     *
     * @return oxCategoryList
     */
    public function d3GetCategoryList()
    {
        if (isset($this->oSearchCategoriesList)
            && $this->oSearchCategoriesList
            && $this->oSearchCategoriesList instanceof oxCategoryList
            && $this->oSearchCategoriesList->count()
        ) {
            return $this->oSearchCategoriesList;
        }

        $oCategoryList = oxNew('oxcategorylist');

        return $oCategoryList;
    }

    /**
     * Template variable getter. Returns hits related vendor list (generating in $this->_getVendorList() above)
     *
     * @return oxvendorlist
     */
    public function d3GetVendorList()
    {
        if (isset($this->oSearchVendorList)
            && $this->oSearchVendorList
            && $this->oSearchVendorList instanceof oxVendorList
            && $this->oSearchVendorList->count()
        ) {
            return $this->oSearchVendorList;
        }

        $oVendorList = oxNew('oxvendorlist');

        return $oVendorList;
    }

    /**
     * Template variable getter.  Returns hits related manufacturer list
     * (generating in $this->_d3GetManufacturerList() above)
     *
     * @return oxmanufacturerlist
     */
    public function d3GetManufacturerList()
    {
        if (isset($this->oSearchManufacturerList)
            && $this->oSearchManufacturerList
            && $this->oSearchManufacturerList instanceof oxManufacturerList
            && $this->oSearchManufacturerList->count()
        ) {
            return $this->oSearchManufacturerList;
        }

        $oManufacturerList = oxNew('oxmanufacturerlist');

        return $oManufacturerList;
    }

    /**
     * Template variable getter. Returns hits related attribute list (generating in $this->_d3GetAttributeList())
     *
     * @return array
     */
    public function d3GetAttributeList()
    {
        if (isset($this->aSearchAttribList) && $this->aSearchAttribList && count($this->aSearchAttribList)) {
            return $this->aSearchAttribList;
        }

        return array();
    }

    /**
     * @param $sAttrId
     *
     * @return bool
     */
    public function d3AttributeFilterUseMultipleValues($sAttrId)
    {
        return $this->d3GetSearchHandler()->d3AttributeFilterUseMultipleValues($sAttrId);
    }

    /**
     * @return bool
     */
    public function d3CategoryFilterUseMultipleValues()
    {
        return $this->d3GetSearchHandler()->d3CategoryFilterUseMultipleValues();
    }

    /**
     * @return bool
     */
    public function d3VendorFilterUseMultipleValues()
    {
        return $this->d3GetSearchHandler()->d3VendorFilterUseMultipleValues();
    }

    /**
     * @return bool
     */
    public function d3ManufacturerFilterUseMultipleValues()
    {
        return $this->d3GetSearchHandler()->d3ManufacturerFilterUseMultipleValues();
    }

    /**
     * generates a hit related price step list
     */
    public function d3GeneratePriceSteps()
    {
        if (false == $this->d3GetSet()->isActive()
            || false == $this->_d3UseAlistFilters()
            || false == $this->d3GetSet()->getValue('blExtSearch_showPriceSelector')
        ) {
            return;
        }

        $this->aPriceSteps = $this->d3GetSearchHandler()->getPriceSteps();

        // adds used price selector values
        if ($this->d3HasjQuerySlider()
            && is_array($this->aPriceSelector)
        ) {
            $this->getaListController()->addTplParam('sSelectedPriceStep', implode('-', $this->aPriceSelector));
        } elseif ($this->sPriceSelector) {
            $this->getaListController()->addTplParam('sSelectedPriceStep', $this->sPriceSelector);
        }
    }

    /**
     * @deprecated , use d3GeneratePriceSteps instead
     */
    protected function _d3GetPriceSteps()
    {
        $this->d3GetPriceSteps();
    }

    /**
     * Template variable getter. Returns price selector list (generated in $this->_d3GetPriceSteps() above)
     *
     * @return array
     */
    public function d3getPriceSteps()
    {
        if (is_array($this->aPriceSteps) && count($this->aPriceSteps)) {
            return $this->aPriceSteps;
        }

        return array();
    }

    /**
     * @return bool
     */
    public function d3HasjQuerySlider()
    {
        if ($this->d3GetSet()->getValue('blExtSearch_showPriceSelector')
            && $this->d3GetSet()->getValue('sExtSearch_PriceSelectorsDispType') == 'jqslider'
        ) {
            /** @var oeThemeSwitcherThemeManager $oThemeManager */
            if (class_exists('oeThemeSwitcherThemeManager') == true
                && ($oThemeManager = oxNew('oeThemeSwitcherThemeManager'))
                && $oThemeManager->isMobileThemeRequested()
            ) {
                return false;
            }

            return true;
        }

        return false;
    }

    /**
     * @param string $sBase
     * @return string
     */
    public function d3AddBaseUrlParams($sBase = '')
    {
        $sRet = '';
        if ($this->d3GetSet()->isActive()) {
            if (false == strstr($sBase, '&amp;d3searchcategorymultiselector=')
                && oxRegistry::getConfig()->getRequestParameter('d3searchcategorymultiselector')
            ) {
                $sRet .= "&amp;d3searchcategorymultiselector=" . oxRegistry::getConfig()->getRequestParameter('d3searchcategorymultiselector');

                if ($this->d3GetSearchHandler()->d3GetMultiFilterData('d3searchcategorymulti')
                    && ($aCategoryMulti = $this->d3GetSearchHandler()->d3GetMultiFilterData('d3searchcategorymulti'))
                ) {
                    if (isset($aCategoryMulti) && is_array($aCategoryMulti)) {
                        foreach ($aCategoryMulti as $sKey => $sValue) {
                            if (strlen(trim($sValue))) {
                                $sRet .= "&amp;d3searchcategorymulti[" . $sKey . "]=" . urlencode($sValue);
                            }
                        };
                    }
                }
            }

            if (false == strstr($sBase, '&amp;d3searchvendormultiselector=')
                && oxRegistry::getConfig()->getRequestParameter('d3searchvendormultiselector')
            ) {
                $sRet .= "&amp;d3searchvendormultiselector=" . oxRegistry::getConfig()->getRequestParameter('d3searchvendormultiselector');

                if ($this->d3GetSearchHandler()->d3GetMultiFilterData('d3searchvendormulti')
                    && ($aVendorMulti = $this->d3GetSearchHandler()->d3GetMultiFilterData('d3searchvendormulti'))
                ) {
                    if (isset($aVendorMulti) && is_array($aVendorMulti)) {
                        foreach ($aVendorMulti as $sKey => $sValue) {
                            if (strlen(trim($sValue))) {
                                $sRet .= "&amp;d3searchvendormulti[" . $sKey . "]=" . urlencode($sValue);
                            }
                        };
                    }
                }
            }

            if (false == strstr($sBase, '&amp;d3searchmanufacturermultiselector=') &&
                oxRegistry::getConfig()->getRequestParameter('d3searchmanufacturermultiselector')
            ) {
                $sRet .= "&amp;d3searchmanufacturermultiselector=" . oxRegistry::getConfig()->getRequestParameter('d3searchmanufacturermultiselector');

                if ($this->d3GetSearchHandler()->d3GetMultiFilterData('d3searchmanufacturermulti')
                    && ($aManufacturerMulti = $this->d3GetSearchHandler()->d3GetMultiFilterData('d3searchmanufacturermulti'))
                ) {
                    if (isset($aManufacturerMulti) && is_array($aManufacturerMulti)) {
                        foreach ($aManufacturerMulti as $sKey => $sValue) {
                            if (strlen(trim($sValue))) {
                                $sRet .= "&amp;d3searchmanufacturermulti[" . $sKey . "]=" . urlencode($sValue);
                            }
                        };
                    }
                }
            }

            // price selectors original values
            if (false == strstr($sBase, '&amp;d3psov=')
                && $this->d3HasjQuerySlider()
                && oxRegistry::getConfig()->getRequestParameter('priceselector')
                && ($aPSOV = oxRegistry::getConfig()->getRequestParameter('d3psov'))
            ) {
                if (isset($aPSOV) && is_array($aPSOV)) {
                    foreach ($aPSOV as $sKey => $sValue) {
                        $sRet .= "&amp;d3psov[".$sKey."]=" . urlencode($sValue);
                    };
                }
            }

            // adds used price selector values
            $this->d3GetPriceSelectors();
            if (false == strstr($sBase, '&amp;priceselector=')
                && $this->d3HasjQuerySlider()
                && is_array($this->aPriceSelector)
            ) {
                $sRet .= "&amp;priceselector=" . urlencode(implode('-', $this->aPriceSelector));
            } elseif ($this->sPriceSelector) {
                $sRet .= "&amp;priceselector=" . urlencode($this->sPriceSelector);
            }

            if (is_array($this->getD3AdditionalSearchParamList()) && count($this->getD3AdditionalSearchParamList())) {
                foreach ($this->getD3AdditionalSearchParamList() as $sAddSearchParam) {
                    $sParamValue = oxRegistry::getConfig()->getRequestParameter($sAddSearchParam);
                    if (false == strstr($sBase, '&amp;'.$sAddSearchParam.'=') && $sParamValue) {
                        $sRet .= "&amp;" . $sAddSearchParam . "=" . urlencode($sParamValue);
                    }
                }
            }

            if (false == strstr($sBase, '&amp;isextsearch=')
                && (strlen($sRet) || $this->_d3HasAttributeValues())
            ) {
                $sRet .= "&amp;isextsearch=alist";
            }
        }

        return $sRet;
    }

    /**
     * @return array
     */
    public function getD3AdditionalSearchParamList()
    {
        switch (oxRegistry::getConfig()->getActiveView()->getClassName()) {
            case 'vendorlist':
                if (($sKey = array_search('searchvendor', $this->_aD3AdditionalSearchParams))) {
                    unset($this->_aD3AdditionalSearchParams[$sKey]);
                }
                break;
            case 'manufacturerlist':
                if (($sKey = array_search('searchmanufacturer', $this->_aD3AdditionalSearchParams))) {
                    unset($this->_aD3AdditionalSearchParams[$sKey]);
                }
                break;
            case 'alist':
                if (($sKey = array_search('searchcnid', $this->_aD3AdditionalSearchParams))) {
                    unset($this->_aD3AdditionalSearchParams[$sKey]);
                }
                break;
        }

        return $this->_aD3AdditionalSearchParams;
    }

    /**
     * @return string
     */
    public function d3GetDeselectValue()
    {
        return $this->d3GetSearchHandler()->d3GetDeselectValue();
    }

    /**
     * @return string
     */
    public function d3getFilterPageId()
    {
        switch (strtolower($this->getaListController()->getClassName())) {
            case 'manufacturerlist':
                $sIdent = oxRegistry::getConfig()->getRequestParameter('mnid');
                break;
            default:
                $sIdent = oxRegistry::getConfig()->getRequestParameter('cnid');
        }

        $sPageId = '##'.
            oxRegistry::getLang()->getLanguageAbbr()."##".
            oxRegistry::getConfig()->getShopId()."##".
            $sIdent;

        return $sPageId;
    }

    /**
     * @param $sOptionTitle
     *
     * @return string
     */
    public function d3GetMultipleSelectionTranslation($sOptionTitle)
    {
        return sprintf(oxRegistry::getLang()->translateString('D3_EXTSEARCH_EXT_MULTIPLESELECT'), $sOptionTitle);
    }

    /**
     * @return string
     */
    public function d3GetPriceSliderInfoMinValue()
    {
        $dMin        = 0;
        $aPriceSteps = $this->d3getPriceSteps();
        if (count($aPriceSteps)) {
            $dMin = $aPriceSteps['min'];
        }

        $dMin = sprintf('%.2f', $dMin / 100);

        return $dMin;
    }

    /**
     * @return string
     */
    public function d3GetPriceSliderInfoMaxValue()
    {
        $dMax        = 0;
        $aPriceSteps = $this->d3getPriceSteps();

        if (count($aPriceSteps)) {
            $dMax = $aPriceSteps['max'];
        }

        $dMax = sprintf('%.2f', $dMax / 100);

        return $dMax;
    }

    /**
     * @return string
     */
    public function d3GetPriceSliderInputMinValue()
    {
        $dMin               = 0;
        $aPriceSteps        = $this->d3getPriceSteps();
        $aSubmPriceSelector = (array) $this->getaListController()->getViewParameter('submpriceselectors');
        if (count($aSubmPriceSelector) && $aSubmPriceSelector['min']) {
            $dMin = $aSubmPriceSelector['min'];
        } elseif (count($aPriceSteps)) {
            $dMin = $aPriceSteps['min'];
        }

        $dMin = sprintf('%.2f', $dMin / 100);

        return $dMin;
    }

    /**
     * @return string
     */
    public function d3GetPriceSliderInputMaxValue()
    {
        $dMax               = 0;
        $aPriceSteps        = $this->d3getPriceSteps();
        $aSubmPriceSelector = (array) $this->getaListController()->getViewParameter('submpriceselectors');

        // per Formular gesetzte Werte
        if (count($aSubmPriceSelector) && $aSubmPriceSelector['max']) {
            $dMax = $aSubmPriceSelector['max'];
        } elseif (count($aPriceSteps)) {
            $dMax = $aPriceSteps['max'];
        }

        $dMax = sprintf('%.2f', $dMax / 100);

        return $dMax;
    }

    /**
     * @return array
     */
    public function d3getPriceLimits()
    {
        $aPriceSliderOriginalValues = oxRegistry::getConfig()->getRequestParameter('d3psov');

        if (isset($aPriceSliderOriginalValues) && is_array($aPriceSliderOriginalValues)) {
            return array(
                'min'   => str_replace('.', '', $aPriceSliderOriginalValues['min']),
                'max'   => str_replace('.', '', $aPriceSliderOriginalValues['max']),
            );
        }

        return $this->d3GetSearchHandler()->getPriceLimits();
    }

    /**
     * @return string
     */
    public function d3GetPriceSliderOriginalMinValue()
    {
        $aPriceSliderOriginalValues = oxRegistry::getConfig()->getRequestParameter('d3psov');
        if (isset($aPriceSliderOriginalValues)
            && is_array($aPriceSliderOriginalValues)
            && isset($aPriceSliderOriginalValues['min'])
        ) {
            return $aPriceSliderOriginalValues['min'];
        }

        return $this->d3GetPriceSliderInputMinValue();
    }

    /**
     * @return string
     */
    public function d3GetPriceSliderOriginalMaxValue()
    {
        $aPriceSliderOriginalValues = oxRegistry::getConfig()->getRequestParameter('d3psov');
        if (isset($aPriceSliderOriginalValues)
            && is_array($aPriceSliderOriginalValues)
            && isset($aPriceSliderOriginalValues['max'])
        ) {
            return $aPriceSliderOriginalValues['max'];
        }

        return $this->d3GetPriceSliderInputMaxValue();
    }

    public function d3ClearFilter()
    {
        $this->d3GetSearchHandler()->d3ClearFilters();
        $oView = oxRegistry::getConfig()->getActiveView();
        $oView->setFncName(null);
    }

    public function addNavigationParams($aParams)
    {
        $aAddParams = array();

        if ($this->d3GetSet()->isActive()
            && $this->_d3UseAlistFilters()
        ) {
            if (strlen(oxRegistry::getConfig()->getRequestParameter('searchparam'))) {
                $aAddParams['searchparam'] = htmlspecialchars(
                    html_entity_decode(oxRegistry::getConfig()->getRequestParameter('searchparam'))
                );
            }

            if ($this->d3HasjQuerySlider()
                && oxRegistry::getConfig()->getRequestParameter('priceselector')
                && ($aPSOV = oxRegistry::getConfig()->getRequestParameter('d3psov'))
            ) {
                if (isset($aPSOV) && is_array($aPSOV)) {
                    foreach ($aPSOV as $sKey => $sValue) {
                        $aAddParams['d3psov['.$sKey.']'] = urlencode($sValue);
                    };
                }
            }

            if (oxRegistry::getConfig()->getRequestParameter('d3searchcategorymultiselector')) {
                $aAddParams['d3searchcategorymultiselector'] = oxRegistry::getConfig()->getRequestParameter('d3searchcategorymultiselector');

                if ($this->d3GetSearchHandler()->d3GetMultiFilterData('d3searchcategorymulti')
                    && ($aCategoryMulti = $this->d3GetSearchHandler()->d3GetMultiFilterData('d3searchcategorymulti'))
                ) {
                    if (isset($aCategoryMulti) && is_array($aCategoryMulti)) {
                        foreach ($aCategoryMulti as $sKey => $sValue) {
                            if (strlen(trim($sValue))) {
                                $aAddParams['d3searchcategorymulti[' . $sKey . ']'] = urlencode($sValue);
                            }
                        };
                    }
                }
            }

            if (oxRegistry::getConfig()->getRequestParameter('d3searchvendormultiselector')) {
                $aAddParams['d3searchvendormultiselector'] = oxRegistry::getConfig()->getRequestParameter('d3searchvendormultiselector');

                if ($this->d3GetSearchHandler()->d3GetMultiFilterData('d3searchvendormulti')
                    && ($aVendorMulti = $this->d3GetSearchHandler()->d3GetMultiFilterData('d3searchvendormulti'))
                ) {
                    if (isset($aVendorMulti) && is_array($aVendorMulti)) {
                        foreach ($aVendorMulti as $sKey => $sValue) {
                            if (strlen(trim($sValue))) {
                                $aAddParams['d3searchvendormulti[' . $sKey . ']'] = urlencode($sValue);
                            }
                        };
                    }
                }
            }

            if (oxRegistry::getConfig()->getRequestParameter('d3searchmanufacturermultiselector')) {
                $aAddParams['d3searchmanufacturermultiselector'] = oxRegistry::getConfig()->getRequestParameter('d3searchmanufacturermultiselector');

                if ($this->d3GetSearchHandler()->d3GetMultiFilterData('d3searchmanufacturermulti')
                    && ($aManufacturerMulti = $this->d3GetSearchHandler()->d3GetMultiFilterData('d3searchmanufacturermulti'))
                ) {
                    if (isset($aManufacturerMulti) && is_array($aManufacturerMulti)) {
                        foreach ($aManufacturerMulti as $sKey => $sValue) {
                            if (strlen(trim($sValue))) {
                                $aAddParams['d3searchmanufacturermulti[' . $sKey . ']'] = urlencode($sValue);
                            }
                        };
                    }
                }
            }

            $this->d3GetPriceSelectors();
            // adds used price selector values
            if ($this->d3HasjQuerySlider()
                && is_array($this->aPriceSelector)
            ) {
                $aAddParams['priceselector'] = implode('-', $this->aPriceSelector);
            } elseif ($this->sPriceSelector) {
                $aAddParams['priceselector'] = $this->sPriceSelector;
            }

            if (is_array($this->getD3AdditionalSearchParamList())
                && count($this->getD3AdditionalSearchParamList())
            ) {
                foreach ($this->getD3AdditionalSearchParamList() as $sAddSearchParam) {
                    $mParamValue = oxRegistry::getConfig()->getRequestParameter($sAddSearchParam);
                    if (is_array($mParamValue) && count($mParamValue)) {
                        foreach ($mParamValue as $sKey => $sValue) {
                            $aAddParams[$sAddSearchParam.'['.$sKey.']'] = urlencode($sValue);
                        }
                    } elseif (is_string($mParamValue)) {
                        $aAddParams[$sAddSearchParam] = urlencode($mParamValue);
                    }
                }
            }

            if ((count($aAddParams) || $this->_d3HasAttributeValues()) &&
                ($sExtSearchFlag = oxRegistry::getConfig()->getRequestParameter('isextsearch'))
            ) {
                $aAddParams['isextsearch'] = $sExtSearchFlag;
            }
        }

        return array_merge($aParams, $aAddParams);
    }

    /**
     * @return bool
     */
    private function _d3UseAlistFilters()
    {
        if (null === $this->_blUseAlistFilter) {
            $this->_blUseAlistFilter = ($this->d3GetSet()->getLicenseConfigData('blUseFilterInArticleLists', false) || $this->d3GetSet()->isDemo())
                && $this->d3GetSet()->getValue('blExtSearch_useAListFilter');
        }
        return $this->_blUseAlistFilter;
    }

    /**
     * @return d3_alist_extsearch
     */
    public function getaListController()
    {
        return $this->_oaListController;
    }

    /**
     * @return string
     */
    public function getD3AdditionalParams()
    {
        return $this->_sD3AdditionalParams;
    }
}
