<?php
/**
 * --------------------------------------------------------------------------------------------
 * VP Custom Filter Module - Joomla! 3 Module for VirtueMart 3.0
 * --------------------------------------------------------------------------------------------
 * @package    VP Custom Filter Module
 * @author     Abhishek Das
 * @copyright  Copyright (C) 2012-2021 VirtuePlanet Services LLP. All rights reserved.
 * @license    GNU General Public License version 2. http://www.gnu.org/licenses/gpl-2.0.html
 * @link       http://www.virtueplanet.com
 * --------------------------------------------------------------------------------------------
*/
defined('_JEXEC') or die;

// Register VirtueMart config to Joomla autoloader
JLoader::register('VmConfig', JPATH_ADMINISTRATOR . '/components/com_virtuemart/helpers/config.php');

// Load VirtueMart Config and language
VmConfig::loadConfig();
VmConfig::loadJLang('com_virtuemart', true);

// Register all required VirtueMart classes to Joomla autoloader
JLoader::register('VirtueMartModelVendor',   JPATH_ADMINISTRATOR . '/components/com_virtuemart/models/vendor.php');
JLoader::register('calculationHelper',       JPATH_ADMINISTRATOR . '/components/com_virtuemart/helpers/calculationh.php');
JLoader::register('ShopFunctions',           JPATH_ADMINISTRATOR . '/components/com_virtuemart/helpers/shopfunctions.php');
JLoader::register('VmImage',                 JPATH_ADMINISTRATOR . '/components/com_virtuemart/helpers/image.php');
JLoader::register('TableMedias',             JPATH_ADMINISTRATOR . '/components/com_virtuemart/tables/medias.php');
JLoader::register('TableCategories',         JPATH_ADMINISTRATOR . '/components/com_virtuemart/tables/categories.php');
JLoader::register('VirtueMartModelCategory', JPATH_ADMINISTRATOR . '/components/com_virtuemart/models/category.php');
JLoader::register('VirtueMartModelProduct',  JPATH_ADMINISTRATOR . '/components/com_virtuemart/models/product.php');
JLoader::register('vmCustomPlugin',          JPATH_ADMINISTRATOR . '/components/com_virtuemart/plugins/vmcustomplugin.php');

class ModVPCustomFilterHelper
{
	protected $app;
	protected $db;
	protected $input;
	protected $filter_input;
	protected $category_id;
	protected $manufacturer_ids;
	protected $keyword;
	protected $product_ids;
	protected $params;
	protected $modParams;
	protected $filterHelper;
	protected $currencyHelper;
	protected $inputFilter;
	protected $uri;
	protected $cache;
	
	public function __construct($modParams)
	{
		if(!JPluginHelper::isEnabled('system', 'vpframework'))
		{
			throw new Exception('VP Custom Filter Module Error: System - VirtuePlanet Framework Plugin is not enabled.');
		}
		
		$this->app              = JFactory::getApplication();
		$this->db               = JFactory::getDbo();
		$this->input            = $this->app->input;
		$this->params           = plgSystemVPFrameworkHelper::getTemplate()->params;
		$this->modParams        = $modParams;
		$this->filterHelper     = VPFrameworkFilter::getInstance($this->params, $this->modParams);
		$this->category_id      = $this->filterHelper->get('category_id');
		$this->manufacturer_ids = $this->filterHelper->get('manufacturer_ids');
		$this->keyword          = $this->filterHelper->get('keyword');
		$this->product_ids      = $this->filterHelper->get('product_ids');
		$this->filter_input     = $this->filterHelper->get('filter_input');
		$this->currencyHelper   = $this->filterHelper->get('currencyHelper');
	}
	
