<?php
/**
 *---------------------------------------------------------------------------------------
 * @package       VirtuePlanet Framework for Joomla!
 *---------------------------------------------------------------------------------------
 * @copyright     Copyright (C) 2012-2021 VirtuePlanet Services LLP. All rights reserved.
 * @license       GNU General Public License version 2 or later; see LICENSE.txt
 * @authors       Abhishek Das
 * @email         info@virtueplanet.com
 * @link          https://www.virtueplanet.com
 *---------------------------------------------------------------------------------------
 */

defined('_JEXEC') or die;

// Register VirtueMart config to Joomla autoloader
JLoader::register('VmConfig', JPATH_ROOT . '/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('vmVersion', JPATH_ROOT . '/administrator/components/com_virtuemart/version.php');
JLoader::register('VirtueMartModelVendor', JPATH_ROOT . '/administrator/components/com_virtuemart/models/vendor.php');
JLoader::register('calculationHelper', JPATH_ROOT . '/administrator/components/com_virtuemart/helpers/calculationh.php');
JLoader::register('ShopFunctions', JPATH_ROOT . '/administrator/components/com_virtuemart/helpers/shopfunctions.php');
JLoader::register('VmImage', JPATH_ROOT . '/administrator/components/com_virtuemart/helpers/image.php');
JLoader::register('TableMedias', JPATH_ROOT . '/administrator/components/com_virtuemart/tables/medias.php');
JLoader::register('TableCategories', JPATH_ROOT . '/administrator/components/com_virtuemart/tables/categories.php');
JLoader::register('VirtueMartModelCategory', JPATH_ROOT . '/administrator/components/com_virtuemart/models/category.php');
JLoader::register('VirtueMartModelProduct', JPATH_ROOT . '/administrator/components/com_virtuemart/models/product.php');
JLoader::register('vmCustomPlugin', JPATH_VM_PLUGINS . '/vmcustomplugin.php');

/**
* VP Framework VirtueMart Helper
* 
* @since 1.0.5
*/
class VPFrameworkVM
{
	public static $compareList = null;
	public static $wishlist = null;
	
	protected static $currencies = null;
	protected static $activeCategories = null;
	protected static $counter = 0;
	protected static $colorCSS = array();
	protected static $lazyContainerClass = array();
	protected static $ratings = array();
	protected static $reviewCounts = array();
	protected static $cookieWishlist = null;
	
	protected static $categoryTree = array();
	protected static $lastCategory = 0;
	protected static $validatorLoaded = false;
	protected static $attributes = array();

	public static function loadLanguages()
	{
		VmConfig::loadJLang('com_virtuemart', true);
	}
	
	public static function onLayoutCall($file_path)
	{
		// Special actions
	}
	
	public static function getCurrencies()
	{
		if(static::$currencies === null)
		{
			$db = JFactory::getDbo();
			$query = $db->getQuery(true)
									->select('virtuemart_currency_id, currency_name, currency_code_3')
									->from('#__virtuemart_currencies')
									->where('published = 1')
									->order('ordering ASC, virtuemart_currency_id ASC');
									
			$db->setQuery($query);
			$currencies = $db->loadObjectList('virtuemart_currency_id');
			
			if(empty($currencies))
			{
				static::$currencies = array();
			}
			else
			{
				static::$currencies = $currencies;
			}
		}
		
		return static::$currencies;
	}
	
	public static function getCategories(&$params, $param_prefix = '')
	{
		$params             = !($params instanceof JRegistry) ? new JRegistry : $params;
		$parent_id          = (int) $params->get($param_prefix . 'vm_category_parent_id', 0);
		$active_category_id = self::getActiveCategories();
		$start              = $params->get($param_prefix . 'vm_category_start_level', null);
		$end                = $params->get($param_prefix . 'vm_category_end_level', null);
		$addImages          = $params->get($param_prefix . 'show_vm_category_image', 0);
		$key                = 'vm_categories.parent_id:' . $parent_id . '.active_category_id:' . 
		                      json_encode($active_category_id) . '.start:' . $start . '.end:' . $end . 
		                      '.addImage:' . $addImages;

		$cache = JFactory::getCache('vp_framework', '');
		$categories = $cache->get($key);

		if(empty($categories))
		{
			self::$categoryTree = array();
			self::$lastCategory = 0;
			$categories = self::categoryLoop($parent_id, $params, $param_prefix);
			$cache->store($categories, $key);
		}

		return $categories;
	}
	
	static public function categoryLoop($parent_id = 0, &$params, $param_prefix = '', $level = 0) 
	{
		$level++;
		$model = VmModel::getModel('Category');
		$activeCategories = self::getActiveCategories();
		$vendor_id = 1;
		$start = $params->get($param_prefix . 'vm_category_start_level', null); 
		$end = $params->get($param_prefix . 'vm_category_end_level', null);
		$addImages = $params->get($param_prefix . 'show_vm_category_image', 0);
		
		$categories = $model->getChildCategoryList($vendor_id, $parent_id);

		if(!empty($categories))
		{
			if($addImages)
			{
				$model->addImages($categories);
			}

			foreach ($categories as $category) 
			{
				$category->id                   = null;
				$category->title                = htmlspecialchars($category->category_name, ENT_COMPAT, 'UTF-8', false);
				$category->category_description = htmlspecialchars($category->category_description, ENT_COMPAT, 'UTF-8', false);
				$category->type                 = 'vmcategory';
				$category->link                 = JRoute::_('index.php?option=com_virtuemart&view=category&virtuemart_category_id='. $category->virtuemart_category_id);
				$category->active               = in_array($category->virtuemart_category_id, $activeCategories);
				$category->level                = !empty($start) ? ($level - $start) + 1 : $level;
				$category->deeper               = false;
				$category->shallower            = false;
				$category->level_diff           = 0;
				$category->group                = 0;
				
				if(isset($category->images[0]))
				{
					$category->thumbnail = $category->images[0]->displayMediaThumb('class="vpf-category-thumbnail"', false);
					unset($category->images);
				}
				else
				{
					$category->thumbnail = null;
				}
				
				if(isset(self::$categoryTree[self::$lastCategory]))
				{
					self::$categoryTree[self::$lastCategory]->deeper     = ($category->level > self::$categoryTree[self::$lastCategory]->level);
					self::$categoryTree[self::$lastCategory]->shallower  = ($category->level < self::$categoryTree[self::$lastCategory]->level);
					self::$categoryTree[self::$lastCategory]->level_diff = (self::$categoryTree[self::$lastCategory]->level - $category->level);
				}
				
				$category->cols = (int) $params->get($param_prefix . 'vm_mega_cols', 1);
				$category->cols = ($category->cols > 0) ? $category->cols : 1;
				
				$category->params = new JRegistry;
				$category->params->set('show_image', 0);
			
				if($category->level == 2)
				{
					$category->group = 1;
					$category->subwidth = floor(12/$category->cols);
					$category->params->set('show_image', $addImages);
				}
				elseif($category->level > 1)
				{
					$category->group = 0;
					$category->subwidth = 12;
				}
				
				$category->width = strtolower(trim($params->get($param_prefix . 'vm_mega_width', 0)));
				if(!in_array($category->width, array('auto', 'justify')))
				{
					$category->width = (float) $category->width;
				}
				$category->width = !empty($category->width) ? $category->width : ($category->cols == 1 ? 'auto' : 'justify');
				$category->mega_class = 'vm-category';
				
				
				if((empty($start) || ($level >= $start)) && (empty($end) || ($level <= $end)))
				{
					self::$lastCategory = $category->virtuemart_category_id;
					self::$categoryTree[$category->virtuemart_category_id] = $category;
				}
				
				$category->parent = $model->hasChildren($category->virtuemart_category_id);
				
				if($category->parent)
				{
					self::categoryLoop($category->virtuemart_category_id, $params, $param_prefix, $level);
				}
			}
			
			if(isset(self::$categoryTree[self::$lastCategory]))
			{
				self::$categoryTree[self::$lastCategory]->deeper     = (($start?$start:1) > self::$categoryTree[self::$lastCategory]->level);
				self::$categoryTree[self::$lastCategory]->shallower  = (($start?$start:1) < self::$categoryTree[self::$lastCategory]->level);
				self::$categoryTree[self::$lastCategory]->level_diff = (self::$categoryTree[self::$lastCategory]->level - ($start?$start:1));
			}
		}

		return self::$categoryTree;
	}
	
	public static function getActiveCategories()
	{
		if(static::$activeCategories === null)
		{
			$app    = JFactory::getApplication();
			$config = VmConfig::loadConfig();
			$model  = VmModel::getModel('Category');
			
			$active_category_ids = $app->input->get('virtuemart_category_id', array(0), 'ARRAY');
			$active_category_ids = array_filter(array_map('intval', $active_category_ids));
			
			static::$activeCategories = array();
			
			if(!empty($active_category_ids))
			{
				foreach($active_category_ids as $active_category_id)
				{
					$activeCategories = $model->getCategoryRecurse($active_category_id, 0);
					
					static::$activeCategories = array_merge(static::$activeCategories, $activeCategories);
				}
			}
			
			static::$activeCategories = array_merge(static::$activeCategories, $active_category_ids);
			static::$activeCategories = array_unique(static::$activeCategories);
		}

		return static::$activeCategories;
	}
	
	public static function categoryListTree($parent_id = 0, $level = 0, $vendor_id = 1, $disabled = array())
	{
		$key = 'vm_category_list.options.parent_id' . $parent_id . '.level:' . $level . '.vendor_id:' . $vendor_id . 'disabled:' . json_encode($disabled);
		$cache = JFactory::getCache('virtuemart_cat_options', '');
		$cache->setCaching(1);
		$options = $cache->get($key);
		
		if(empty($options))
		{
			$options = self::getCategoryListOptions($parent_id, $level, $vendor_id, $disabled);
			$cache->store($options, $key);
		}
		
		return (array) $options;
	}

	public static function getCategoryListOptions($parent_id = 0, $level = 0, $vendor_id = 1, $disabled = array())
	{
		static $options = array();
		$level++;
		$categoryModel = VmModel::getModel ('category');
		$categoryModel->_noLimit = true;
		$categories = $categoryModel->getCategories(true, $parent_id, false, '', $vendor_id);
		
		if(!empty($categories))
		{
			foreach($categories as $category)
			{
				$isDisabled = in_array($category->virtuemart_category_id, $disabled);
				$category_id = $category->virtuemart_category_id;
				$category_name = str_repeat (' - ', ($level - 1)) . $category->category_name;
				$options[] = JHtml::_('select.option', $category_id, $category_name, 'value', 'text', $isDisabled);
				
				if($categoryModel->hasChildren($category_id))
				{
					self::getCategoryListOptions($category_id, $level, $vendor_id, $disabled);
				}
			}
		}
		
		return $options;
	}
	
	public static function getCompareList()
	{
		if(static::$compareList === null)
		{
			$session = JFactory::getSession();
			$product_ids = (array) $session->get('vmcompare', array(), 'vpframework');
			
			if(!empty($product_ids))
			{
				$model = VmModel::getModel('Product');	
				$ratingModel = VmModel::getModel('ratings');
				$model->withRating = $ratingModel->showRating();	
				$products = $model->getProducts($product_ids);
				$model->addImages($products, 1);
				
				if(!empty($products))
				{
					$customfieldsModel = VmModel::getModel('Customfields');
					foreach($products as $key => $productItem)
					{
						$productItem->stock = self::getStockText($productItem);
						
						if(!empty($productItem->customfields))
						{
							$product = clone($productItem);
							$customfields = array();
							foreach($productItem->customfields as $cu)
							{
								$customfields[] = clone($cu);
							}

							$customfieldsSorted = array();
							$customfieldsModel->displayProductCustomfieldFE($product, $customfields);
							$product->stock = self::getStockText($productItem);
							foreach ($customfields as $k => $custom)
							{
								if (!empty($custom->layout_pos))
								{
									$customfieldsSorted[$custom->layout_pos][] = $custom;
									unset($customfields[$k]);
								}
							}
							$customfieldsSorted['normal'] = $customfields;
							$product->customfieldsSorted = $customfieldsSorted;
							unset($product->customfields);
							$products[$key] = $product;
						} 
						else
						{
							$products[$key] = $productItem;
						}
					}
				}
				
				static::$compareList = $products;
			} 
			else
			{
				static::$compareList = array();
			}
		}
		
		return static::$compareList;
	}
	
	public static function getWishlistFromCookie($force = false)
	{
		$template = plgSystemVPFrameworkHelper::getTemplate();
		$params = $template->params;
		
		if(!$params->get('vm_wishlist_use_cookie', 1))
		{
			return array();
		}
		
		if(self::$cookieWishlist === null || $force)
		{
			$config = JFactory::getConfig();
			$cookie_domain = $config->get('cookie_domain', '');
			$cookie_path = $config->get('cookie_path', '/');
			$items = array();
			
			$hash = JApplication::getHash('VPFRAMEWORK_VMWISHLIST');
			
			// Create the encryption key, apply extra hardening using the user agent string.
			// Since we're decoding, no UA validity check is required.
			$privateKey = JApplication::getHash(@$_SERVER['HTTP_USER_AGENT']);
			
			$key = new JCryptKey('simple', $privateKey, $privateKey);
			$crypt = new JCrypt(new JCryptCipherSimple, $key);
			
			if($str = JRequest::getString($hash, '', 'cookie', JREQUEST_ALLOWRAW | JREQUEST_NOTRIM))
			{
				$str = $crypt->decrypt($str);
				$cookieData = @unserialize($str);
				
				$filter = JFilterInput::getInstance();
				
				if($cookieData && is_array($cookieData))
				{
					foreach($cookieData as $item)
					{
						$item = (int) $filter->clean($item);
						
						if($item > 0)
						{
							$items[] = $item;
						}
					}
				}
			}
			
			self::$cookieWishlist = $items;
		}
		
		return self::$cookieWishlist;
	}
	
	public static function setWishlistToCookie($items)
	{
		$template = plgSystemVPFrameworkHelper::getTemplate();
		$params = $template->params;
		
		if(!$params->get('vm_wishlist_use_cookie', 1))
		{
			return;
		}
		
		$config = JFactory::getConfig();
		$cookie_domain = $config->get('cookie_domain', '');
		$cookie_path = $config->get('cookie_path', '/');
		
		$hash = JApplication::getHash('VPFRAMEWORK_VMWISHLIST');
		
		// Create the encryption key, apply extra hardening using the user agent string.
		// Since we're decoding, no UA validity check is required.
		$privateKey = JApplication::getHash(@$_SERVER['HTTP_USER_AGENT']);
		
		$key = new JCryptKey('simple', $privateKey, $privateKey);
		$crypt = new JCrypt(new JCryptCipherSimple, $key);
		
		$lifetime = 2592000; // One Month in seconds
		
		setcookie($hash, $crypt->encrypt(serialize($items)), (time() + $lifetime), $cookie_path, $cookie_domain);
	}
	
	public static function getWishlist()
	{
		if(static::$wishlist === null)
		{
			$user = JFactory::getUser();
			$user_id = (int) $user->get('id');
			
			if(!$user->guest && !empty($user_id))
			{
				$db = JFactory::getDbo();
				$query = $db->getQuery(true)
				            ->select('virtuemart_product_id')
				            ->from('#__vpframework_vm_wishlist')
				            ->where('user_id = ' . $user_id);

				$db->setQuery($query);
				$product_ids = $db->loadColumn();
			}
			else
			{
				$session = JFactory::getSession();
				$itemsInCookie = VPFrameworkVM::getWishlistFromCookie();
				$product_ids = (array) $session->get('vmwishlist', $itemsInCookie, 'vpframework');
			}
			
			if(!empty($product_ids))
			{
				$model = VmModel::getModel('Product');
				$ratingModel = VmModel::getModel('ratings');
				$model->withRating = $ratingModel->showRating();
				$products = $model->getProducts($product_ids);
				$model->addImages($products, 1);

				if(!empty($products))
				{
					$customfieldsModel = VmModel::getModel('Customfields');
					if (!class_exists ('vmCustomPlugin'))
					{
						require(JPATH_VM_PLUGINS . '/vmcustomplugin.php');
					}
					foreach($products as $key => $productItem)
					{
						$productItem->stock = self::getStockText($productItem);
						
						if(!empty($productItem->customfields))
						{
							$product = clone($productItem);
							$customfields = array();
							foreach($productItem->customfields as $cu)
							{
								$customfields[] = clone($cu);
							}

							$customfieldsSorted = array();
							$customfieldsModel->displayProductCustomfieldFE($product, $customfields);
							$product->stock = self::getStockText($productItem);
							foreach ($customfields as $k => $custom)
							{
								if (!empty($custom->layout_pos))
								{
									$customfieldsSorted[$custom->layout_pos][] = $custom;
									unset($customfields[$k]);
								}
							}
							$customfieldsSorted['normal'] = $customfields;
							$product->customfieldsSorted = $customfieldsSorted;
							unset($product->customfields);
							$products[$key] = $product;
						} 
						else
						{
							$products[$key] = $productItem;
						}
					}
				}
				
				static::$wishlist = $products;
			}
			else
			{
				static::$wishlist = array();
			}
		}
		
		return static::$wishlist;
	}
	
	public static function moveWishlistToUser()
	{
		$app = JFactory::getApplication();
		$user = JFactory::getUser();
		$session = JFactory::getSession();
		$db = JFactory::getDbo();
		$query = $db->getQuery(true);
		$user_id = $user->get('id');
		
		if(!$user->guest && $user_id > 0)
		{
			$itemsInCookie = VPFrameworkVM::getWishlistFromCookie();
			$product_ids = (array) $session->get('vmwishlist', $itemsInCookie, 'vpframework');
			
			if(empty($product_ids))
			{
				return true;
			}
			
			// Get existing items
			$query->select($db->quoteName('virtuemart_product_id'))
			      ->from($db->quoteName('#__vpframework_vm_wishlist'))
			      ->where('user_id = ' . (int) $user_id);

			$db->setQuery($query);
			$existing_product_ids = $db->loadColumn();
			
			if(!empty($existing_product_ids))
			{
				$product_ids = array_diff($product_ids, $existing_product_ids);
			}
			
			if(!empty($product_ids))
			{
				$query->clear()
							->insert($db->quoteName('#__vpframework_vm_wishlist'))
							->columns(array($db->quoteName('user_id'), $db->quoteName('virtuemart_product_id')));
				
				$values = array();
				
				foreach($product_ids as $product_id)
				{
					$query->values($user_id . ',' . $product_id);
				}
				
				try 
				{
					$db->setQuery($query);
					$db->execute();
				}
				catch (Exception $e) 
				{
					$app->enqueueMessage($e->getMessage(), 'error');
					return false;
				}
				
				$session->set('vmwishlist', array(), 'vpframework');
				VPFrameworkVM::setWishlistToCookie(array());
				
				//$app->enqueueMessage(JText::_('PLG_SYSTEM_VPFRAMEWORK_WISHLIST_MOVED_TO_ACCOUNT'), 'success');
			}
		}
		
		return true;
	}
	
	
	public static function getOrderByInfo($html)
	{
		if(empty($html) || !is_string($html))
		{
			return false;
		}
		
		$dom = new DOMDocument;
		$dom_state = libxml_use_internal_errors(true);
		$meta = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
		$dom->loadHTML($meta . $html);
		libxml_clear_errors();
		libxml_use_internal_errors($dom_state);
		$links = $dom->getElementsByTagName('a');
		
		if(!$links->length)
		{
			return false;
		}
		
		$return = new stdClass;
		$return->active = null;
		$return->selected = '';
		$return->dir = 'asc';
		$return->dir_title = vmText::_('COM_VIRTUEMART_DESC');
		$return->dir_url = null;
		$return->options = array();
		
		$app    = JFactory::getApplication();
		$option = $app->input->getCmd('option');
		$view   = $app->input->getCmd('view');

		foreach($links as $link)
		{
			if($link->getAttribute('href'))
			{
				$title = $link->getAttribute('title');
				$url = $link->getAttribute('href');
				$value = $link->textContent;
				
				if($value == $title)
				{
					$return->options[] = JHtml::_('select.option', (string) $url, $value);
				}
				else
				{
					if($option == 'com_customfilters' && $view == 'products')
					{
						$return->active = $title;
						$return->dir_url = self::escape($url);
						$return->selected = $url;
						$return->options[] = JHtml::_('select.option', (string) $url, $return->active);
						
						if(strpos($value, vmText::_('COM_VIRTUEMART_DESC')) !== false)
						{
							$return->dir = 'asc';
							$return->dir_title = vmText::_('COM_VIRTUEMART_DESC');
						}
						else
						{
							$return->dir = 'desc';
							$return->dir_title = vmText::_('COM_VIRTUEMART_ASC');
						}
					}
					else
					{
						$return->active = trim(str_replace($title, '', $value));
						$return->dir_url = self::escape($url);
						$return->selected = $url;
						$return->options[] = JHtml::_('select.option', (string) $url, $return->active);
						
						if($title == vmText::_('COM_VIRTUEMART_DESC'))
						{
							$return->dir = 'asc';
							$return->dir_title = vmText::_('COM_VIRTUEMART_DESC');
						}
						else
						{
							$return->dir = 'desc';
							$return->dir_title = vmText::_('COM_VIRTUEMART_ASC');
						}
					}
				}
			}
		}
		
		unset($dom, $links, $link);
		
		return $return;
	}

	public static function getManufactuerFilterInfo($html)
	{
		if(empty($html) || !is_string($html))
		{
			return false;
		}
		
		$dom = new DOMDocument;
		$dom_state = libxml_use_internal_errors(true);
		$meta = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
		$dom->loadHTML($meta . $html);
		libxml_clear_errors();
		libxml_use_internal_errors($dom_state);
		$links = $dom->getElementsByTagName('a');
		
		if(!$links->length)
		{
			return false;
		}
		
		$divs = $dom->getElementsByTagName('div');

		if(!$divs->length)
		{
			return false;
		}
		
		$return = new stdClass;
		$return->active = null;
		$return->selected = '';
		$return->options = array();
		
		foreach($divs as $div)
		{
			if($div->getAttribute('class') == 'activeOrder')
			{
				$url = JUri::current();
				$value = $div->textContent;
				$return->options[] = JHtml::_('select.option', (string) $url, $value);
				$return->selected = $url;
				$return->active = $value;
				break;
			}
		}

		foreach($links as $link)
		{
			if($link->getAttribute('href'))
			{
				$url = $link->getAttribute('href');
				$value = $link->textContent;
				$return->options[] = JHtml::_('select.option', (string) $url, $value);
			}
		}
		
		unset($dom, $divs, $div, $links, $link);
		
		return $return;
	}
	
	public static function getLimitBoxInfo($html)
	{
		if(empty($html) || !is_string($html))
		{
			return false;
		}

		$dom = new DOMDocument;
		$dom_state = libxml_use_internal_errors(true);
		$meta = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
		$dom->loadHTML($meta . $html);
		libxml_clear_errors();
		libxml_use_internal_errors($dom_state);
		$options = $dom->getElementsByTagName('option');

		if(!$options->length)
		{
			return false;
		}
		
		$return = new stdClass;
		$return->active = null;
		$return->selected = '';
		$return->options = array();
		
		foreach($options as $option)
		{
			$text = $option->textContent;
			$value = $option->getAttribute('value');
			$return->options[] = JHtml::_('select.option', (string) $value, $text);

			if($option->getAttribute('selected'))
			{
				$return->selected = $value;
				$return->active = $text;
			}
		}
		
		unset($dom, $options, $option);
		return $return;
	}
	
	public static function getSwitches()
	{
		static $switches = null;
		
		if($switches === null)
		{
			$app              = JFactory::getApplication();
			$option           = $app->input->getCmd('option');
			$view             = $app->input->getCmd('view');
			$category_ids     = $app->input->get('virtuemart_category_id', array(0), 'ARRAY');
			$category_ids     = array_map('intval', $category_ids);
			$category_id_hash = ($option == 'com_customfilters' && $view == 'products') ? 'customfilters' : md5(serialize($category_ids));
			$defaultLayout    = $app->getUserState('vpframework.vm.productsublayout.category.' . $category_id_hash, 0);
			$productsLayout   = VmConfig::get('productsublayout', 'products');
			$productsLayout   = !empty($defaultLayout) ? $defaultLayout : $productsLayout;
			$modeMap          = array(
				'products' => 'grid',
				'products_horizon' => 'list',
				'products_slim' => 'list'
			);
			$productsLayout   = (empty($productsLayout) || !array_key_exists($productsLayout, $modeMap)) ? 'products' : $productsLayout;
			$viewMode         = strtolower($app->input->get('viewmode', $modeMap[$productsLayout], 'WORD'));
			
			$switches = array();
			
			$switches['grid'] = new stdClass;
			$switches['grid']->title = JText::_('PLG_SYSTEM_VPFRAMEWORK_VIEW_MODE_GRID');
			$uri = clone JURI::getInstance();
			$uri->delVar('custom_parent_id');
			$params = array_merge($uri->getQuery(true), array('viewmode' => 'grid'));
			unset($params['tmpl']);
			$query = $uri->buildQuery($params);
			$uri->setQuery($query);
			$switches['grid']->url = self::escape($uri->toString());
			$switches['grid']->active = (bool)($viewMode == 'grid');
			
			$switches['list'] = new stdClass;
			$switches['list']->title = JText::_('PLG_SYSTEM_VPFRAMEWORK_VIEW_MODE_LIST');
			$uri = clone JURI::getInstance();
			$uri->delVar('custom_parent_id');
			$params = array_merge($uri->getQuery(true), array('viewmode' => 'list'));
			unset($params['tmpl']);
			$query = $uri->buildQuery($params);
			$uri->setQuery($query);
			$switches['list']->url = self::escape($uri->toString());
			$switches['list']->active = (bool)($viewMode == 'list');
		}

		return $switches;
	}

	public static function setLazyContainer($class, $params, $param_prefix = '')
	{
		if(!isset(static::$lazyContainerClass[$class]))
		{
			$param_prefix = trim((string) $param_prefix);
			$doc = JFactory::getDocument();
			$css = $class . '{height: ' . (int) $params->get($param_prefix . 'vm_lazythumb_height_lg', 290) . 'px;}';
			
			if($params->get('is_responsive', 1))
			{
				$css .= '@media only screen and (max-width : 1200px) {';
				$css .= $class . '{height: ' . (int) $params->get($param_prefix . 'vm_lazythumb_height_md', 250) . 'px;}';
				$css .= '}';
				$css .= '@media only screen and (max-width : 992px) {';
				$css .= $class . '{height: ' . (int) $params->get($param_prefix . 'vm_lazythumb_height_sm', 190) . 'px;}';
				$css .= '}';
				$css .= '@media only screen and (max-width: 767px) {';
				$css .= $class . '{height: ' . (int) $params->get($param_prefix . 'vm_lazythumb_height_xs', 100) . 'px;}';
				$css .= '}';
			}
			
			$doc->addStyleDeclaration($css);
			static::$lazyContainerClass[$class] = $css;
		}
	}
	
	public static function displayThumnbailLazily($image, $fallback_alt = '', $class = null, $loadingImage = null, $data_tag = 'data-original')
	{
		if(!$image = new VPFrameworkVMImage($image))
		{
			return false;
		}

		$thumbnail = $image->getThumb($fallback_alt);
		
		$html = '<img ';
		
		if(!empty($loadingImage))
		{
			$html .= 'src="' . trim($loadingImage) . '" ';
		}
		elseif($loadingImage !== false)
		{
			$template = plgSystemVPFrameworkHelper::getTemplate();
			$html .= 'src="' . $template->media_uri . '/images/lazyload-dummy.png" '; 
		}
		
		$html .= trim($data_tag) . '="' . $thumbnail['url'] . '" ';
		$html .= 'alt="' . $thumbnail['alt'] . '" ';
		
		if(!empty($class))
		{
			$html .= 'class="' . trim($class) . '"';
		}
		
		$html .= '/>';
		
		return $html;
	}
	
	public static function displayStringTypeField($field, $params, $dropUp = false)
	{
		if(!empty($field->display) && $field->field_type == 'S' && !empty($field->is_cart_attribute) && !empty($field->is_input) && !empty($field->is_list) && $field->is_list != 2)
		{
			return self::displayStringListTypeField($field, $params, $dropUp);
		}
		elseif(!isset($field->options) || empty($field->options) || empty($field->display) || $field->field_type != 'S' || empty($field->is_cart_attribute) || empty($field->is_input))
		{
			return $field->display;
		}
		
		$button_fields = $params->get('vm_button_fields', array());
		$color_fields = $params->get('vm_field_colors', array());
		
		if(!in_array($field->virtuemart_custom_id, $button_fields))
		{
			return self::displayListTypeField($field, $params, $dropUp);
		}

		$dom = new DOMDocument;
		$dom_state = libxml_use_internal_errors(true);
		$meta = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
		$dom->loadHTML($meta . $field->display);
		libxml_clear_errors();
		libxml_use_internal_errors($dom_state);
		$selectLists = $dom->getElementsByTagName('select');

		if(!$selectLists->length)
		{
			unset($dom, $selectLists);
			return $field->display;
		}
		
		static $colorCSS = array();
		$doc = JFactory::getDocument();
		
		$selectList = $selectLists->item(0);
		$field_name = $selectList->getAttribute('name');
		$field_id = $selectList->getAttribute('id');
		
		// Lets free some memory
		unset($dom, $selectLists, $selectList);
		
		$html = '<div class="vpf-radio-button">';
		
		foreach($field->options as $option)
		{
			$html .= '<label for="' . $field_id . '-' . $option->virtuemart_customfield_id . '">';
			$selected = ($option->virtuemart_customfield_id == $field->virtuemart_customfield_id) ? ' checked="checked"' : '';
			$html .= '<input type="radio" id="' . $field_id . '-' . $option->virtuemart_customfield_id . '" name="' . $field_name . '" value="' . $option->virtuemart_customfield_id . '"' . $selected . '/>';
			
			if(array_key_exists($option->customfield_value, $color_fields))
			{
				$colorHexacode = $color_fields[$option->customfield_value];
				$background = str_replace('#', '', $colorHexacode);
				$class  = 'btn btn-fieldvalue btn-colorfield hasTooltip';
				$class .= ' vpf-colorfield-' . self::getColorFieldsCSSClass($option->customfield_value);
				$class .= ' ' . self::readableColour($background, 'btn-colorfield-dark', 'btn-colorfield-light');
				$name = vmText::_($option->customfield_value);
				
				$html .= '<span class="' . $class . '" title="' . strip_tags($name) . '"><span class="sr-only">' . $name . '</span></span>';
			}
			else
			{
				$html .= '<span class="btn btn-fieldvalue">' . vmText::_($option->customfield_value) . '</span>';
			}
			
			//$price = trim(preg_replace('/' . preg_quote(vmText::_($option->customfield_value)) . '/', '', $option->text, 1));
			
			$price = '';
			
			if($option->customfield_value && is_string($option->customfield_value))
			{
				$value_position = @strpos($option->text, vmText::_($option->customfield_value));
				$value_length   = @strlen(vmText::_($option->customfield_value));
				
				if($value_length > 0 && $value_position !== false)
				{
					$price = @substr_replace($option->text, '', $value_position, $value_length);
					$price = @trim($price);
				}
			}
			
			if(!empty($price) && $price != vmText::_('COM_VIRTUEMART_CART_PRICE_FREE'))
			{
				$html .= '<span class="customfield-price">' . $price . '</span>';
			}
			
			$html .= '</label>';
		}
		
		$html .= '</div>';
		
		return $html;
	}
	
	public static function displayStringListTypeField($field, $params, $dropUp)
	{
		$button_fields = $params->get('vm_button_fields', array());
		$color_fields  = $params->get('vm_field_colors', array());
		$html          = $field->display;
		$values        = explode (';', $field->custom_value);
		$field_id      = 'customProductData_' . $field->virtuemart_product_id . '_' . $field->virtuemart_customfield_id;
		$field_name    = 'customProductData[' . $field->virtuemart_product_id . '][' . $field->virtuemart_custom_id . '][' . $field->virtuemart_customfield_id . ']';
		
		if(in_array($field->virtuemart_custom_id, $button_fields))
		{
			$html = '<div class="vpf-radio-button">';
			
			foreach($values as $value)
			{
				$field_id_n = $field_id . '_' . bin2hex($value);
				$selected   = ($value == $field->customfield_value) ? ' checked="checked"' : '';
				
				$html .= '<label for="' . $field_id_n . '">';
				$html .= '<input type="radio" id="' . $field_id_n . '" name="' . $field_name . '" value="' . $value . '"' . $selected . '/>';
				
				if(array_key_exists($value, $color_fields))
				{
					$colorHexacode = $color_fields[$value];
					$background = str_replace('#', '', $colorHexacode);
					$class  = 'btn btn-fieldvalue btn-colorfield hasTooltip';
					$class .= ' vpf-colorfield-' . self::getColorFieldsCSSClass($value);
					$class .= ' ' . self::readableColour($background, 'btn-colorfield-dark', 'btn-colorfield-light');
					$name   = vmText::_($value);
					
					$html .= '<span class="' . $class . '" title="' . strip_tags($name) . '"><span class="sr-only">' . $name . '</span></span>';
				}
				else
				{
					$html .= '<span class="btn btn-fieldvalue">' . vmText::_($value) . '</span>';
				}
				
				$html .= '</label>';
			}
			
			$html .= '</div>';
		}
		else
		{
			$listClass = 'vm-field-selectpicker';
			$listClass = $dropUp ? $listClass . ' dropup' : $listClass;
			
			$html = '<select id="' . $field_id . '" name="' . $field_name . '" class="' . $listClass . '">';
			
			foreach($values as $value)
			{
				$optClass = '';
				$selected = ($value == $field->customfield_value) ? ' selected="selected"' : '';
				
				if(array_key_exists($value, $color_fields))
				{
					$colorHexacode = $color_fields[$value];
					$background = str_replace('#', '', $colorHexacode);

					$class = 'vpf-colorfield-' . self::getColorFieldsCSSClass($value);
					$class = $class . ' ' . self::readableColour($background, 'vpf-colorfield-dark', 'vpf-colorfield-light');
					
					$optClass = ' class="' . $class . '"';
				}
				
				$html .= '<option value="' . $value . '"' . $optClass . $selected . '>' . $value . '</option>';
			}
			
			$html .= '</select>';
		}
		
		return $html;
	}
	
	public static function displayListTypeField($field, $params, $dropUp = false)
	{
		if(!in_array($field->field_type, array('A', 'C', 'S')) || !$field->is_cart_attribute)
		{
			return $field->display;
		}
		
		$doc = JFactory::getDocument();
		$color_fields = $params->get('vm_field_colors', array());
		$html = $field->display;
		
		switch($field->field_type)
		{
			case 'A':
			case 'C':
			
				$dom = new DOMDocument;
				$dom_state = libxml_use_internal_errors(true);
				$meta = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
				$dom->loadHTML($meta . $field->display);
				libxml_clear_errors();
				libxml_use_internal_errors($dom_state);
				$selectLists = $dom->getElementsByTagName('select');
				$options = $dom->getElementsByTagName('option');

				if(!$selectLists->length || !$options->length)
				{
					$radios = $dom->getElementsByTagName('input');
					
					if($radios->length)
					{
						unset($selectLists, $options);
						return self::displayRadioTypeField($field, $params, $dropUp, $dom);
					}
					else
					{
						unset($dom, $selectLists, $options);
						return $field->display;
					}
				}
				
				foreach($selectLists as $selectList)
				{
					$listClass = $selectList->getAttribute('class');
					$listClass = !empty($listClass) ? str_replace('vm-chzn-select', 'vm-field-selectpicker', $listClass) : 'vm-field-selectpicker';
					$listClass = $dropUp ? $listClass . ' dropup' : $listClass;
					$selectList->setAttribute('class', $listClass);
					$options = $selectList->childNodes;
					
					if(!$options->length)
					{
						continue;
					}
					
					foreach($options as $option)
					{
						if(array_key_exists($option->nodeValue, $color_fields))
						{
							$colorHexacode = $color_fields[$option->nodeValue];
							$background = str_replace('#', '', $colorHexacode);

							$class = $option->getAttribute('class');
							$class = !empty($class) ? ($class . ' vpf-colorfield-' . self::getColorFieldsCSSClass($option->nodeValue)) : ('vpf-colorfield-' . self::getColorFieldsCSSClass($option->nodeValue));
							$class = $class . ' ' . self::readableColour($background, 'vpf-colorfield-dark', 'vpf-colorfield-light');
							$option->setAttribute('class', $class);
						}
					}
				}
				
				$html = $dom->saveHTML();
				$html = preg_replace('~<(?:!DOCTYPE|/?(?:html|head|body))[^>]*>\s*~i', '', $html);
				$html = str_replace($meta, '', $html);
				unset($dom, $selectLists, $options, $option);
				break;

			case 'S':
			
				$dom = new DOMDocument;
				$dom_state = libxml_use_internal_errors(true);
				$meta = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
				$dom->loadHTML($meta . $field->display);
				libxml_clear_errors();
				libxml_use_internal_errors($dom_state);
				$selectLists = $dom->getElementsByTagName('select');
				$options = $dom->getElementsByTagName('option');

				if(!$selectLists->length || $selectLists->length > 1 || !$options->length || empty($field->options))
				{
					unset($dom, $selectLists, $options);
					return $field->display;
				}

				$listClass = $selectLists->item(0)->getAttribute('class');
				$listClass = !empty($listClass) ? str_replace('vm-chzn-select', 'vm-field-selectpicker show-tick', $listClass) : 'vm-field-selectpicker show-tick';
				$listClass = $dropUp ? $listClass . ' dropup' : $listClass;
				$selectLists->item(0)->setAttribute('class', $listClass);
				
				foreach($options as $option)
				{
					$value = $option->getAttribute('value');
					
					if(!array_key_exists($value, $field->options))
					{
						continue;
					}
					
					$data = $field->options[$value];
					
					// $price = trim(preg_replace('/' . preg_quote(vmText::_($data->customfield_value)) . '/', '', $option->nodeValue, 1));
					// $price = ($price == vmText::_('COM_VIRTUEMART_CART_PRICE_FREE')) ? '' : $price;
					
					$price = '';
					
					if($data->customfield_value && is_string($data->customfield_value))
					{
						$value_position = @strpos($option->nodeValue, vmText::_($data->customfield_value));
						$value_length   = @strlen(vmText::_($data->customfield_value));
						
						if($value_length > 0 && $value_position !== false)
						{
							$price = @substr_replace($option->nodeValue, '', $value_position, $value_length);
							$price = @trim($price);
						}
					}
					
					$price = ($price == vmText::_('COM_VIRTUEMART_CART_PRICE_FREE')) ? '' : $price;
					
					if(empty($data->customfield_value) && $value == 0)
					{
						$data->customfield_value = vmText::_('COM_VIRTUEMART_LIST_EMPTY_OPTION');
					}
					
					$option->nodeValue = htmlspecialchars(vmText::_($data->customfield_value));
					
					if(!empty($price))
					{
						$option->setAttribute('data-subtext', $price);
					}
					
					if(array_key_exists($data->customfield_value, $color_fields))
					{
						$colorHexacode = $color_fields[$data->customfield_value];
						$background = str_replace('#', '', $colorHexacode);

						$class = $option->getAttribute('class');
						$class = !empty($class) ? ($class . ' vpf-colorfield-' . self::getColorFieldsCSSClass($data->customfield_value)) : ('vpf-colorfield-' . self::getColorFieldsCSSClass($data->customfield_value));
						$class = $class . ' ' . self::readableColour($background, 'vpf-colorfield-dark', 'vpf-colorfield-light');
						$option->setAttribute('class', $class);
					}
				}
				
				$html = $dom->saveHTML();
				$html = preg_replace('~<(?:!DOCTYPE|/?(?:html|head|body))[^>]*>\s*~i', '', $html);
				$html = str_replace($meta, '', $html);
				unset($dom, $selectLists, $options, $option);
				break;
			
			default:
				$html = $field->display;
				break;
		}
		
		return $html;
	}

	public static function displayRadioTypeField($field, $params, $dropUp = false, $dom = null)
	{

		if(!isset($field->options) || empty($field->options) || empty($field->display) || empty($field->is_cart_attribute))
		{
			return $field->display;
		}
		
		$button_fields = $params->get('vm_button_fields', array());
		$color_fields  = $params->get('vm_field_colors', array());
		$isButtons     = false;
		
		if(in_array($field->virtuemart_custom_id, $button_fields))
		{
			$isButtons = true;
		}
		
		$meta = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">';
		
		if(!($dom instanceof DOMDocument))
		{
			$dom = new DOMDocument;
			$dom_state = libxml_use_internal_errors(true);
			$dom->loadHTML($meta . $field->display);
			libxml_clear_errors();
			libxml_use_internal_errors($dom_state);
		}
		
		$sets    = $dom->getElementsByTagName('div');
		$labels  = $dom->getElementsByTagName('label');
		$radios  = $dom->getElementsByTagName('input');
		$label   = '';
		$inputs  = '';
		$input   = '';
		$btn     = '';
		$sr_only = '';

		if(!$sets->length || !$labels->length || !$radios->length)
		{
			unset($dom, $sets, $radios, $labels);
			return $field->display;
		}
		
		$first_input = $radios->item(0);
		
		if($first_input->getAttribute('type') != 'radio')
		{
			unset($first_input);
			return $field->display;
		}
		
		foreach($sets as $set)
		{
			if($isButtons)
			{
				$set->setAttribute('class', 'vpf-radio-button vpf-button-group');
			}
			else
			{
				$set->setAttribute('class', 'form-group');
			}
			
			$labels = $set->getElementsByTagName('label');
			
			if(!$labels->length)
			{
				unset($dom, $sets, $radios, $labels);
				return $field->display;
			}
			
			foreach($labels as $label)
			{
				$class = $label->getAttribute('class');
				$class = !empty($class) ? str_replace('radio', '', $class) : $class;
				
				if(!$isButtons)
				{
					$class = !empty($class) ? $class . ' radio-inline' : 'radio-inline';
				}
				
				if(trim($class) != '')
				{
					$label->setAttribute('class', $class);
				}
				else
				{
					$label->removeAttribute('class');
				}
				
				$inputs = $label->getElementsByTagName('input');
				
				if(!$inputs->length)
				{
					continue;
				}
				
				$input = $inputs->item(0);
				$input->removeAttribute('style');
				
				if($isButtons)
				{
					$value = trim($label->nodeValue);
					$label->nodeValue = '';
					
					$btn = $dom->createElement('span');
					$label->appendChild($input);
					$label->appendChild($btn);
					
					if(array_key_exists($value, $color_fields))
					{
						$colorHexacode = $color_fields[$value];
						$background    = str_replace('#', '', $colorHexacode);
						$class         = 'btn btn-fieldvalue btn-colorfield hasTooltip vpf-colorfield-' . self::getColorFieldsCSSClass($value);
						$class         = $class . ' ' . self::readableColour($background, 'vpf-colorfield-dark', 'vpf-colorfield-light');
						
						$btn->setAttribute('class', $class);
						$btn->setAttribute('title', $value);
						
						$sr_only = $dom->createElement('span');
						$btn->appendChild($sr_only);
						$sr_only->setAttribute('class', 'sr-only');
						$sr_only->nodeValue = $value;
					}
					else
					{
						$class = 'btn btn-fieldvalue';
						$btn->setAttribute('class', $class);
						$btn->nodeValue = $value;
					}
				}
			}
		}
		
		$html = $dom->saveHTML();
		$html = preg_replace('~<(?:!DOCTYPE|/?(?:html|head|body))[^>]*>\s*~i', '', $html);
		$html = str_replace($meta, '', $html);
		unset($dom, $sets, $set, $labels, $label, $inputs, $input, $btn, $sr_only);
		
		return $html;
	}

	public static function setColorFieldsCSS($params = null)
	{
		if(empty($params))
		{
			$template = plgSystemVPFrameworkHelper::getTemplate();
			$params   = $template->params;
		}
		
		$color_fields = $params->get('vm_field_colors', array());
		
		if(empty($color_fields))
		{
			return;
		}
		
		$doc = JFactory::getDocument();
		$tab = $doc->_getTab();
		$lineEnd = $doc->_getLineEnd();
		$css = array();
		
		foreach($color_fields as $name => $value)
		{
			if(array_key_exists($name, $css))
			{
				continue;
			}
			
			$colorCode = str_replace('#', '', $value);
			$isWhite = (strlen($colorCode) == 3 && strtolower($colorCode) == 'fff') || strtolower($colorCode) === 'ffffff';
			$border = $isWhite ? $lineEnd . $tab . $tab . '.btn-colorfield.vpf-colorfield-' . self::getColorFieldsCSSClass($name) . ' {border-color: #DDD !important}' : '';
			
			$css[$name] = $tab . $tab . '.vpf-colorfield-' . self::getColorFieldsCSSClass($name) . ' {background-color: ' . $value . ' !important}' . $border;
		}
		
		if(!empty($css))
		{
			$css = implode($lineEnd, $css);
			$doc->addStyleDeclaration($css);
		}
	}
	
	public static function getColorFieldsCSSClass($name)
	{
		$name = bin2hex($name);
		
		if (function_exists('iconv'))
		{
			$name = iconv(mb_detect_encoding($name, mb_detect_order(), true), "UTF-8", $name);
		}
		
		// $name = str_replace(array(' ', '&nbsp;'), '-', $name);
		// $name = preg_replace("/[^a-zA-Z0-9 -]/", "", $name);  //allow only a-Z, integers and dashes
		// $name = preg_replace('/-{2,}/', '-', $name); // remove any double dashes that we resulted with from the previous steps
		// $name = strtolower($name);
		
		return $name;
	}
	
	public static function getTabsData($product, $field_position = 'normal')
	{
		$titles = array();
		$displays = array();
		
		if(!empty($product->product_desc))
		{
			$titles['tab-product-desc'] = vmText::_('COM_VIRTUEMART_PRODUCT_DESC_TITLE');
			$displays['tab-product-desc'] = '<div class="description">' . $product->product_desc . '</div>';
		}
		
		$fields = isset($product->customfieldsSorted[$field_position]) ? $product->customfieldsSorted[$field_position] : array();
		
		if(!empty($fields))
		{
			foreach($fields as $field)
			{
				if($field->is_hidden || in_array($field->field_type, array('R', 'Z', 'G')))
				{
					continue;
				}
				
				$field_display = '<div class="tab-field field-type-' .  $field->field_type . '">' . $field->display . '</div>';
				
				if(!$field->show_title)
				{
					if(isset($displays['tab-product-desc']))
					{
						$displays['tab-product-desc'] .= $field_display;
					}
				}
				else
				{
					$tab_id = 'tab-field-id-' . $field->virtuemart_custom_id;
					
					if(isset($titles[$tab_id]) && isset($displays[$tab_id]))
					{
						$displays[$tab_id] .= $field_display;
					}
					else
					{
						$titles[$tab_id] = vmText::_($field->custom_title);
						$displays[$tab_id] = $field_display;
					}
				}
			}
		}
		
		$tabs = array();
		$tabs['titles'] = $titles;
		$tabs['displays'] = $displays;

		return $tabs;
	}
	
	public static function getRelatedFields($product)
	{
		$related_products = array();
		$related_categories = array();
		
		if(!empty($product->customfieldsSorted))
		{
			foreach($product->customfieldsSorted as $fields)
			{
				if(!empty($fields))
				{
					foreach($fields as $field)
					{
						if($field->field_type == 'R')
						{
							$related_products[] = $field;
						}
						elseif($field->field_type == 'Z')
						{
							$related_categories[] = $field;
						}
					}
				}
			}
		}
		
		$related = array();
		$related['products'] = $related_products;
		$related['categories'] = $related_categories;
		
		return $related;
	}
	
	public static function readableColour($background, $forDark = '#FFFFFF', $forLight = '#000000')
	{
		$background = trim(str_replace('#', '', $background));
		
		if(strlen($background) == 3)
		{
			$r = hexdec(str_repeat(substr($background, 0, 1), 2));
			$g = hexdec(str_repeat(substr($background, 1, 1), 2));
			$b = hexdec(str_repeat(substr($background, 2, 1), 2));	
		}
		else
		{
			$r = hexdec(substr($background, 0, 2));
			$g = hexdec(substr($background, 2, 2));
			$b = hexdec(substr($background, 4, 2));			
		}

		if(($r + $g + $b) > 382)
		{
			return $forLight;
		}
		else
		{
			return $forDark;
		}
	}
	
	public static function getStockText($product) 
	{
		$stockhandle   = VmConfig::get('stockhandle', 'none');
		$stock_level   = ($product->product_in_stock - $product->product_ordered);
		$reorder_level = $product->low_stock_notification;
		
		$class         = 'normal-stock text-success';
		$text          = JText::_('PLG_SYSTEM_VPFRAMEWORK_PRODUCT_IN_STOCK');
		$tip           = vmText::_('COM_VIRTUEMART_STOCK_LEVEL_DISPLAY_NORMAL_TIP');
		
		if ($stockhandle != 'none' && $stock_level <= 0) 
		{
			$class = 'no-stock text-danger';
			$text  = JText::_('PLG_SYSTEM_VPFRAMEWORK_PRODUCT_OUT_OF_STOCK');
			$tip   = vmText::_('COM_VIRTUEMART_STOCK_LEVEL_DISPLAY_OUT_TIP');
		}
		elseif ($stockhandle != 'none' && $stock_level <= $reorder_level) 
		{
			$class = 'low-stock text-warning';
			$text  = JText::sprintf('PLG_SYSTEM_VPFRAMEWORK_PRODUCT_LOW_STOCK', $stock_level);
			$tip   = vmText::_('COM_VIRTUEMART_STOCK_LEVEL_DISPLAY_LOW_TIP');
		}
		
		$stock = new stdClass;
		$stock->text = $text;
		$stock->tip = $tip;
		$stock->class = $class;
		
		return $stock;
	}
	
	public static function getRating($virtuemart_product_id)
	{	
		if(!isset(static::$ratings[$virtuemart_product_id]))
		{
			$rating = new stdClass;
			$rating->rating = 0;
			$rating->count = 0;
			$version = self::getVersion();
			
			$db = JFactory::getDbo();
			$query = $db->getQuery(true);
			
			if(version_compare($version, '3.0.18', 'ge'))
			{
				$query->select('COUNT(`virtuemart_rating_vote_id`) AS count, SUM(`vote`) AS rating')
				      ->from('#__virtuemart_rating_votes')
				      ->where('virtuemart_product_id = ' . (int) $virtuemart_product_id);
			}
			else
			{
				$query->select('SUM(rates) AS rating, SUM(ratingcount) AS count')
				      ->from('#__virtuemart_ratings')
				      ->where('virtuemart_product_id = ' . (int) $virtuemart_product_id)
				      ->where('published = 1');
			}

			try
			{
				$db->setQuery($query);
				$total = $db->loadObject();
			} 
			catch(Exception $e) 
			{
				JFactory::getApplication()->enqueueMessage($e->getMessage(), 'error');
				return $rating;
			}
		
			if(!empty($total) && !empty($total->rating) && !empty($total->count))
			{
				$rating->rating = ($total->rating / $total->count);
				$rating->count = $total->count;
			}
			
			static::$ratings[$virtuemart_product_id] = $rating;
		}
		
		return static::$ratings[$virtuemart_product_id];
	}
	
	public static function getVersion()
	{
		$version = class_exists('vmVersion') && !empty(vmVersion::$RELEASE) ? vmVersion::$RELEASE : '3.0';
		
		return $version;
	}
	
	public static function getReviewCount($virtuemart_product_id)
	{
		if(!isset(static::$reviewCounts[$virtuemart_product_id]))
		{
			$db = JFactory::getDbo();
			$query = $db->getQuery(true)
			            ->select('COUNT(virtuemart_rating_review_id)')
			            ->from('#__virtuemart_rating_reviews')
			            ->where('virtuemart_product_id = ' . (int) $virtuemart_product_id)
			            ->where('published = 1');
			try
			{
				$db->setQuery($query);
				$count = $db->loadResult();
			} 
			catch(Exception $e) 
			{
				JFactory::getApplication()->enqueueMessage($e->getMessage(), 'error');
				return 0;
			}
			
			static::$reviewCounts[$virtuemart_product_id] = $count;
		}
		
		return static::$reviewCounts[$virtuemart_product_id];
	}
	
	public static function addValidator()
	{
		if(static::$validatorLoaded)
		{
			return;
		}
		
		$guest = JFactory::getUser()->guest;

		// Implement Joomla's form validation
		JHtml::_('behavior.formvalidator');

		$regfields = array('username', 'name');
		if($guest)
		{
			$regfields[] = 'password';
			$regfields[] = 'password2';
		}

		$jsRegfields = implode("','", $regfields);
		$js = "
		function myValidator(f, r) {
		    r = !r ? false : r;
		    var $ = jQuery.noConflict();
		    var regfields = ['" . $jsRegfields . "'];
		    for (i = 0; i < regfields.length; i++) {
		        var elem = $('#' + regfields[i] + '_field');
		        if (r == true) {
		            elem.attr('required', 'require').addClass('required');
		        } else {
		            elem.removeAttr('required').removeClass('required');
		        }
		    }
		    $('label.virtuemart_state_id').attr('for', 'virtuemart_state_id_field');
		    var reCaptchaWrapper = $('#recaptcha_wrapper');
		    if (document.formvalidator.isValid(f)) {
		        if (reCaptchaWrapper.length && reCaptchaWrapper.is(':hidden') && (r == true)) {
		            $('#recaptcha_wrapper').removeClass('hide').show();
		        } else {
		            return true;
		        }
		    } else {
		        if ($('select#virtuemart_country_id_field').hasClass('invalid')) {
		            $('select#virtuemart_country_id_field').parents('.form-group').addClass('has-error');
		        }
		        if ($('select#virtuemart_state_id_field').hasClass('invalid')) {
		            $('select#virtuemart_state_id_field').parents('.form-group').addClass('has-error');
		        }
		        if (reCaptchaWrapper.length && reCaptchaWrapper.is(':hidden') && (r == true)) {
		            $('#recaptcha_wrapper').removeClass('hide').show();
		        }
		    }
		    return false;
		}";

		$get = new ReflectionMethod('vmJsApi', 'getJScripts');
		$remove = new ReflectionMethod('vmJsApi', 'removeJScript');
		
		if($get->isStatic() && $remove->isStatic())
		{
			$loadedScripts = vmJsApi::getJScripts();
			if(array_key_exists('vm.validator', $loadedScripts))
			{
				vmJsApi::removeJScript('vm.validator');
			}
		}

		vmJsApi::addJScript('vm.validator', $js);
		static::$validatorLoaded = true;
	}
	
	public static function loadjQueryUI()
	{
		$doc = JFactory::getDocument();
		
		if(!VmConfig::get('jquery', true))
		{
			return;
		}
		
		if(VmConfig::get('google_jquery', true))
		{
			$doc->addScript('//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js');
		}
		else
		{
			$template = plgSystemVPFrameworkHelper::getTemplate();
			$template_file = JPath::clean($template->path . '/js/jquery-ui.min.js');
			$vm_file = JPath::clean(JPATH_SITE . '/components/com_virtuemart/assets/js/jquery-ui.min.js');
			
			if(file_exists($template_file))
			{
				$doc->addScript($template->uri . '/js/jquery-ui.min.js');
			}
			elseif(file_exists($vm_file))
			{
				$doc->addScript(JUri::base(true) . '/components/com_virtuemart/assets/js/jquery-ui.min.js');
			}
		}
		
		// Load UI Tooltip Fix
		JHtml::script('vpframework/fix-ui-conflict.js', false, true);
	}
	
	public static function hasCartAttribute($product)
	{
		$product_id = (int) $product->virtuemart_product_id;
		
		if(!isset(self::$attributes[$product_id]))
		{
			$hasAttributes = false;
			
			if(!empty($product->customfieldsSorted['addtocart']))
			{
				foreach($product->customfieldsSorted['addtocart'] as $attribute)
				{
					if(empty($attribute->is_hidden))
					{
						$hasAttributes = true;
						break;
					}
				}
			}

			self::$attributes[$product_id] = $hasAttributes;
		}
		
		return self::$attributes[$product_id];
	}
	
	public static function escape($string)
	{
		return htmlspecialchars(strip_tags($string), ENT_COMPAT, 'UTF-8');
	}
}