	public function getFilters($module_id)
	{
		$default_filter_order = array('manufacturers', 'fields', 'price');
		$filter_order = (array) $this->modParams->get('filter_order', $default_filter_order);
		
		$available_filter = array();
		$xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><form />');
		
		// Add dummy field because JForm can not parse empty form
		$dummy = $xml->addChild('field');
		$dummy->addAttribute('name', 'dummy');
		$dummy->addAttribute('type', 'hidden');
		$dummy->addAttribute('filter', 'unset');
		
		foreach($filter_order as $filter_type)
		{
			switch($filter_type)
			{
				case 'manufacturers':
					
					if($this->modParams->get('enable_manufacturer_filter', 1))
					{
						$excludeCategories = (array) $this->modParams->get('exclude_categories_manufacturer', array());
						
						if(!empty($excludeCategories) && in_array($this->category_id, $excludeCategories))
						{
							break;
						}
						
						$show_mfg_product_count = (int) $this->modParams->get('manufacturer_filter_product_count', 0);
						$manufactuers           = $this->getManufacturers(true);
						
						if(!empty($manufactuers) && count($manufactuers) > 1)
						{
							$fieldset = $xml->addChild('fieldset');
							$fieldset->addAttribute('name', 'manufacturers');
							$field = $fieldset->addChild('field');
							$field->addAttribute('name', 'cfm');
							$field->addAttribute('label', 'PLG_SYSTEM_VPFRAMEWORK_MANUFACTURERS_FILTER');
							$field->addAttribute('type', 'vpcf' . $this->modParams->get('manufacturer_filter_style', 'checkbox'));
							$field->addAttribute('display_style', $this->modParams->get('manufacturer_filter_style', 'checkbox'));
							$field->addAttribute('show_product_count', $show_mfg_product_count);
							$field->addAttribute('id_prefix', $module_id);
							$field->addAttribute('multiple', true);
							$field->addAttribute('show_quicksearch', $this->modParams->get('show_manufacturer_filter_quicksearch', 1));
							$field->addAttribute('show_clear', $this->modParams->get('show_manufacturer_filter_clear', 1));
							$field->addAttribute('clear_url', $this->getUrl('cfm', null, 'clear'));
							
							$max_height = $this->modParams->get('manufacturer_filter_max_height', '');
							$max_height = $max_height ? (int) $max_height : '';
							$field->addAttribute('max_height', $max_height);
							
							$nofollow = (int) $this->modParams->get('nofollow_noindex', 1);
							$field->addAttribute('nofollow', $nofollow);
							
							foreach($manufactuers as $mkey => $manufactuer)
							{
								$manufactuer->value = $manufactuer->virtuemart_manufacturer_id;
								$manufactuer->url   = $this->getUrl('cfm', null, $manufactuer->virtuemart_manufacturer_id);
								
								$option = $field->addChild('option', $manufactuer->mf_name);
								$option->addAttribute('value', $manufactuer->virtuemart_manufacturer_id);
								$option->addAttribute('url', $manufactuer->url);
								
								if($show_mfg_product_count)
								{
									$manufactuer->active_product_count = ($manufactuer->product_count - $manufactuer->inactive_product_count);
									$option->addAttribute('product_count', $manufactuer->active_product_count);
								}
							}
						}
					}
					
					break;
				
				case 'fields':
				
					if($cFields = $this->filterHelper->getCustomFields($this->modParams))
					{
						$fieldset = $xml->addChild('fieldset');
						$fieldset->addAttribute('name', 'custom_fields');
						$hasChild = false;
						
						foreach($cFields as $key => &$cField)
						{
							$cOptions = $this->getCustomFieldOption($cField, true);
							
							if(empty($cOptions))
							{
								continue;
							}
							
							$hasChild = true;
							
							$title = JText::sprintf('PLG_SYSTEM_VPFRAMEWORK_FIELD_FILTER', JText::_($cField->custom_title));
							
							if(!empty($cField->filter_title))
							{
								$title = JText::_($cField->filter_title);
							}
							
							$fieldType = 'vpcf' . strtolower($cField->display_style);
							
							if($cField->field_type == 'S')
							{
								if(!empty($cField->is_list) && $cField->is_list == '1' && !empty($cField->custom_value))
								{
									// Options need to be derived from custom value or default value
									$cOptions = $this->filterHelper->getFieldOptionsFromDefault($cField->custom_value, $cOptions);
								}
								
								if($cField->display_style != 'list')
								{
									$buttonFields = (array) $this->params->get('vm_button_fields', array());

									if(!empty($buttonFields) && in_array($cField->custom_id, $buttonFields))
									{
										$fieldType = 'vpcfbutton';
									}
								}
							}
							
							$field = $fieldset->addChild('field');
							$field->addAttribute('name', 'cff_' . $cField->custom_id);
							$field->addAttribute('label', $title);
							$field->addAttribute('type', $fieldType);
							$field->addAttribute('customfield_type', $cField->field_type);
							$field->addAttribute('is_list', $cField->is_list);
							$field->addAttribute('display_style', $cField->display_style);
							$field->addAttribute('max_height', $cField->max_height);
							$field->addAttribute('show_product_count', $cField->show_product_count);
							$field->addAttribute('id_prefix', $module_id);
							$field->addAttribute('multiple', true);
							$field->addAttribute('show_quicksearch', $cField->show_quicksearch);
							$field->addAttribute('show_clear', $cField->show_clear);
							$field->addAttribute('clear_url', $this->getUrl('cff_' . $cField->custom_id, null, 'clear'));
							
							$nofollow = (int) $this->modParams->get('nofollow_noindex', 1);
							$field->addAttribute('nofollow', $nofollow);
							
							foreach($cOptions as &$cOption)
							{
								if($cField->field_type == 'B')
								{
									$cOption->customfield_value = !empty($cOption->customfield_value) ? JText::_('JYES') : JText::_('JNO');
								}
								
								$cOption->value = bin2hex($cOption->customfield_value);
								$multiSelect    = ($cField->display_style == 'checkbox');
								$cOption->url   = $this->getUrl('cff_' . $cField->custom_id, null, $cOption->value, $multiSelect);
								
								$option = $field->addChild('option', (string) htmlspecialchars($cOption->customfield_value, ENT_COMPAT, 'UTF-8'));
								$option->addAttribute('value', (string) $cOption->value);
								$option->addAttribute('url', (string) $cOption->url);
								
								if($cField->field_type == 'S' && $fieldType == 'vpcfbutton')
								{
									$colorFields = (array) $this->params->get('vm_field_colors', array());

									if(array_key_exists($cOption->customfield_value, $colorFields))
									{
										$colorHexacode = $colorFields[$cOption->customfield_value];
										$background = str_replace('#', '', $colorHexacode);
										$class  = 'btn btn-fieldvalue btn-colorfield';
										$class .= ' vpf-colorfield-' . VPFrameworkVM::getColorFieldsCSSClass($cOption->customfield_value);
										$class .= ' ' . VPFrameworkVM::readableColour($background, 'btn-colorfield-dark', 'btn-colorfield-light');
										
										$option->addAttribute('class', (string) $class);
										$option->addAttribute('hide_name', 1);
										//$html .= '<span class="' . $class . '" title="' . strip_tags($name) . '"><span class="sr-only">' . $name . '</span></span>';
									}
								}
								
								if($cField->show_product_count)
								{
									$cOption->active_product_count = ($cOption->product_count - $cOption->inactive_product_count);
									$option->addAttribute('product_count', $cOption->active_product_count);
								}
							}
						}
						
						if(!$hasChild)
						{
							$dom = dom_import_simplexml($fieldset);
							$dom->parentNode->removeChild($dom);
						}
					}
					
					break;
				
				case 'price':
					
					$excludeCategories = (array) $this->modParams->get('exclude_categories_price', array());
					
					if(!empty($excludeCategories) && in_array($this->category_id, $excludeCategories))
					{
						break;
					}
					
					$userModel    = VmModel::getModel('user');
					$user         = $userModel->getCurrentUser();
					$shopperModel = VmModel::getModel('shoppergroup');
					$displayPrice = false;

					if(count($user->shopper_groups) > 0)
					{
						$sprgrp = $shopperModel->getShopperGroup($user->shopper_groups[0]);
					}
					else
					{
						$sprgrp = $shopperModel->getDefault($user->JUser->guest);
					}
					
					if(!empty($sprgrp) && $sprgrp->custom_price_display)
					{
						if($sprgrp->show_prices)
						{
							$displayPrice = true;
						}
					}
					elseif(VmConfig::get('show_prices', 1))
					{
						$displayPrice = true;
					}
					
					if($displayPrice && $this->modParams->get('enable_price_filter', 1))
					{
						$active_currency_id = $this->filterHelper->getActiveCurrencyId();
						$vendorCurrency     = $this->filterHelper->getVendorCurrency();
						$activeCurrency     = $this->filterHelper->getCurrencyData($active_currency_id);
						$vendor_currency_id = $vendorCurrency['vendor_currency'];
						$customRanges       = $this->getCustomPriceRanges();
						
						$min_price = null;
						$max_price = null;
						
						// If custom price range is maintained for this category
						if(isset($customRanges[$this->category_id]))
						{
							$min_price = $customRanges[$this->category_id]->min_price;
							$max_price = $customRanges[$this->category_id]->max_price;
						}
						// Do we need to do complex price calcuations
						elseif($this->modParams->get('complex_price_filter', 0))
						{
							$range     = $this->getComplexPriceRange();
							$min_price = isset($range->min_price) ? $range->min_price : null;
							$max_price = isset($range->max_price) ? $range->max_price : null;
						}
						else
						{
							$range     = $this->getPriceRange();
							$min_price = $range->min_price;
							$max_price = $range->max_price;

							if(!empty($max_price) || !empty($range->max_override_price))
							{
								$min_price = !is_null($min_price) ? $this->filterHelper->calculateFinalPrice($min_price) : null;
								$max_price = !is_null($max_price) ? $this->filterHelper->calculateFinalPrice($max_price) : null;

								if(!is_null($range->min_override_price) && ($range->min_override_price < $min_price || is_null($min_price)))
								{
									$min_price = $range->min_override_price;
								}
								
								if(!is_null($range->max_override_price) && ($range->max_override_price > $max_price || is_null($max_price)))
								{
									$max_price = $range->max_override_price;
								}
							}
						}
						
						if($active_currency_id != $vendor_currency_id)
						{
							$min_price = !is_null($min_price) ? $this->currencyHelper->convertCurrencyTo($active_currency_id, $min_price, false) : null;
							$max_price = !is_null($max_price) ? $this->currencyHelper->convertCurrencyTo($active_currency_id, $max_price, false) : null;
						}
						
						if(empty($activeCurrency))
						{
							throw new Exception('VP Custom Filter Module could not able to load active currency data.');
						}
						
						if($min_price !== null && $max_price !== null && $max_price > $min_price && ($max_price - $min_price) > 1)
						{
							$min_price = $this->filterHelper->roundPrice($min_price);
							$max_price = $this->filterHelper->roundPrice($max_price);
							
							$fieldset = $xml->addChild('fieldset');
							$fieldset->addAttribute('name', 'price');
							$field = $fieldset->addChild('field');
							$field->addAttribute('name', 'cfp');
							$field->addAttribute('label', 'PLG_SYSTEM_VPFRAMEWORK_PRICE_FILTER');
							$field->addAttribute('type', 'vpcfprice');
							$field->addAttribute('id_prefix', $module_id);
							
							$field->addAttribute('symbol', $activeCurrency->currency_symbol);
							$field->addAttribute('decimal_place', $activeCurrency->currency_decimal_place);
							$field->addAttribute('decimal_symbol', $activeCurrency->currency_decimal_symbol);
							$field->addAttribute('thousands', $activeCurrency->currency_thousands);
							$field->addAttribute('style', $activeCurrency->currency_positive_style);
							$field->addAttribute('show_clear', $this->modParams->get('show_price_filter_clear', 1));
							$field->addAttribute('clear_url', $this->getUrl('cfp', null, 'clear'));
							
							$option = $field->addChild('option', $min_price);
							$option->addAttribute('value', '0');
							$option->addAttribute('url', $this->getUrl('cfp', '0', $min_price));
							
							$option = $field->addChild('option', $max_price);
							$option->addAttribute('value', '1');
							$option->addAttribute('url', $this->getUrl('cfp', '1', $max_price));
							
							$nofollow = (int) $this->modParams->get('nofollow_noindex', 1);
							$field->addAttribute('nofollow', $nofollow);
						}
					}
					
					break;
			}
		}

		jimport( 'joomla.form.form' );
		
		JForm::addFieldPath(JPATH_SITE . '/modules/mod_vp_custom_filter/fields');

		$form = JForm::getInstance('vpcf.module.filters.' . $module_id, $xml->asXML(), array('control' => ''));
		
		$data = new stdClass;
		
		$data->cfm = !empty($this->filter_input['cfm']) ? (array) $this->filter_input['cfm'] : array();
		$data->cfp = !empty($this->filter_input['cfp']) ? (array) $this->filter_input['cfp'] : array();
		
		$cffs = !empty($this->filter_input['cff']) ? (array) $this->filter_input['cff'] : array();
		
		foreach($cffs as $custom_id => $values)
		{
			if(is_array($values))
			{
				foreach($values as $value)
				{
					$key = 'cff_' . $custom_id;
					
					if(!isset($data->$key))
					{
						$data->$key = array();
					}
					
					$temp = $data->$key;
					$temp[] = bin2hex($value);
					$data->$key = $temp;
				}
			}
		}

		$form->bind($data);
		
		return $form;
	}
	
	protected function getUrl($name, $key, $value, $multiSelect = true)
	{
		$uri   = clone($this->getActionUrl(true));
		$vars  = $this->input->get($name, array(), 'ARRAY');
		$value = (string) $value;
		
		if($name == 'cfm')
		{
			$virtuemart_manufacturer_id = $this->input->get('virtuemart_manufacturer_id', array(), 'ARRAY');
			
			if(!empty($virtuemart_manufacturer_id))
			{
				$vars = array_merge($vars, $virtuemart_manufacturer_id);
				$vars = array_unique($vars);
			}
		}
		
		if(strtolower($value) == 'clear')
		{
			$value = '0';
			$vars = array();
		}
		elseif(!$multiSelect)
		{
			$vars = array();
		}
		
		if(!empty($vars))
		{
			foreach($vars as &$var)
			{
				$var = $this->filterHelper->clean($var);
			}
			
			$emptyKey = array_search('0', $vars);
			
			if($emptyKey  !== false)
			{
				unset($vars[$emptyKey]);
			}
			
			if($key === null)
			{
				if(!in_array($value, $vars))
				{
					$vars[] = $value;
				}
				else
				{
					$oldKey = array_search($value, $vars);
					
					if($oldKey !== false)
					{
						unset($vars[$oldKey]);
						
						if(empty($vars))
						{
							$vars[$oldKey] = '0';
						}
					}
				}
			}
			else
			{
				$vars[$key] = $value;
			}
		}
		else
		{
			if($key === null)
			{
				$vars = array($value);
			}
			else
			{
				$vars = array($key => $value);
			}
		}
		
		$uri->setVar($name, $vars);
		$url = $uri->toString();
		
		// RFC 3986 encoding of square brackets
		$url = str_replace(array('[', ']'), array('%5B', '%5D'), $url);
		
		return $url;
	}
	
	protected function getPriceRange()
	{
		$user        = JFactory::getUser();
		$currency    = $this->filterHelper->getVendorCurrency();
		$currency_id = $this->input->get('virtuemart_currency_id', $currency['vendor_currency'], 'int');
		$currency_id = $this->app->getUserStateFromRequest('virtuemart_currency_id', 'virtuemart_currency_id', $currency_id);
		$key         = 'priceRange.params:' . $this->modParams->toString() . '.currency_id:' . $currency_id .
		               '.user_id:' . $user->get('id') . '.category_id:' . $this->category_id . '.manufacturer_id:' . @implode('|', $this->manufacturer_ids) .
		               '.filter_input:' . serialize($this->filter_input) . '.keyword:' . $this->keyword;
		$cache       = JFactory::getCache('mod_vp_custom_filter', '');
		$caching     = $this->modParams->get('vpcache', null);
		$lifetime    = (int) $this->modParams->get('vpcache_time', 900);
		
		if($caching !== null)
		{
			$cache->setCaching($caching);
			$cache->setLifeTime($lifetime);
		}
		
		// Try from cache
		$range = $cache->get($key);
		
		if($range === false)
		{
			// Reload range by database query
			$range = $this->_getPriceRange();
			$cache->store($range, $key);
		}
		
		return $range;
	}
	
	protected function getComplexPriceRange()
	{
		$priceRange            = new stdClass;
		$priceRange->min_price = null;
		$priceRange->max_price = null;
		$prices                = $this->filterHelper->getAllProductPrices();

		if(!empty($prices))
		{
			$displayPriceType = $this->modParams->get('displayed_price_type', 'salesPrice');
			
			$validPrices = array_filter($prices, function($price) use ($displayPriceType)
			{
				return !empty($price['salesPrice']) && ($displayPriceType == 'salesPrice' || isset($price[$displayPriceType]));
			});
			
			if(!empty($validPrices))
			{
				if($this->modParams->get('multi_currrency_product', 0))
				{
					$productCurrencies = $this->filterHelper->getProductCurrencies();
					
					if(!empty($productCurrencies))
					{
						$vendorCurrency = $this->filterHelper->getVendorCurrency();
						$currencyHelper = CurrencyDisplay::getInstance($vendorCurrency['vendor_currency']);
						
						foreach($validPrices as &$validPrice)
						{
							if($validPrice['product_currency'] != $vendorCurrency['vendor_currency'])
							{
								$validPrice[$displayPriceType] = $currencyHelper->convertCurrencyTo($validPrice['product_currency'], $validPrice[$displayPriceType], true);
							}
						}
					}
				}
				
				$priceRange->min_price = min(array_column($validPrices, $displayPriceType));
				$priceRange->max_price = max(array_column($validPrices, $displayPriceType));
			}
		}
		
		return $priceRange;
	}
	
	protected function _getPriceRange()
	{
		if(!isset($this->cache['priceRange']))
		{
			$vendorCurrency     = $this->filterHelper->getVendorCurrency();
			$currencyHelper     = CurrencyDisplay::getInstance($vendorCurrency['vendor_currency']);
			$langFback          = (!VmConfig::get('prodOnlyWLang', false) && VmConfig::$defaultLang != VmConfig::$vmlang && VmConfig::$langCount > 1);
			$productCurrencies  = array();
			$min_price          = 0;
			$max_price          = 0;
			$min_override_price = null;
			$max_override_price = null;
			
			if($this->modParams->get('multi_currrency_product', 0))
			{
				$productCurrencies = $this->filterHelper->getProductCurrencies();
			}
			
			$db    = $this->db;
			$query = $db->getQuery(true);
			
			$query->select('MAX(CASE WHEN (pp.`override` IS NULL OR pp.`override` = 0) THEN pp.`product_price` ELSE null END) AS max_price')
			      ->select('MIN(CASE WHEN (pp.`override` IS NULL OR pp.`override` = 0) THEN pp.`product_price` ELSE null END) AS min_price');

			$query->select('MAX(CASE WHEN pp.`override` = 1 THEN pp.`product_override_price` ELSE null END) AS max_override_price')
			      ->select('MIN(CASE WHEN pp.`override` = 1 THEN pp.`product_override_price` ELSE null END) AS min_override_price');
			
			$query->from('`#__virtuemart_product_prices` AS pp')
			      ->join('LEFT', '`#__virtuemart_products` AS p ON pp.`virtuemart_product_id` = p.`virtuemart_product_id`');

			if($langFback && VmConfig::$defaultLang != VmConfig::$jDefLang)
			{
				$query->join('INNER', '`#__virtuemart_products_' . VmConfig::$jDefLang . '` as pl ON pp.`virtuemart_product_id` = pl.`virtuemart_product_id`');
			}
			elseif(VmConfig::get('prodOnlyWLang', false))
			{
				$query->join('INNER', '`#__virtuemart_products_' . VmConfig::$vmlang . '` as pl ON pp.`virtuemart_product_id` = pl.`virtuemart_product_id`');
			}
			
			$query->join('LEFT', '`#__virtuemart_product_categories` AS pc ON pp.`virtuemart_product_id` = pc.`virtuemart_product_id`');
			
			if($this->category_id > 0)
			{
				if(VmConfig::get('show_subcat_products', false))
				{
					$categoryModel   = VmModel::getModel('category');
					$childCategories = $categoryModel->getChildCategoryList(1, $this->category_id, null, null, true);
					
					if(!empty($childCategories))
					{
						$categories      = array();
						$categories[]    = $this->category_id;
						
						foreach($childCategories as $childCategory)
						{
							$categories[] = $childCategory->virtuemart_category_id;
						}
						
						$query->where('pc.`virtuemart_category_id` IN (' . implode(',', $categories) . ')');
					}
					else
					{
						$query->where('pc.`virtuemart_category_id` = ' . $this->category_id);
					}
				}
				else
				{
					$query->where('pc.`virtuemart_category_id` = ' . $this->category_id);
				}
			}
			else
			{
				if(!VmConfig::get('show_uncat_parent_products', true))
				{
					$query->where('((p.`product_parent_id` = 0 AND `pc`.`virtuemart_category_id` > 0) OR p.`product_parent_id` > 0)');
				}
				
				if (!VmConfig::get('show_uncat_child_products', true))
				{
					$query->where('((p.`product_parent_id` > 0 AND `pc`.`virtuemart_category_id` > 0) OR p.`product_parent_id` = 0)');
				}
			}
			
			if(!VmConfig::get('show_unpub_cat_products', true))
			{
				$query->join('LEFT', '`#__virtuemart_categories` AS c ON pc.`virtuemart_category_id` = c.`virtuemart_category_id`');
				$query->where('c.`published` = 1');
			}

			if(!VmConfig::get('use_as_catalog',0))
			{
				if (VmConfig::get('stockhandle','none') == 'disableit_children')
				{
					$childrenInStock = $this->getChildProductsInStock();
					
					if(!empty($childrenInStock))
					{
						$query->where('((p.`product_in_stock` - p.`product_ordered`) > "0" OR p.`virtuemart_product_id` IN (' . implode(',', $childrenInStock) . '))');
					}
					else
					{
						$query->where('p.`product_in_stock` - p.`product_ordered` > "0"');
					}
				}
				elseif (VmConfig::get('stockhandle','none') == 'disableit')
				{
					$query->where('p.`product_in_stock` - p.`product_ordered` > "0"');
				}
			}
			
			$usermodel        = VmModel::getModel('user');
			$currentVMuser    = $usermodel->getCurrentUser();
			$shoppergroup_ids = $currentVMuser->shopper_groups;

			if(is_array($shoppergroup_ids))
			{
				$query->join('LEFT', '`#__virtuemart_product_shoppergroups` as ps ON p.`virtuemart_product_id` = ps.`virtuemart_product_id`');
				
				$sgrgroups = array();
				
				foreach ($shoppergroup_ids as $key => $shoppergroup_id)
				{
					$sgrgroups[] = 'ps.`virtuemart_shoppergroup_id`= "' . (int) $shoppergroup_id . '" ';
				}
				
				$sgrgroups[] = '(ISNULL(ps.`virtuemart_shoppergroup_id`) OR ps.`virtuemart_shoppergroup_id` = "0")';
				
				$query->where('( ' . implode (' OR ', $sgrgroups) . ' )');
				
				// For shopper group based pricing
				$sgrgroups = array();
				
				foreach ($shoppergroup_ids as $key => $shoppergroup_id)
				{
					$sgrgroups[] = 'pp.`virtuemart_shoppergroup_id`= "' . (int) $shoppergroup_id . '" ';
				}
				
				$sgrgroups[] = '(ISNULL(pp.`virtuemart_shoppergroup_id`) OR pp.`virtuemart_shoppergroup_id` = "0")';
				
				$query->where('( ' . implode (' OR ', $sgrgroups) . ' )');
			}
			else
			{
				$query->where('(ISNULL(pp.`virtuemart_shoppergroup_id`) OR pp.`virtuemart_shoppergroup_id` = "0")');
			}
			
			if(!empty($productCurrencies))
			{
				$query->select('pp.`product_currency`')
					->group('pp.`product_currency`')
					->where('pp.`product_currency` IN (' . implode(',', $productCurrencies) . ')');
			}
			
			if($this->filterHelper->isFiltered())
			{
				$valid_product_ids = null;
				
				if(!empty($this->filter_input['cff']) && isset($this->product_ids['byFields']) && is_array($this->product_ids['byFields']))
				{
					$valid_product_ids = $this->product_ids['byFields'];
				}
				
				if(!empty($this->filter_input['cfm']) && isset($this->product_ids['byManufacturers']) && is_array($this->product_ids['byManufacturers']))
				{
					$valid_product_ids = is_array($valid_product_ids) ? array_intersect($valid_product_ids, $this->product_ids['byManufacturers']) : $this->product_ids['byManufacturers'];
				}
				
				$by_keywords = $this->getProductIdsByKeyword();
				
				if(is_array($by_keywords))
				{
					$valid_product_ids = is_array($valid_product_ids) ? array_intersect($valid_product_ids, $by_keywords) : $by_keywords;
				}
				
				// Search only in filtered product ids
				if(is_array($valid_product_ids))
				{
					if(!empty($valid_product_ids))
					{
						$query->where('p.`virtuemart_product_id` IN (' . implode(',', $valid_product_ids) . ')');
					}
					else
					{
						$query->where('p.`virtuemart_product_id` = "-1"');
					}
				}
			}
			else
			{
				$by_keywords = $this->getProductIdsByKeyword();
				
				if(is_array($by_keywords))
				{
					if(!empty($by_keywords))
					{
						$query->where('p.`virtuemart_product_id` IN (' . implode(',', $by_keywords) . ')');
					}
					else
					{
						$query->where('p.`virtuemart_product_id` = "-1"');
					}
				}
			}
			
			$query->where('p.`published` = 1');
			
			$db->setQuery($query);//echo str_replace('#__', 'vjr0w_', $query);exit;
			
			if(!empty($productCurrencies))
			{
				$items = $db->loadObjectList();
				
				if(!empty($items))
				{
					$max_prices          = array();
					$min_prices          = array();
					$max_override_prices = array();
					$min_override_prices = array();
					
					foreach($items as $item)
					{
						if($item->product_currency != $vendorCurrency['vendor_currency'])
						{
							$item->max_price = !is_null($item->max_price) ? $currencyHelper->convertCurrencyTo($item->product_currency, $item->max_price, true) : null;
							$item->min_price = !is_null($item->min_price) ? $currencyHelper->convertCurrencyTo($item->product_currency, $item->min_price, true) : null;
							$item->max_override_price = !is_null($item->max_override_price) ? $currencyHelper->convertCurrencyTo($item->product_currency, $item->max_override_price, true) : null;
							$item->min_override_price = !is_null($item->min_override_price) ? $currencyHelper->convertCurrencyTo($item->product_currency, $item->min_override_price, true) : null;
						}
						
						if(!is_null($item->max_price))
						{
							$max_prices[] = $item->max_price;
						}
						
						if(!is_null($item->min_price))
						{
							$min_prices[] = $item->min_price;
						}
						
						if(!is_null($item->max_override_price))
						{
							$max_override_prices[] = $item->max_override_price;
						}
						
						if(!is_null($item->min_override_price))
						{
							$min_override_prices[] = $item->min_override_price;
						}
					}
					
					$max_price = !empty($max_prices) ? max($max_prices) : null;
					$min_price = !empty($min_prices) ? min($min_prices) : null;
					$max_override_price = !empty($max_override_prices) ? max($max_override_prices) : null;
					$min_override_price = !empty($min_override_prices) ? min($min_override_prices) : null;
				}
			}
			else
			{
				$prices = $db->loadObject();
				
				if(!empty($prices))
				{
					$max_price = !is_null($prices->max_price) ? $prices->max_price : null;
					$min_price = !is_null($prices->min_price) ? $prices->min_price : null;
					$max_override_price = !is_null($prices->max_override_price) ? $prices->max_override_price : null;
					$min_override_price = !is_null($prices->min_override_price) ? $prices->min_override_price : null;
				}
			}
			
			$priceRange = new stdClass;
			$priceRange->min_price = $min_price;
			$priceRange->max_price = $max_price;
			$priceRange->min_override_price = $min_override_price;
			$priceRange->max_override_price = $max_override_price;

			$this->cache['priceRange'] = $priceRange;
		}
		
		return $this->cache['priceRange'];
	}
	
	protected function getManufacturers($get_product_count)
	{
		$user        = JFactory::getUser();
		$currency    = $this->filterHelper->getVendorCurrency();
		$currency_id = $this->input->get('virtuemart_currency_id', $currency['vendor_currency'], 'int');
		$currency_id = $this->app->getUserStateFromRequest('virtuemart_currency_id', 'virtuemart_currency_id', $currency_id);
		$key         = 'manufacturers.params:' . $this->modParams->toString() . '.currency_id:' . $currency_id .
		               '.user_id:' . $user->get('id') . '.category_id:' . $this->category_id . '.manufacturer_id:' . @implode('|', $this->manufacturer_ids) .
		               '.filter_input:' . serialize($this->filter_input) . '.get_product_count:' . $get_product_count . '.keyword:' . $this->keyword;
		$cache       = JFactory::getCache('mod_vp_custom_filter', '');
		$caching     = $this->modParams->get('vpcache', null);
		$lifetime    = (int) $this->modParams->get('vpcache_time', 900);
		
		if($caching !== null)
		{
			$cache->setCaching($caching);
			$cache->setLifeTime($lifetime);
		}
		
		// Try from cache
		$manufacturers = $cache->get($key);
		
		if($manufacturers === false)
		{
			// Reload range by database query
			$manufacturers = $this->_getManufacturers($get_product_count);
			$cache->store($manufacturers, $key);
		}
		
		return $manufacturers;
	}
	
	protected function _getManufacturers($get_product_count)
	{
		if(!isset($this->cache['manufacturers']))
		{
			$db                = $this->db;
			$query             = $db->getQuery(true);
			$langFback         = (!VmConfig::get('prodOnlyWLang', false) && VmConfig::$defaultLang != VmConfig::$vmlang && VmConfig::$langCount > 1);
			$valid_product_ids = null;
			$joinInactiveTable = false;
			
			if(!empty($this->filter_input['cfp']) && isset($this->product_ids['byPrice']) && is_array($this->product_ids['byPrice']))
			{
				$valid_product_ids = $this->product_ids['byPrice'];
			}
			
			if(!empty($this->filter_input['cff']) && isset($this->product_ids['byFields']) && is_array($this->product_ids['byFields']))
			{
				$valid_product_ids = is_array($valid_product_ids) ? array_intersect($valid_product_ids, $this->product_ids['byFields']) : $this->product_ids['byFields'];
			}
			
			$by_keywords = $this->getProductIdsByKeyword();
	
			if(is_array($by_keywords))
			{
				$valid_product_ids = is_array($valid_product_ids) ? array_intersect($valid_product_ids, $by_keywords) : $by_keywords;
			}
			
			$valid_product_ids = !empty($valid_product_ids) ? array_values(array_unique($valid_product_ids)) : $valid_product_ids;
			
			$query->select('m.`virtuemart_manufacturer_id`, ml.`mf_name`');
			
			if($get_product_count)
			{
				$query->select('COUNT(DISTINCT p.`virtuemart_product_id`) AS product_count');
				//$query->select('GROUP_CONCAT(DISTINCT p.`virtuemart_product_id` SEPARATOR \',\') AS virtuemart_product_ids');
				
				if(empty($valid_product_ids) && is_array($valid_product_ids))
				{
					$query->select('COUNT(DISTINCT p.`virtuemart_product_id`) AS inactive_product_count');
				}
				elseif(!empty($valid_product_ids))
				{
					$query->select('COUNT(DISTINCT inactivep.`virtuemart_product_id`) AS inactive_product_count');
					
					$joinInactiveTable = true;
				}
				else
				{
					$query->select('"0" AS inactive_product_count');
				}
			}
			
			$query->from('`#__virtuemart_manufacturers` AS m')
				->join('INNER', '`#__virtuemart_manufacturers_' . VmConfig::$vmlang . '` AS ml ON m.`virtuemart_manufacturer_id` = ml.`virtuemart_manufacturer_id`')
				->join('INNER', '`#__virtuemart_product_manufacturers` AS pm ON m.`virtuemart_manufacturer_id` = pm.`virtuemart_manufacturer_id`');

			if($this->filterHelper->shopHasChildProducts())
			{
				$subQueryChild = $db->getQuery(true);
				$subQueryChild->select('subpchildm.`virtuemart_product_id` AS child_product_id')
					->from('`#__virtuemart_product_manufacturers` AS subpchildm')
					->join('LEFT', '`#__virtuemart_products` AS pchild ON subpchildm.`virtuemart_product_id` = pchild.`virtuemart_product_id`')
					->where('subpchildm.`virtuemart_manufacturer_id` > 0')
					->where('pchild.`product_parent_id` > 0')
					->where('pchild.`published` = 1');
				
				$query->join('LEFT', '`#__virtuemart_products` AS p ON pm.`virtuemart_product_id` = p.`virtuemart_product_id` OR (p.`product_parent_id` > 0 AND pm.`virtuemart_product_id` = p.`product_parent_id` AND p.`virtuemart_product_id` NOT IN (' . $subQueryChild . '))');
			}
			else
			{
				$query->join('LEFT', '`#__virtuemart_products` AS p ON pm.`virtuemart_product_id` = p.`virtuemart_product_id`');
			}
			
			// Join product table to find inactive product count
			if($joinInactiveTable)
			{
				if(!empty($valid_product_ids) && is_array($valid_product_ids))
				{
					if(count($valid_product_ids) > 1)
					{
						$query->join('LEFT', '`#__virtuemart_products` AS inactivep ON p.`virtuemart_product_id` = inactivep.`virtuemart_product_id` AND inactivep.`virtuemart_product_id` NOT IN (' . implode(',', $valid_product_ids) . ')');
					}
					else
					{
						$query->join('LEFT', '`#__virtuemart_products` AS inactivep ON p.`virtuemart_product_id` = inactivep.`virtuemart_product_id` AND inactivep.`virtuemart_product_id` <> '.  $valid_product_ids[0]);
					}
				}
				else
				{
					$query->join('LEFT', '`#__virtuemart_products` AS inactivep ON p.`virtuemart_product_id` = inactivep.`virtuemart_product_id`');
				}
			}
			
			if($langFback && VmConfig::$defaultLang != VmConfig::$jDefLang)
			{
				$query->join('INNER', '`#__virtuemart_products_' . VmConfig::$jDefLang . '` as pl ON pm.`virtuemart_product_id` = pl.`virtuemart_product_id`');
			}
			elseif(VmConfig::get('prodOnlyWLang', false))
			{
				$query->join('INNER', '`#__virtuemart_products_' . VmConfig::$vmlang . '` as pl ON pm.`virtuemart_product_id` = pl.`virtuemart_product_id`');
			}
			
			$query->join('LEFT', '`#__virtuemart_product_categories` AS pc ON p.`virtuemart_product_id` = pc.`virtuemart_product_id`');
			
			if($this->category_id > 0)
			{
				if(VmConfig::get('show_subcat_products', false))
				{
					$categoryModel   = VmModel::getModel('category');
					$childCategories = $categoryModel->getChildCategoryList(1, $this->category_id, null, null, true);
					
					if(!empty($childCategories))
					{
						$categories   = array();
						$categories[] = $this->category_id;
						
						foreach($childCategories as $childCategory)
						{
							$categories[] = $childCategory->virtuemart_category_id;
						}
						
						$query->where('pc.`virtuemart_category_id` IN (' . implode(',', $categories) . ')');
					}
					else
					{
						$query->where('pc.`virtuemart_category_id` = ' . $this->category_id);
					}
				}
				else
				{
					$query->where('pc.`virtuemart_category_id` = ' . $this->category_id);
				}
			}
			else
			{
				if(!VmConfig::get('show_uncat_parent_products', true))
				{
					$query->where('((p.`product_parent_id` = 0 AND `pc`.`virtuemart_category_id` > 0) OR p.`product_parent_id` > 0)');
				}
				
				if (!VmConfig::get('show_uncat_child_products', true))
				{
					$query->where('((p.`product_parent_id` > 0 AND `pc`.`virtuemart_category_id` > 0) OR p.`product_parent_id` = 0)');
				}
			}
			
			if(!VmConfig::get('show_unpub_cat_products', true))
			{
				$query->join('LEFT', '`#__virtuemart_categories` AS c ON pc.`virtuemart_category_id` = c.`virtuemart_category_id`');
				$query->where('c.`published` = 1');
			}

			if(!VmConfig::get('use_as_catalog',0))
			{
				if (VmConfig::get('stockhandle','none') == 'disableit_children')
				{
					$childrenInStock = $this->getChildProductsInStock();
					
					if(!empty($childrenInStock))
					{
						$query->where('((p.`product_in_stock` - p.`product_ordered`) > "0" OR p.`virtuemart_product_id` IN (' . implode(',', $childrenInStock) . '))');
					}
					else
					{
						$query->where('p.`product_in_stock` - p.`product_ordered` > "0"');
					}
				}
				elseif (VmConfig::get('stockhandle','none')=='disableit')
				{
					$query->where('p.`product_in_stock` - p.`product_ordered` >"0"');
				}
			}
			
			$usermodel        = VmModel::getModel ('user');
			$currentVMuser    = $usermodel->getCurrentUser();
			$shoppergroup_ids = (array) $currentVMuser->shopper_groups;

			if(is_array($shoppergroup_ids))
			{
				$query->join('LEFT', '`#__virtuemart_product_shoppergroups` as ps ON pm.`virtuemart_product_id` = ps.`virtuemart_product_id`');
				
				$sgrgroups = array();
				
				foreach ($shoppergroup_ids as $key => $shoppergroup_id)
				{
					$sgrgroups[] = '`ps`.`virtuemart_shoppergroup_id`= "' . (int) $shoppergroup_id . '" ';
				}
				
				$sgrgroups[] = '`ps`.`virtuemart_shoppergroup_id` IS NULL ';
				
				$query->where('( ' . implode (' OR ', $sgrgroups) . ' )');
			}
			
			$query->where('(ml.`mf_name` IS NOT NULL AND ml.`mf_name` != "")');
			$query->where('p.`published` = 1');
			$query->group('m.`virtuemart_manufacturer_id`');
			$query->order('ml.`mf_name` ASC');
			
			$db->setQuery($query);//echo str_replace('#__', 'vkp0j_', $query);exit;
			$this->cache['manufacturers'] = $db->loadObjectList();
		}
		
		return $this->cache['manufacturers'];
	}
	
	protected function getCustomFieldOption($customField, $get_product_count)
	{
		$user        = JFactory::getUser();
		$currency    = $this->filterHelper->getVendorCurrency();
		$currency_id = $this->input->get('virtuemart_currency_id', $currency['vendor_currency'], 'int');
		$currency_id = $this->app->getUserStateFromRequest('virtuemart_currency_id', 'virtuemart_currency_id', $currency_id);
		$key         = 'customFieldOptions.params:' . $this->modParams->toString() . '.currency_id:' . $currency_id .
		               '.user_id:' . $user->get('id') . '.category_id:' . $this->category_id . '.manufacturer_id:' . @implode('|', $this->manufacturer_ids) .
		               '.filter_input:' . serialize($this->filter_input) . '.get_product_count:' . $get_product_count . '.custom_field:' . serialize($customField) .
		               '.keyword:' . $this->keyword;
		$cache       = JFactory::getCache('mod_vp_custom_filter', '');
		$caching     = $this->modParams->get('vpcache', null);
		$lifetime    = (int) $this->modParams->get('vpcache_time', 900);
		
		if($caching !== null)
		{
			$cache->setCaching($caching);
			$cache->setLifeTime($lifetime);
		}
		
		// Try from cache
		$customFieldOption = $cache->get($key);

		if($customFieldOption === false)
		{
			// Reload range by database query
			$customFieldOption = $this->_getCustomFieldOption($customField, $get_product_count);
			$cache->store($customFieldOption, $key);
		}
		
		return $customFieldOption;
	}
	
	protected function _getCustomFieldOption($customField, $get_product_count)
	{
		if(!isset($this->cache['fieldOptions']))
		{
			$this->cache['fieldOptions'] = array();
		}
		
		$custom_id = $customField->custom_id;
		
		if(!isset($this->cache['fieldOptions'][$custom_id]))
		{
			$db                = $this->db;
			$query             = $db->getQuery(true);
			$langFback         = (!VmConfig::get('prodOnlyWLang', false) && VmConfig::$defaultLang != VmConfig::$vmlang && VmConfig::$langCount > 1);
			$valid_product_ids = null;
			$joinInactiveTable = false;
			
			if(!empty($this->filter_input['cfp']) && isset($this->product_ids['byPrice']) && is_array($this->product_ids['byPrice']))
			{
				$valid_product_ids = $this->product_ids['byPrice'];
			}
			
			$cffs = $this->filter_input['cff'];
			
			unset($cffs[$custom_id]);
			
			if(!empty($cffs) && isset($this->product_ids['byFieldsGroups']) && is_array($this->product_ids['byFieldsGroups']))
			{
				$valid_product_ids_of_others = null;
				
				foreach($cffs as $key => $values)
				{
					if(!isset($this->product_ids['byFieldsGroups'][$key]))
					{
						//$valid_product_ids_of_others = array();
						break;
					}
					else
					{
						//$valid_product_ids_of_others = array_merge($valid_product_ids_of_others, $this->product_ids['byFieldsGroups'][$key]);
						$valid_product_ids_of_others = is_array($valid_product_ids_of_others) ? array_intersect($valid_product_ids_of_others, $this->product_ids['byFieldsGroups'][$key]) : $this->product_ids['byFieldsGroups'][$key];
					}
				}
			
				$valid_product_ids_of_others = !empty($valid_product_ids_of_others) && is_array($valid_product_ids_of_others) ? array_unique($valid_product_ids_of_others) : array();
				
				$valid_product_ids = is_array($valid_product_ids) ? array_intersect($valid_product_ids, $valid_product_ids_of_others) : $valid_product_ids_of_others;
			}

			if(!empty($this->filter_input['cfm']) && isset($this->product_ids['byManufacturers']) && is_array($this->product_ids['byManufacturers']))
			{
				$valid_product_ids = is_array($valid_product_ids) ? array_intersect($valid_product_ids, $this->product_ids['byManufacturers']) : $this->product_ids['byManufacturers'];
			}

			$by_keywords = $this->getProductIdsByKeyword();

			if(is_array($by_keywords))
			{
				$valid_product_ids = is_array($valid_product_ids) ? array_intersect($valid_product_ids, $by_keywords) : $by_keywords;
			}

			$valid_product_ids = !empty($valid_product_ids) ? array_values(array_unique($valid_product_ids)) : $valid_product_ids;

			if($get_product_count)
			{
				$query->select('cfv.`customfield_value`');
				
				$query->select('COUNT(DISTINCT p.`virtuemart_product_id`) AS product_count');
				//$query->select('GROUP_CONCAT(DISTINCT p.`virtuemart_product_id` SEPARATOR \',\') AS virtuemart_product_ids');
				
				if(empty($valid_product_ids) && is_array($valid_product_ids))
				{
					$query->select('COUNT(DISTINCT p.`virtuemart_product_id`) AS inactive_product_count');
				}
				elseif(!empty($valid_product_ids))
				{
					$query->select('COUNT(DISTINCT inactivep.`virtuemart_product_id`) AS inactive_product_count');
					
					$joinInactiveTable = true;
				}
				else
				{
					$query->select('"0" AS inactive_product_count');
				}
			}
			else
			{
				$query->select('DISTINCT(cfv.`customfield_value`)');
			}
			
			$query->from('`#__virtuemart_product_customfields` AS cfv');
			
			if($this->filterHelper->shopHasChildProducts())
			{
				$query->join('LEFT', '`#__virtuemart_products` AS p ON cfv.`virtuemart_product_id` = p.`virtuemart_product_id` OR cfv.`virtuemart_product_id` = p.`product_parent_id`');
				
				if($this->filterHelper->shopHasCustomFieldOverride())
				{
					$query->join('LEFT', '`#__virtuemart_product_customfields` AS pcvo ON cfv.`virtuemart_customfield_id` = pcvo.`override` AND p.`virtuemart_product_id` = pcvo.`virtuemart_product_id` AND pcvo.`override` > 0');
					$query->where('pcvo.`virtuemart_customfield_id` IS NULL');
				}
				
				if($this->filterHelper->shopHasCustomFieldDisabler())
				{
					$query->join('LEFT', '`#__virtuemart_product_customfields` AS pcvd ON cfv.`virtuemart_customfield_id` = pcvd.`disabler` AND p.`virtuemart_product_id` = pcvd.`virtuemart_product_id` AND pcvd.`disabler` > 0');
					$query->where('pcvd.`virtuemart_customfield_id` IS NULL');
				}
			}
			else
			{
				$query->join('LEFT', '`#__virtuemart_products` AS p ON cfv.`virtuemart_product_id` = p.`virtuemart_product_id`');
			}
			
			// Join product table to find inactive product count
			if($joinInactiveTable)
			{
				if(!empty($valid_product_ids) && is_array($valid_product_ids))
				{
					if(count($valid_product_ids) > 1)
					{
						$query->join('LEFT', '`#__virtuemart_products` AS inactivep ON p.`virtuemart_product_id` = inactivep.`virtuemart_product_id` AND inactivep.`virtuemart_product_id` NOT IN (' . implode(',', $valid_product_ids) . ')');
					}
					else
					{
						$query->join('LEFT', '`#__virtuemart_products` AS inactivep ON p.`virtuemart_product_id` = inactivep.`virtuemart_product_id` AND inactivep.`virtuemart_product_id` <> '.  $valid_product_ids[0]);
					}
				}
				else
				{
					$query->join('LEFT', '`#__virtuemart_products` AS inactivep ON p.`virtuemart_product_id` = inactivep.`virtuemart_product_id`');
				}
			}
			
			if($langFback && VmConfig::$defaultLang != VmConfig::$jDefLang)
			{
				$query->join('INNER', '`#__virtuemart_products_' . VmConfig::$jDefLang . '` as pl ON cfv.`virtuemart_product_id` = pl.`virtuemart_product_id`');
			}
			elseif(VmConfig::get('prodOnlyWLang', false))
			{
				$query->join('INNER', '`#__virtuemart_products_' . VmConfig::$vmlang . '` as pl ON cfv.`virtuemart_product_id` = pl.`virtuemart_product_id`');
			}
			
			$query->join('LEFT', '`#__virtuemart_product_categories` AS pc ON p.`virtuemart_product_id` = pc.`virtuemart_product_id`');
			
			if($this->category_id > 0)
			{
				if(VmConfig::get('show_subcat_products', false))
				{
					$categoryModel   = VmModel::getModel('category');
					$childCategories = $categoryModel->getChildCategoryList(1, $this->category_id, null, null, true);
					
					if(!empty($childCategories))
					{
						$categories      = array();
						$categories[]    = $this->category_id;
						
						foreach($childCategories as $childCategory)
						{
							$categories[] = $childCategory->virtuemart_category_id;
						}
						
						$query->where('pc.`virtuemart_category_id` IN (' . implode(',', $categories) . ')');
					}
					else
					{
						$query->where('pc.`virtuemart_category_id` = ' . $this->category_id);
					}
				}
				else
				{
					$query->where('pc.`virtuemart_category_id` = ' . $this->category_id);
				}
			}
			else
			{
				if(!VmConfig::get('show_uncat_parent_products', true))
				{
					$query->where('((p.`product_parent_id` = 0 AND `pc`.`virtuemart_category_id` > 0) OR p.`product_parent_id` > 0)');
				}
				
				if (!VmConfig::get('show_uncat_child_products', true))
				{
					$query->where('((p.`product_parent_id` > 0 AND `pc`.`virtuemart_category_id` > 0) OR p.`product_parent_id` = 0)');
				}
			}
			
			if(!VmConfig::get('show_unpub_cat_products', true))
			{
				$query->join('LEFT', '`#__virtuemart_categories` AS c ON pc.`virtuemart_category_id` = c.`virtuemart_category_id`');
				$query->where('c.`published` = 1');
			}

			if(!VmConfig::get('use_as_catalog',0))
			{
				if (VmConfig::get('stockhandle','none') == 'disableit_children')
				{
					$childrenInStock = $this->getChildProductsInStock();
					
					if(!empty($childrenInStock))
					{
						$query->where('((p.`product_in_stock` - p.`product_ordered`) > "0" OR p.`virtuemart_product_id` IN (' . implode(',', $childrenInStock) . '))');
					}
					else
					{
						$query->where('p.`product_in_stock` - p.`product_ordered` > "0"');
					}
				}
				elseif (VmConfig::get('stockhandle','none')=='disableit')
				{
					$query->where('p.`product_in_stock` - p.`product_ordered` > "0"');
				}
			}
			
			$usermodel        = VmModel::getModel ('user');
			$currentVMuser    = $usermodel->getCurrentUser();
			$shoppergroup_ids = (array) $currentVMuser->shopper_groups;

			if(is_array($shoppergroup_ids))
			{
				$query->join('LEFT', '`#__virtuemart_product_shoppergroups` as ps ON cfv.`virtuemart_product_id` = ps.`virtuemart_product_id`');
				
				$sgrgroups = array();
				
				foreach ($shoppergroup_ids as $key => $shoppergroup_id)
				{
					$sgrgroups[] = '`ps`.`virtuemart_shoppergroup_id`= "' . (int) $shoppergroup_id . '" ';
				}
				
				$sgrgroups[] = '`ps`.`virtuemart_shoppergroup_id` IS NULL ';
				
				$query->where('( ' . implode (' OR ', $sgrgroups) . ' )');
			}
			
			$query->where('(cfv.`customfield_value` IS NOT NULL AND cfv.`customfield_value` != "")');
			$query->where('p.`published` = 1');
			$query->where('cfv.`virtuemart_custom_id` = ' . (int) $custom_id);
			$query->where('cfv.`disabler` = 0');
			$query->group('cfv.`customfield_value`');
			
			$direction = !empty($customField->ordering_dir) && $customField->ordering_dir == 'desc' ? 'DESC' : 'ASC';
			
			if($customField->ordering == 'numerical')
			{
				$query->order('CAST(cfv.`customfield_value` as unsigned) ' . $direction);
			}
			elseif($customField->ordering == 'alphabetical')
			{
				$query->order('cfv.`customfield_value` ' . $direction);
			}
			else
			{
				$query->order('cfv.`ordering` ASC, cfv.`virtuemart_customfield_id` ' . $direction);
			}
			
			$db->setQuery($query);//echo str_replace('#__', 'vkp0j_', $query);exit;
			$this->cache['fieldOptions'][$custom_id] = $db->loadObjectList();
		}

		return $this->cache['fieldOptions'][$custom_id];
	}
	
	protected function getChildProductsInStock()
	{
		if(!isset($this->cache['childProductsInStock']))
		{
			$this->cache['childProductsInStock'] = array();
		}
		
		if(!isset($this->cache['childProductsInStock'][$this->category_id]))
		{
			$db    = JFactory::getDbo();
			$query = $db->getQuery(true);
			
			$query->select('p.`virtuemart_product_id`')
				->from('`#__virtuemart_products` AS p')
				->join('LEFT', '`#__virtuemart_products` AS children ON p.`product_parent_id` = children.`product_parent_id`')
				->where('(children.`product_in_stock` - children.`product_ordered`) > "0"')
				->group('p.`virtuemart_product_id`');

			if($this->category_id > 0)
			{
				$query->join('LEFT', '`#__virtuemart_product_categories` AS pc ON p.`virtuemart_product_id` = pc.`virtuemart_product_id`');
				$query->where('pc.`virtuemart_category_id` = ' . $this->category_id);
			}
			
			$db->setQuery($query);
			$this->cache['childProductsInStock'][$this->category_id] = $db->loadColumn();
		}
		
		return $this->cache['childProductsInStock'][$this->category_id];
	}
	
	protected function getProductIdsByKeyword()
	{
		$keyword = $this->input->get('keyword', '', 'STRING');
		$keyword = ($keyword === '') ? $this->input->get('filter_product', '', 'STRING') : $keyword;
		
		if($keyword === '')
		{
			return false;
		}
		
		if(!isset($this->product_ids['byKeyword']))
		{
			$db    = $this->db;
			$query = $db->getQuery(true);
			
			$category_joined     = false;
			$manufacturer_joined = false;
			$valid_search_fields = VmConfig::get('browse_search_fields', array());
			$langFback           = (!VmConfig::get('prodOnlyWLang', false) && VmConfig::$defaultLang != VmConfig::$vmlang && VmConfig::$langCount > 1);
			$keyword             = vRequest::filter(html_entity_decode($keyword, ENT_QUOTES, "UTF-8"), FILTER_SANITIZE_STRING, FILTER_FLAG_ENCODE_LOW);
			$keyword             =  '"%' .str_replace(array(' ', '-'), '%', $keyword). '%"';
			
			$query->select('p.`virtuemart_product_id`')
				->from('`#__virtuemart_products` AS p');
			
			if($langFback)
			{
				if(VmConfig::$defaultLang != VmConfig::$jDefLang)
				{
					$query->join('INNER', '`#__virtuemart_products_' . VmConfig::$jDefLang . '` as ljd USING (`virtuemart_product_id`)')
						->join('LEFT', '`#__virtuemart_products_' . VmConfig::$defaultLang . '` as ld USING (`virtuemart_product_id`)');
				}
				else
				{
					$query->join('LEFT', '`#__virtuemart_products_' . VmConfig::$defaultLang . '` as ld USING (`virtuemart_product_id`)');
				}
				
				$query->join('LEFT', '`#__virtuemart_products_' . VmConfig::$vmlang . '` as l USING (`virtuemart_product_id`)');
			}
			else
			{
				$query->join('INNER', '`#__virtuemart_products_' . VmConfig::$vmlang . '` as l USING (`virtuemart_product_id`)');
			}
			
			$query->join('LEFT', '`#__virtuemart_product_categories` AS pc ON p.`virtuemart_product_id` = pc.`virtuemart_product_id`');
				
			if($this->category_id > 0)
			{
				if(VmConfig::get('show_subcat_products', false))
				{
					$categoryModel   = VmModel::getModel('category');
					$childCategories = $categoryModel->getChildCategoryList(1, $this->category_id, null, null, true);
					
					if(!empty($childCategories))
					{
						$categories      = array();
						$categories[]    = $this->category_id;
						
						foreach($childCategories as $childCategory)
						{
							$categories[] = $childCategory->virtuemart_category_id;
						}
						
						$query->where('pc.`virtuemart_category_id` IN (' . implode(',', $categories) . ')');
					}
					else
					{
						$query->where('pc.`virtuemart_category_id` = ' . $this->category_id);
					}
				}
				else
				{
					$query->where('pc.`virtuemart_category_id` = ' . $this->category_id);
				}
			}
			else
			{
				if(!VmConfig::get('show_uncat_parent_products', true))
				{
					$query->where('((p.`product_parent_id` = 0 AND `pc`.`virtuemart_category_id` > 0) OR p.`product_parent_id` > 0)');
				}
				
				if (!VmConfig::get('show_uncat_child_products', true))
				{
					$query->where('((p.`product_parent_id` > 0 AND `pc`.`virtuemart_category_id` > 0) OR p.`product_parent_id` = 0)');
				}
			}
				
			if(!VmConfig::get('show_unpub_cat_products', true))
			{
				$query->join('LEFT', '`#__virtuemart_categories` AS c ON pc.`virtuemart_category_id` = c.`virtuemart_category_id`');
				$query->where('c.`published` = 1');
			}
				
			if(!VmConfig::get('use_as_catalog', 0))
			{
				if (VmConfig::get('stockhandle','none') == 'disableit_children')
				{
					$query->join('LEFT OUTER', '`#__virtuemart_products` children ON p.`virtuemart_product_id` = children.`product_parent_id`');
					$query->where('((p.`product_in_stock` - p.`product_ordered`) >"0" OR (children.`product_in_stock` - children.`product_ordered`) > "0")');
				}
				elseif (VmConfig::get('stockhandle','none')=='disableit')
				{
					$query->where('p.`product_in_stock` - p.`product_ordered` >"0"');
				}
			}
			
			$usermodel = VmModel::getModel ('user');
			$currentVMuser = $usermodel->getCurrentUser();
			$shoppergroup_ids = (array) $currentVMuser->shopper_groups;
			
			if(is_array($shoppergroup_ids))
			{
				$query->join('LEFT', '`#__virtuemart_product_shoppergroups` as ps ON p.`virtuemart_product_id` = ps.`virtuemart_product_id`');
				
				$sgrgroups = array();
				
				foreach ($shoppergroup_ids as $key => $shoppergroup_id)
				{
					$sgrgroups[] = '`ps`.`virtuemart_shoppergroup_id`= "' . (int) $shoppergroup_id . '" ';
				}
				
				$sgrgroups[] = '`ps`.`virtuemart_shoppergroup_id` IS NULL ';
				
				$query->where('( ' . implode (' OR ', $sgrgroups) . ' )');
			}
			
			$filter_search = array();
			$joinCatLang   = false;
			$joinMfLang    = false;
			$joinPrice     = false;
			
			foreach($valid_search_fields as $searchField)
			{
				if(($searchField == 'category_name' || $searchField == 'category_description'))
				{
					$joinCatLang = true;
				}
				elseif($searchField == 'mf_name')
				{
					$joinMfLang = true;
				}
				elseif($searchField == 'product_price')
				{
					$joinPrice = true;
				}
				elseif($searchField == 'product_name' || $searchField == 'product_s_desc' || $searchField == 'product_desc' || $searchField == 'slug')
				{
					$langFields[] = $searchField;
					$keywords_plural = preg_replace('/\s+/', '%" AND ' . $searchField . ' LIKE "%', $keyword);
					
					if($langFback)
					{
						$filter_search[] =  '`ld`.' . $searchField . ' LIKE ' . $keywords_plural;
						
						if(VmConfig::$defaultLang != VmConfig::$jDefLang)
						{
							$filter_search[] =  '`ljd`.' . $searchField . ' LIKE ' . $keywords_plural;
						}
					}
					
					$searchField = '`l`.' . $searchField;
				}

				if(strpos($searchField, '`') !== false)
				{
					$keywords_plural = preg_replace('/\s+/', '%" AND ' . $searchField . ' LIKE "%', $keyword);
					$filter_search[] =  $searchField . ' LIKE ' . $keywords_plural;
				}
				else
				{
					$keywords_plural = preg_replace('/\s+/', '%" AND `' . $searchField . '` LIKE "%', $keyword);
					$filter_search[] = '`' . $searchField . '` LIKE ' . $keywords_plural;
				}
			}
			if(!empty($filter_search))
			{
				$query->where('(' . implode (' OR ', $filter_search) . ')');
			}
			else
			{
				$query->where('`l`.product_name LIKE ' . $keyword);
				$langFields[] = 'product_name';
			}
			
			if($joinCatLang)
			{
				$query->join('LEFT', '`#__virtuemart_categories_' . VmConfig::$vmlang . '` as cl ON cl.`virtuemart_category_id` = `pc`.`virtuemart_category_id`');
			}
			
			if($joinMfLang)
			{
				$query->join('LEFT', '`#__virtuemart_product_manufacturers` ON p.`virtuemart_product_id` = `#__virtuemart_product_manufacturers`.`virtuemart_product_id`')
				      ->join('LEFT', '`#__virtuemart_manufacturers_' . VmConfig::$vmlang . '` as m ON m.`virtuemart_manufacturer_id` = `#__virtuemart_product_manufacturers`.`virtuemart_manufacturer_id`');
			}
			
			if($joinPrice)
			{
				$query->join('LEFT', '`#__virtuemart_product_prices` as pp ON p.`virtuemart_product_id` = pp.`virtuemart_product_id`');
			}
			
			$query->where('p.`published` = 1');
			$query->group('p.`virtuemart_product_id`');
			
			try
			{
				$db->setQuery($query);
				$product_ids = $db->loadColumn();
			}
			catch (RuntimeException $e)
			{
				JLog::add(sprintf('Keyword filter module query error: %s', $e->getMessage()), JLog::ERROR, 'vpframework');
				return false;
			}
			
			$this->product_ids['byKeyword'] = $product_ids;
		}
		
		return $this->product_ids['byKeyword'];
	}
	
	public function getActionUrl($rawUri = false)
	{
		if(empty($this->uri))
		{
			$option     = strtolower($this->input->getCmd('option', ''));
			$view       = strtolower($this->input->getCmd('view', ''));
			$limitstart = $this->getLimitstart();
			$virtuemart_manufacturer_id = array();
			
			if($option != 'com_virtuemart' && $view != 'category')
			{
				$page = JRoute::_('index.php?option=com_virtuemart&view=category&virtuemart_category_id=0&limitstart=0', false);
				$uri  = clone JUri::getInstance($page);
			}
			else
			{
				$virtuemart_manufacturer_id = $this->input->get('virtuemart_manufacturer_id', array(), 'ARRAY');
				$virtuemart_manufacturer_id = !empty($virtuemart_manufacturer_id) ? array_filter(array_map('intval', $virtuemart_manufacturer_id)) : array();
				
				if(!empty($virtuemart_manufacturer_id))
				{
					$page = JRoute::_('index.php?option=com_virtuemart&view=category&virtuemart_category_id=0&limitstart=0', false);
					$uri  = clone JUri::getInstance($page);
				}
				else
				{
					$uri = clone JUri::getInstance();
				}
			}
			
			if($limitstart > 0)
			{
				$uri->setVar('limitstart', 0);
			}
			else
			{
				$uri->delVar('limitstart', 0);
			}
			
			$uri->delVar('start');
			
			$cfms = (array) $uri->getVar('cfm', array());
			$uri->delVar('cfm');
			$uri->delVar('virtuemart_manufacturer_id');
			
			if(!empty($virtuemart_manufacturer_id))
			{
				$cfms = array_unique(array_merge($cfms, $virtuemart_manufacturer_id));
			}
			
			$cfps = (array) $uri->getVar('cfp', array());
			$uri->delVar('cfp');
			
			$uri->delVar('custom_parent_id');

			foreach($cfms as $key => &$cfm)
			{
				if(empty($cfm))
				{
					unset($cfms[$key]);
				}
			}
			
			if(!empty($cfms))
			{
				$uri->setVar('cfm', $cfms);
			}
			
			foreach($cfps as $key => &$cfp)
			{
				if(empty($cfp))
				{
					unset($cfps[$key]);
				}
			}
			
			if(!empty($cfps))
			{
				$uri->setVar('cfp', $cfps);
			}
			
			if($cFields = $this->filterHelper->getCustomFields($this->modParams))
			{
				foreach($cFields as $cField)
				{
					$name = 'cff_' . $cField->custom_id;
					$cffs = (array) $uri->getVar($name, array());
					$uri->delVar($name);
					
					foreach($cffs as $key => &$cff)
					{
						if(empty($cff))
						{
							unset($cffs[$key]);
						}
					}
					
					if(!empty($cffs))
					{
						$uri->setVar($name, $cffs);
					}
				}
			}
			
			$this->uri = $uri;
		}
		
		if($rawUri)
		{
			return $this->uri;
		}
		
		$router = $this->app->getRouter();
		
		if($router->getMode() == JROUTER_MODE_SEF)
		{
			$virtuemart_category_id = strtolower($this->input->getInt('virtuemart_category_id', 0));
			$url = JRoute::_('index.php?option=com_virtuemart&view=category&virtuemart_category_id=' . $virtuemart_category_id, false);
			$url = strtok($url, '?');
		}
		else
		{
			$url = JUri::current();
		}
		
		return $url;
	}
	
	public function getHiddenFields()
	{
		$uri    = clone($this->getActionUrl(true));
		$router = $this->app->getRouter();
		
		if($router->getMode() == JROUTER_MODE_SEF)
		{
			$virtuemart_category_id = strtolower($this->input->getInt('virtuemart_category_id', 0));
			
			$menu   = $this->app->getMenu();
			$com    = JComponentHelper::getComponent('com_virtuemart');
			$items  = $menu->getItems('component_id', $com->id);
			$itemid = 0;
			
			foreach($items as $item)
			{
				if(
				   isset($item->query['option']) && $item->query['option'] == 'com_virtuemart' &&
				   isset($item->query['view']) && $item->query['view'] == 'category' &&
				   isset($item->query['virtuemart_category_id']) && $item->query['virtuemart_category_id'] == $virtuemart_category_id &&
				   empty($item->query['virtuemart_manufacturer_id'])
					)
				{
					$itemid = $item->id;
					break;
				}
			}

			if(!empty($itemid))
			{
				$item = $menu->getItem($itemid);
				
				if(empty($item->query['option']) || $item->query['option'] != 'com_virtuemart')
				{
					$uri->setVar('option', 'com_virtuemart');
				}
				
				if(empty($item->query['view']) || $item->query['view'] != 'category')
				{
					$uri->setVar('view', 'category');
				}
			}
			else
			{
				$option = strtolower($this->input->getCmd('option', ''));
				$view   = strtolower($this->input->getCmd('view', ''));
				
				if($option != 'com_virtuemart')
				{
					$uri->setVar('option', 'com_virtuemart');
				}
				
				if($view != 'category')
				{
					$uri->setVar('view', 'category');
					$uri->setVar('virtuemart_category_id', '0');
				}
			}
		}
		else
		{
			$virtuemart_category_id = $this->input->getInt('virtuemart_category_id', 0);
			
			$uri->setVar('option', 'com_virtuemart');
			$uri->setVar('view', 'category');
			$uri->setVar('virtuemart_category_id', $virtuemart_category_id);
		}
		
		$query = $uri->getQuery(true);

		if(!empty($query))
		{
			return $this->_getHiddenFields($query);
		}
		
		return '';
	}
	
	protected function _getHiddenFields($query, $parent = null)
	{
		$fields = array();
		
		foreach($query as $key => $value)
		{
			if(strpos($key, 'cff_') === 0 || $key == 'cfp' || $key == 'cfm')
			{
				continue;
			}
			
			if($key == 'Itemid' && empty($value))
			{
				continue;
			}
			
			$name = $parent ? $parent . '[' . $key . ']' : $key;
			
			if(is_array($value))
			{
				$fields[] = $this->_getHiddenFields($value, $name);
			}
			else
			{
				$fields[] = '<input type="hidden" name="' . $name . '" value="' . $this->filterHelper->clean($value) . '" />';
			}
		}
		
		$fields = !empty($fields) ? implode($fields) : '';
		
		return $fields;
	}
	
	protected function getCustomPriceRanges()
	{
		if(!isset($this->cache['customPriceRanges']))
		{
			$options = array();
			$ranges  = (array) $this->modParams->get('price_ranges', array());
			
			foreach($ranges as $range)
			{
				$range = (object) $range;
				
				if(!empty($range->enabled))
				{
					$options[$range->category_id] = new stdClass;
					$options[$range->category_id]->min_price = null;
					$options[$range->category_id]->max_price = null;
					$options[$range->category_id]->min_override_price = preg_replace('/[^0-9\.]/', '', $range->min_price);
					$options[$range->category_id]->max_override_price = preg_replace('/[^0-9\.]/', '', $range->max_price);
				}
			}
			
			$this->cache['customPriceRanges'] = $options;
		}
		
		return $this->cache['customPriceRanges'];
	}

	
	public function getLimitstart()
	{
		if(!isset($this->cache['limitstart']))
		{
			$app = JFactory::getApplication ();
			$view = vRequest::getCmd('view', 'virtuemart');

			$cateid = vRequest::getInt ('virtuemart_category_id', -1);
			$manid = vRequest::getInt ('virtuemart_manufacturer_id', 0);

			$limitString = 'com_virtuemart.' . $view . 'c' . $cateid . '.limit';
			$limit = (int) $app->getUserStateFromRequest ($limitString, 'limit');

			$limitStartString  = 'com_virtuemart.' . $view . '.limitstart';
			
			if($app->isSite() and ($cateid != -1 or $manid != 0))
			{
				//vmdebug('setPaginationLimits is site and $cateid,$manid ',$cateid,$manid);
				$lastCatId = ShopFunctionsf::getLastVisitedCategoryId();
				$lastManId = ShopFunctionsf::getLastVisitedManuId();

				if( !empty($cateid) and $cateid != -1)
				{
					$gCatId = $cateid;
				}
				elseif(!empty($lastCatId))
				{
					$gCatId = $lastCatId;
				}

				if(!empty($gCatId))
				{
					$catModel= VmModel::getModel('category');
					$category = $catModel->getCategory($gCatId);
				}
				else
				{
					$category = new stdClass();
				}

				if ((!empty($lastCatId) and $lastCatId != $cateid) or (!empty($manid) and $lastManId != $manid))
				{
					//We are in a new category or another manufacturer, so we start at page 1
					$limitStart = vRequest::getInt('limitstart', 0,'GET');
				}
				else
				{
					//We were already in the category/manufacturer, so we take the value stored in the session
					$limitStartString  = 'com_virtuemart.' . $view . 'c' . $cateid . 'm' . $manid. '.limitstart';
					$limitStart = $app->getUserStateFromRequest($limitStartString, 'limitstart', vRequest::getInt('limitstart', 0,'GET'), 'int');
				}
			}
			else
			{
				$limitStart = $app->getUserStateFromRequest ('com_virtuemart.' . $view . '.limitstart', 'limitstart', vRequest::getInt('limitstart', 0, 'GET'), 'int');
			}
			
			$this->cache['limitstart'] = $limitStart;
		}
		
		return $this->cache['limitstart'];
	}
}