<?php
/**
 *---------------------------------------------------------------------------------------
 * @package      VP Conversion Tracking - Joomla! System Plugin
 * @subpackage   For VirtueMart 3+
 *---------------------------------------------------------------------------------------
 * @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;

/**
* VPCT Helper Tracker class
* 
* @since 1.0
*/
class VPCTHelperTracker extends JObject
{
	protected $app;
	
	protected $doc;
	
	protected $headStringToReplace = '<meta name="vpct" content="head-trackers" />';
	
	protected $pageStringToReplace = '<meta name="vpct" content="page-trackers" />';
	
	protected $inHead = array();
	
	protected $inPage = array();
	
	protected $inBody = array();
	
	protected $order = null;
	
	protected static $instance = null;
	
	protected static $mustache = null;
	
	
	public function __construct($order)
	{
		$this->app = JFactory::getApplication();
		$this->doc = JFactory::getDocument();
		
		if ($order)
		{
			$this->order = $order;
		}
	}
	
	/**
	* Method to get an instance of the the VPCTHelperTracker class
	* 
	* @return  object  VPCTHelperTracker class object
	*/
	public static function getInstance($order)
	{
		if (self::$instance === null)
		{
			self::$instance = new self($order);
		}
		
		return self::$instance;
	}
	
	public function placeHeadStringToReplace()
	{
		if ($this->headStringToReplace)
		{
			$this->doc->addCustomTag($this->headStringToReplace);
		}
	}
	
	public function addTracker($contents, $location = 'HEAD', $parse = true)
	{
		$location = strtoupper($location);
		
		if (!empty($contents) && is_string($contents))
		{
			if ($parse)
			{
				$contents = $this->parse($contents);
				
				if ($contents === false)
				{
					$this->setError($this->getError());
					return false;
				}
			}
			
			if ($location == 'HEAD')
			{
				$this->inHead[] = $contents;
			}
			elseif ($location == 'PAGE')
			{
				$this->inPage[] = $contents;
			}
			elseif ($location == 'BODY')
			{
				$this->inBody[] = $contents;
			}
		}
		
		return true;
	}
	
	public function parse($contents)
	{
		if ($this->order === null)
		{
			$this->order = plgSystemVPConversionTrackingHelper::getInstance()->getOrder();
		}
		
		if ($this->order === false)
		{
			$this->setError(__METHOD__ . '() failed. No order data available.');
			return false;
		}
		
		// Get Mustache instance
		if (!$mustache = $this->getMustache())
		{
			$this->setError($this->getError());
			return false;
		}
		
		if ($this->order instanceof VPCTHelperOrder)
		{
			$this->order = new VPCTHelperOrderdata($this->order, $mustache);
		}

		if ($this->order instanceof VPCTHelperOrderdata)
		{
			$contents = $mustache->render($contents, $this->order);
		}
		
		return $contents;
	}
	
	public function loadTrackers()
	{
		$inHead = '';
		$inBody = '';
		$inPage = '';
		
		if (!empty($this->inHead))
		{
			$inHead = implode(PHP_EOL, $this->inHead);
			$this->inHead = array();
		}
		
		if (!empty($this->inBody))
		{
			$inBody = implode(PHP_EOL, $this->inBody);
			$this->inBody = array();
		}
		
		if (!empty($this->inPage))
		{
			$inPage = implode(PHP_EOL, $this->inPage);
			$this->inPage = array();
		}
		
		// Get head, body and suffix buffers
		list($head, $body, $suffix) = $this->getBody();
		
		if (!empty($inPage) && strpos($body, $this->pageStringToReplace) === false)
		{
			$inBody = $inPage . PHP_EOL . $inBody;
			$inPage = '';
		}

		if (!empty($head) && strpos($head, $this->headStringToReplace) !== false)
		{
			// Replace in body element
			$head = str_replace($this->headStringToReplace, $inHead, $head);
			$inHead = '';
		}
		
		// Get correct body closure tag
		$bodyClosure = (strpos($body, '</ body>') !== false) ? '</ body>' : '</body>';
		
		// Prepare body closure replacer
		$inBody = !empty($inBody) ? ($inBody . PHP_EOL . $bodyClosure) : $bodyClosure;
		
		// Replace body elements
		$body = str_replace(array($this->headStringToReplace, $this->pageStringToReplace, $bodyClosure), array($inHead, $inPage, $inBody), $body);
		
		// Rebuild body buffer
		$html = $head . $body . $suffix;
		
		// Set body buffer
		$this->app->setBody($html);
	}
	
	public function addShopperApproved($sa_site_id, $forcecomments = true, $emailAll = true, $location = 'BODY')
	{
		$sa_site_id = (int) $sa_site_id;
		
		if (empty($sa_site_id))
		{
			$this->setError('Invalid Shopper Approved site ID.');
			return false;
		}
		
		$doc         = JFactory::getDocument();
		$tab         = $doc->_getTab();
		$lineEnd     = $doc->_getLineEnd();
		$script      = $lineEnd;
		$sa_products = array();
		$sa_values   = array();
		
		if (!empty($this->order->items))
		{
			foreach($this->order->items as $item)
			{
				$sa_products[$item->virtuemart_order_item_id] = $item->order_item_name;
			}
		}
		
		$sa_values['site']    = $sa_site_id;
		$sa_values['orderid'] = utf8_encode($this->order->order_number);
		
		if (!empty($this->order->details) && !empty($this->order->details['BT']))
		{
			$billing_address    = $this->order->details['BT'];
			
			$customer_name      = !empty($billing_address->first_name) ? $billing_address->first_name : '';
			$customer_name      = !empty($billing_address->middle_name) ? $customer_name . ' ' . $billing_address->middle_name : $customer_name;
			$customer_name      = !empty($billing_address->last_name) ? $customer_name . ' ' . $billing_address->last_name : $customer_name;
			
			$sa_values['name']  = utf8_encode(trim($customer_name));
			$sa_values['email'] = !empty($billing_address->email) ? utf8_encode($billing_address->email) : '';
		}
		
		$sa_values['forcecomments'] = (int) $forcecomments;
		$sa_values['emailAll']      = (int) $emailAll;
		
		$script .= $tab . '<!-- Shopper Approved Survey and Tracking Code Snippet -->' . $lineEnd;
		$script .= $tab . '<script type="text/javascript">' . $lineEnd;
		
		if (!empty($sa_products))
		{
			$sa_products = array_map('utf8_encode', $sa_products);
			$script .= $tab . $tab . 'var sa_products = ' . json_encode($sa_products, JSON_UNESCAPED_UNICODE) . ';' . $lineEnd;
		}
		
		if (!empty($sa_values))
		{
			$script .= $tab . $tab . 'var sa_values = ' . json_encode($sa_values, JSON_UNESCAPED_UNICODE) . ';' . $lineEnd;
		}
		
		$script .= $tab . $tab . 'function saLoadScript(src) {' . $lineEnd;
		$script .= $tab . $tab . $tab . 'var js = window.document.createElement("script");' . $lineEnd;
		$script .= $tab . $tab . $tab . 'js.src = src;' . $lineEnd;
		$script .= $tab . $tab . $tab . 'js.type = "text/javascript";' . $lineEnd;
		$script .= $tab . $tab . $tab . 'document.getElementsByTagName("head")[0].appendChild(js);' . $lineEnd;
		$script .= $tab . $tab . '};' . $lineEnd;
		$script .= $tab . $tab . 'var d = new Date();' . $lineEnd;
		$script .= $tab . $tab . 'if (d.getTime() - 172800000 > 1452717358000) saLoadScript("//www.shopperapproved.com/thankyou/rate/' . $sa_site_id . '.js");' . $lineEnd;
		$script .= $tab . $tab . 'else saLoadScript("//direct.shopperapproved.com/thankyou/rate/' . $sa_site_id . '.js?d=" + d.getTime());' . $lineEnd;
		
		$script .= $tab . '</script>';
		
		if (!$this->addTracker($script, $location, false))
		{
			$this->setError($this->getError());
			return false;
		}
		
		return true;
	}
	
	public function addGoogleTrackers(&$params, $captureConversion)
	{
		$input                    = JFactory::getApplication()->input;
		$enable_ecommerce         = $params->get('enable_google_ecommerce');
		$analytics_method         = $params->get('analytics_method', 'analytics');
		$ga4                      = (int) $params->get('ga4', 0);
		$global_installed         = (int) $params->get('google_analytics_loaded');
		$install_pageview         = (int) $params->get('load_google_analytics_pageview');
		$track_productview        = (int) $params->get('track_product_view', 0);
		$isProductPage            = strtolower($input->getCmd('option')) == 'com_virtuemart' && strtolower($input->getCmd('view')) == 'productdetails';
		$trackProductView         = !$global_installed && $install_pageview && $track_productview && $isProductPage;
		$product_id               = (int) $input->getInt('virtuemart_product_id', 0);
		$analytics_client_id      = $params->get('google_analytics_client_id', '');
		$analytics_client_id      = trim($analytics_client_id);
		$analytics_gtm_id         = $params->get('analytics_gtm_container_id', '');
		$analytics_gtm_id         = trim($analytics_gtm_id);
		$enhanced_ecommerce       = (int) $params->get('google_ecommerce_enhanced');
		$enable_adwords           = $params->get('enable_adwords_tracking');
		$adwords_method           = $params->get('adwords_method', 'gtag');
		$adwords_installed        = (int) $params->get('global_adwords_installed');
		$install_adwords          = (int) $params->get('install_global_adwords');
		$adwords_conversion_id    = $params->get('adwords_conversion_id');
		$adwords_conversion_id    = trim($adwords_conversion_id);
		$adwords_conversion_label = $params->get('adwords_conversion_label');
		$adwords_conversion_label = trim($adwords_conversion_label);
		$adwords_gtm_id           = $params->get('adwords_gtm_container_id', '');
		$adwords_gtm_id           = trim($adwords_gtm_id);
		$analytics_gtm_installed  = false;
		$analytics_gtm_conversion = false;
		
		$currency            = $params->get('google_ecommerce_currency');
		$location            = $params->get('google_ecommerce_location', 'HEAD');
		$doc                 = JFactory::getDocument();
		$tab                 = $doc->_getTab();
		$lineEnd             = $doc->_getLineEnd();
		$global_snippets     = '';
		$snippets            = '';
		$gtag_script_url_id  = null;
		$tracking_for        = array('global' => array(), 'gtag' => array(), 'conversion' => array());
		$dataLayerName       = 'globalDataLayer';
		
		if ($enable_ecommerce)
		{
			if (($analytics_method == 'analytics' || $analytics_method == 'gtag'))
			{
				if (!$global_installed && empty($analytics_client_id))
				{
					$this->setError(__METHOD__ . '() failed. Missing Google Analytics Client ID for Ecommerce Tracking.');
					return false;
				}
				
				// For analytics.js
				if ($analytics_method == 'analytics')
				{
					if (!$global_installed && ($install_pageview || $captureConversion))
					{
						$global_snippets .= $tab . $tab . "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){" . $lineEnd;
						$global_snippets .= $tab . $tab . "(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o)," . $lineEnd;
						$global_snippets .= $tab . $tab . "m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)" . $lineEnd;
						$global_snippets .= $tab . $tab . "})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');" . $lineEnd;
						$global_snippets .= $lineEnd;
						$global_snippets .= $tab . $tab . "ga('create', '" . $analytics_client_id . "', 'auto');" . $lineEnd;
						$global_snippets .= $tab . $tab . "ga('send', 'pageview');" . $lineEnd;
						
						$tracking_for['global'][] = 'Google Analytics';
					}
					
					if ($captureConversion)
					{
						if (!($analytics_conversion_snippet = $this->getAnalyticsConversionSnippet($analytics_client_id, $enhanced_ecommerce, $currency, $location)))
						{
							return false;
						}
						
						$snippets .= $tab . $tab . $analytics_conversion_snippet . $lineEnd;
						
						$tracking_for['conversion'][] = 'Google Analytics';
					}
				}
				// For gtag.js
				else
				{
					if (!$global_installed && ($install_pageview || $captureConversion))
					{
						$gtag_script_url_id = $analytics_client_id;
						
						$global_snippets .= $tab . $tab . "window.dataLayer = window.dataLayer || [];" . $lineEnd;
						$global_snippets .= $tab . $tab . "function gtag(){dataLayer.push(arguments);}" . $lineEnd;
						$global_snippets .= $tab . $tab . "gtag('js', new Date());" . $lineEnd;
						$global_snippets .= $lineEnd;
						$global_snippets .= $tab . $tab . "gtag('config', '" . $analytics_client_id . "');" . $lineEnd;
						
						$tracking_for['global'][] = 'Google Analytics';
						$tracking_for['gtag'][] = 'Google Analytics';
					}
					
					if ($captureConversion)
					{
						if ($ga4)
						{
							if (!($gtag_conversion_snippet = $this->getGA4GtagConversionSnippet($currency)))
							{
								return false;
							}
							
							$tracking_for['conversion'][] = 'Google Analytics 4';
						}
						else
						{
							if (!($gtag_conversion_snippet = $this->getGtagConversionSnippet($enhanced_ecommerce, $currency)))
							{
								return false;
							}
							
							$tracking_for['conversion'][] = 'Google Analytics';
						}
						
						$snippets .= $tab . $tab . $gtag_conversion_snippet . $lineEnd;
					}
				}
			}
			// For Google Tag Manager (GTM)
			else
			{
				if (!$global_installed && empty($analytics_gtm_id))
				{
					$this->setError(__METHOD__ . '() failed. Missing Google Tag Manager Container ID for Ecommerce Tracking.');
					return false;
				}
				
				if (!$global_installed && ($install_pageview || $captureConversion))
				{
					$global_snippets .= $tab . $tab . "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':" . $lineEnd;
					$global_snippets .= $tab . $tab . "new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0]," . $lineEnd;
					$global_snippets .= $tab . $tab . "j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=" . $lineEnd;
					$global_snippets .= $tab . $tab . "'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);" . $lineEnd;
					$global_snippets .= $tab . $tab . "})(window,document,'script','" . $dataLayerName . "','" . $analytics_gtm_id . "');" . $lineEnd;
					
					$noscript  = $tab . '<!-- Google Tag Manager (noscript) -->' . $lineEnd;
					$noscript .= $tab . '<noscript>' . $lineEnd;
					$noscript .= $tab . $tab . '<iframe src="https://www.googletagmanager.com/ns.html?id=' . $analytics_gtm_id . '" height="0" width="0" style="display:none;visibility:hidden"></iframe>' . $lineEnd;
					$noscript .= $tab . '</noscript>' . $lineEnd;
					
					if (!$this->addTracker($noscript, 'BODY', false))
					{
						$this->setError($this->getError());
						return false;
					}
					
					$tracking_for['global'][] = 'Google Analytics';
					
					$analytics_gtm_installed = true;
				}
				elseif ($global_installed)
				{
					$dataLayerName = 'dataLayer';
				}
				
				if ($captureConversion)
				{
					if ($ga4)
					{
						if (!($gtm_conversion_snippet = $this->getGA4GtmConversionSnippet($currency, $dataLayerName)))
						{
							return false;
						}
						
						$tracking_for['conversion'][] = 'Google Analytics 4';
					}
					else
					{
						if (!($gtm_conversion_snippet = $this->getGtmConversionSnippet($enhanced_ecommerce, $currency, $dataLayerName)))
						{
							return false;
						}
						
						$tracking_for['conversion'][] = 'Google Analytics';
					}
					
					$snippets .= $tab . $tab . $gtm_conversion_snippet . $lineEnd;
					
					$analytics_gtm_conversion = true;
				}
			}
		}
		
		// Google Adwrods Tags
		if ($enable_adwords)
		{
			// For gtag.js
			if ($adwords_method == 'gtag')
			{
				if (empty($adwords_conversion_id))
				{
					$this->setError(__METHOD__ . '() failed. Missing Google Adwords Conversion ID.');
					return false;
				}
				
				if (empty($adwords_conversion_label))
				{
					$this->setError(__METHOD__ . '() failed. Missing Google Adwords Conversion Label.');
					return false;
				}
				
				if (!$adwords_installed && ($install_adwords || $captureConversion))
				{
					if (empty($gtag_script_url_id))
					{
						$gtag_script_url_id = $adwords_conversion_id;
						
						$global_snippets .= $tab . $tab . "window.dataLayer = window.dataLayer || [];" . $lineEnd;
						$global_snippets .= $tab . $tab . "function gtag(){dataLayer.push(arguments);}" . $lineEnd;
						$global_snippets .= $tab . $tab . "gtag('js', new Date());" . $lineEnd;
						$global_snippets .= $lineEnd;
						
						$tracking_for['gtag'][] = 'Google Adwords';
					}
					
					$global_snippets .= $tab . $tab . "gtag('config', '" . $adwords_conversion_id . "');" . $lineEnd;
					
					$tracking_for['global'][] = 'Google Adwords';
				}
				
				if ($captureConversion)
				{
					if (!($gtag_adwords_conversion_snippet = $this->getGtagAdwordsConversionSnippet($currency, $adwords_conversion_id, $adwords_conversion_label)))
					{
						return false;
					}
					
					$snippets .= $tab . $tab . $gtag_adwords_conversion_snippet . $lineEnd;
					
					$tracking_for['conversion'][] = 'Google Adwords';
				}
				
			}
			// For Google Tag Manager
			else
			{
				if (!$adwords_installed && empty($adwords_gtm_id))
				{
					$this->setError(__METHOD__ . '() failed. Missing Google Tag Manager Container ID for Adwords Conversion Tracking.');
					return false;
				}
				
				$adwordsDataLayerName = $dataLayerName;
				
				if (!$adwords_installed && ($install_adwords || $captureConversion) && (!$analytics_gtm_installed || $analytics_gtm_id != $adwords_gtm_id))
				{
					$adwordsDataLayerName = 'adwordsDataLayer';
					
					if ($analytics_gtm_installed)
					{
						$global_snippets .= $lineEnd;
					}
					
					$global_snippets .= $tab . $tab . "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':" . $lineEnd;
					$global_snippets .= $tab . $tab . "new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0]," . $lineEnd;
					$global_snippets .= $tab . $tab . "j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=" . $lineEnd;
					$global_snippets .= $tab . $tab . "'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);" . $lineEnd;
					$global_snippets .= $tab . $tab . "})(window,document,'script','" . $adwordsDataLayerName . "','" . $adwords_gtm_id . "');" . $lineEnd;
					
					$noscript  = $tab . '<!-- Google Tag Manager (noscript) -->' . $lineEnd;
					$noscript .= $tab . '<noscript>' . $lineEnd;
					$noscript .= $tab . $tab . '<iframe src="https://www.googletagmanager.com/ns.html?id=' . $adwords_gtm_id . '" height="0" width="0" style="display:none;visibility:hidden"></iframe>' . $lineEnd;
					$noscript .= $tab . '</noscript>' . $lineEnd;
					
					if (!$this->addTracker($noscript, 'BODY', false))
					{
						return false;
					}

					$tracking_for['global'][] = 'Google Adwords';
				}
				elseif ($adwords_installed)
				{
					$adwordsDataLayerName = 'dataLayer';
				}
				
				if ($captureConversion && (!$analytics_gtm_conversion || $adwordsDataLayerName != $dataLayerName))
				{
					// Adwords should be captured using Enhanced Ecommerce dataLayer variables in Google Tag Manager
					if ($ga4)
					{
						if (!($gtm_adwords_conversion_snippet = $this->getGA4GtmConversionSnippet($currency, $adwordsDataLayerName)))
						{
							return false;
						}
					}
					else
					{
						if (!($gtm_adwords_conversion_snippet = $this->getGtmConversionSnippet($enhanced_ecommerce, $currency, $adwordsDataLayerName)))
						{
							return false;
						}
					}
					
					$snippets .= $tab . $tab . $gtm_adwords_conversion_snippet . $lineEnd;
					
					$tracking_for['conversion'][] = 'Google Adwords';
				}
			}
		}
		
		$script = '';
		
		if (!empty($gtag_script_url_id))
		{
			$script .= $lineEnd . $tab . '<!-- Global site tag (gtag.js) - ' . implode(' and ', $tracking_for['gtag']) . ' -->' . $lineEnd;
			$script .= $tab . '<script async src="https://www.googletagmanager.com/gtag/js?id=' . $gtag_script_url_id . '"></script>';
		}
		
		if (!empty($global_snippets))
		{
			$script .= $lineEnd . $tab . '<!-- Global site tracking tag - ' . implode(' and ', $tracking_for['global']) . ' -->' . $lineEnd;
			$script .= $tab . '<script type="text/javascript">' . $lineEnd;
			$script .= $global_snippets;
			$script .= $tab . '</script>';
		}
		
		if (!empty($snippets))
		{
			$script .= $lineEnd . $tab . '<!-- Conversion tracking tag - ' . implode(' and ', $tracking_for['conversion']) . ' -->' . $lineEnd;
			$script .= $tab . '<script type="text/javascript">' . $lineEnd;
			$script .= $snippets;
			$script .= $tab . '</script>';
		}
		
		if (!empty($script) && !$this->addTracker($script, $location, false))
		{
			return false;
		}

		return true;
	}
	
	public function addFacebookPixels(&$params, $captureConversion)
	{
		$input              = JFactory::getApplication()->input;
		$installed          = (int) $params->get('base_fb_pixel_installed', 0);
		$install_base_pixel = (int) $params->get('install_base_fb_pixel', 1);
		$track_pageview     = (int) $params->get('track_fb_product_view', 1);
		$isProductPage      = strtolower($input->getCmd('option')) == 'com_virtuemart' && strtolower($input->getCmd('view')) == 'productdetails';
		$trackProductView   = $track_pageview && $isProductPage;
		$product_id         = (int) $input->getInt('virtuemart_product_id', 0);
		$pixel_id           = $params->get('fb_pixel_id', '');
		$pixel_id           = trim($pixel_id);
		$currency_type      = $params->get('fb_currency', 'user');
		$location           = $params->get('fb_location', 'HEAD');
		$doc                = JFactory::getDocument();
		$tab                = $doc->_getTab();
		$lineEnd            = $doc->_getLineEnd();
		$snippet            = '';
		
		if (!$installed && ($install_base_pixel || $captureConversion || $trackProductView))
		{
			if (empty($pixel_id))
			{
				$this->setError(__METHOD__ . '() failed. Missing Facebook Pixel ID for Ads Conversion Tracking.');
				return false;
			}
			
			$snippet .= $tab . $tab . "!function(f,b,e,v,n,t,s)" . $lineEnd;
			$snippet .= $tab . $tab . "{if (f.fbq)return;n=f.fbq=function(){n.callMethod?" . $lineEnd;
			$snippet .= $tab . $tab . "n.callMethod.apply(n,arguments):n.queue.push(arguments)};" . $lineEnd;
			$snippet .= $tab . $tab . "if (!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';" . $lineEnd;
			$snippet .= $tab . $tab . "n.queue=[];t=b.createElement(e);t.async=!0;" . $lineEnd;
			$snippet .= $tab . $tab . "t.src=v;s=b.getElementsByTagName(e)[0];" . $lineEnd;
			$snippet .= $tab . $tab . "s.parentNode.insertBefore(t,s)}(window, document,'script'," . $lineEnd;
			$snippet .= $tab . $tab . "'https://connect.facebook.net/en_US/fbevents.js');" . $lineEnd;
			$snippet .= $lineEnd;
			$snippet .= $tab . $tab . "fbq('init', '" . $pixel_id . "');" . $lineEnd;
			$snippet .= $tab . $tab . "fbq('track', 'PageView');" . $lineEnd;
			$snippet .= $lineEnd;
			
			$noscript  = $tab . '<!-- Facebook Pixel Code (noscript) -->' . $lineEnd;
			$noscript .= $tab . '<noscript>' . $lineEnd;
			$noscript .= $tab . $tab . '<iframe src="https://www.facebook.com/tr?id=' . $pixel_id . '&ev=PageView&noscript=1" height="1" width="1" style="display:none;visibility:hidden"></iframe>' . $lineEnd;
			$noscript .= $tab . '</noscript>' . $lineEnd;
			
			if (!$this->addTracker($noscript, 'BODY', false))
			{
				return false;
			}
		}
		
		if ($trackProductView && $product_id > 0)
		{
			$productModel = VmModel::getModel('product');
			$product      = $productModel->getProduct($product_id, true, true, true, 1);
			
			if (!empty($product))
			{
				$content = new stdClass;
				
				$content->content_ids = array();
				$content->content_ids[] = !empty($product->product_sku) ? $this->escape($product->product_sku) : (string) $product->virtuemart_product_id;
				$content->content_name = $this->escape($product->product_name);
				$content->content_type = 'product';
				
				if (!empty($product->prices['salesPrice']))
				{
					$currency           = CurrencyDisplay::getInstance();
					$user_currency_id   = $currency->getCurrencyForDisplay();
					$vendor_currency_id = $currency->_vendorCurrency;
					
					if ($currency_type == 'user')
					{
						$content->value    = (float) $currency->roundForDisplay($product->prices['salesPrice']);
						$content->currency = ShopFunctions::getCurrencyByID($user_currency_id, 'currency_code_3');
					}
					else
					{
						$content->value    = (float) $currency->roundForDisplay($product->prices['salesPrice'], $vendor_currency_id);
						$content->currency = ShopFunctions::getCurrencyByID($vendor_currency_id, 'currency_code_3');
					}
				}
				
				$snippet .= $tab . $tab . "fbq('track', 'ViewContent', " . json_encode($content, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . ");" . $lineEnd;
			}
		}
		
		if ($captureConversion)
		{
			if (!($facebook_conversion_snippet = $this->getFacebookConversionSnippet($currency_type)))
			{
				return false;
			}
			
			$snippet .= $tab . $tab . $facebook_conversion_snippet . $lineEnd;
		}
		
		if (!empty($snippet))
		{
			$script  = $lineEnd . $tab . '<!-- Facebook Pixel Conversion Tracking Tag -->' . $lineEnd;
			$script .= $tab . '<script type="text/javascript">' . $lineEnd;
			$script .= $snippet;
			$script .= $tab . '</script>';
			
			if (!$this->addTracker($script, $location, false))
			{
				return false;
			}
		}
		
		return true;
	}
	
	protected function getFacebookConversionSnippet($currency_type)
	{
		$order = is_object($this->order) ? clone($this->order) : $this->order;
		
		if (!($order instanceof VPCTHelperOrder))
		{
			$order = plgSystemVPConversionTrackingHelper::getInstance()->getOrder();
		}
		
		if (!$order || empty($order->virtuemart_order_id))
		{
			$this->setError(__METHOD__ . '() failed. No order data available.');
			return false;
		}
		
		$currency = $order->getCurrency($currency_type);
		
		if (empty($currency))
		{
			$this->setError(__METHOD__ . '() failed. Invalid Currency object.');
			return false;
		}
		
		$doc        = JFactory::getDocument();
		$tab        = $doc->_getTab();
		$lineEnd    = $doc->_getLineEnd();
		$contents   = array();
		$conversion = new stdClass;
		
		foreach($order->items as $item)
		{
			$content = new stdClass;
			
			$content->id       = !empty($item->order_item_sku) ? $this->escape($item->order_item_sku) : (string) $item->virtuemart_product_id;
			$content->name     = $this->escape($item->order_item_name);
			$content->category = $this->escape($item->category_name);
			
			if ($currency_type == 'user')
			{
				$content->item_price = (float) $currency->roundForDisplay($item->product_final_price, $order->user_currency_id);
				$content->quantity   = (int) $item->product_quantity;
			}
			else
			{
				$content->item_price = (float) $currency->roundForDisplay($item->product_final_price);
				$content->quantity   = (int) $item->product_quantity;
			}
			
			$contents[] = $content;
		}
		
		if ($currency_type == 'user')
		{
			$conversion->value    = (float) $currency->roundForDisplay($order->order_total, $order->user_currency_id);
			$conversion->currency = $this->escape($order->user_currency_code);
		}
		else
		{
			$conversion->value    = (float) $currency->roundForDisplay($order->order_total);
			$conversion->currency = (string) $this->escape($order->order_currency_code);
		}
		
		$conversion->contents     = $contents;
		$conversion->content_type = 'product';
		
		return "fbq('track', 'Purchase', " . json_encode($conversion, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . ");";
	}
	
	protected function getGtagAdwordsConversionSnippet($currency_type, $conversion_id, $conversion_label)
	{
		$order = is_object($this->order) ? clone($this->order) : $this->order;
		
		if (!($order instanceof VPCTHelperOrder))
		{
			$order = plgSystemVPConversionTrackingHelper::getInstance()->getOrder();
		}
		
		if (!$order || empty($order->virtuemart_order_id))
		{
			$this->setError(__METHOD__ . '() failed. No order data available.');
			return false;
		}
		
		$currency = $order->getCurrency($currency_type);
		
		if (empty($currency))
		{
			$this->setError(__METHOD__ . '() failed. Invalid Currency object.');
			return false;
		}
		
		$doc      = JFactory::getDocument();
		$tab      = $doc->_getTab();
		$lineEnd  = $doc->_getLineEnd();
		
		$conversion = new stdClass;
		
		$conversion->send_to = $this->escape($conversion_id) . '/' . $this->escape($conversion_label);
		
		if ($currency_type == 'user')
		{
			$conversion->value    = (string) $currency->roundForDisplay($order->order_total, $order->user_currency_id);
			$conversion->currency = $this->escape($order->user_currency_code);
		}
		else
		{
			$conversion->value    = (string) $currency->roundForDisplay($order->order_total);
			$conversion->currency = (string) $this->escape($order->order_currency_code);
		}
		
		$conversion->transaction_id = (string) (!empty($order->order_number)) ? $this->escape($order->order_number) : $order->virtuemart_order_id;
	
		return "gtag('event', 'conversion', " . json_encode($conversion, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . ");";
	}
	
	
	protected function getGtmConversionSnippet($enhanced, $currency_type, $dataLayerName)
	{
		$order = is_object($this->order) ? clone($this->order) : $this->order;
		
		if (!($order instanceof VPCTHelperOrder))
		{
			$order = plgSystemVPConversionTrackingHelper::getInstance()->getOrder();
		}
		
		if (!$order || empty($order->virtuemart_order_id))
		{
			$this->setError(__METHOD__ . '() failed. No order data available.');
			return false;
		}
		
		$currency = $order->getCurrency($currency_type);
		
		if (empty($currency))
		{
			$this->setError(__METHOD__ . '() failed. Invalid Currency object.');
			return false;
		}
		
		$doc      = JFactory::getDocument();
		$tab      = $doc->_getTab();
		$lineEnd  = $doc->_getLineEnd();
		$products = array();
		
		foreach($order->items as $item)
		{
			$product = new stdClass;
			
			$product->id       = !empty($item->order_item_sku) ? $this->escape($item->order_item_sku) : $item->virtuemart_product_id;
			$product->name     = $this->escape($item->order_item_name);
			$product->sku      = $this->escape($item->order_item_sku);
			$product->category = $this->escape($item->category_name);
			
			if ($enhanced)
			{
				$product->brand   = $this->escape($item->mf_name);
				$product->variant = '';
				
				JLoader::register('VirtueMartModelCustomfields', JPATH_ADMINISTRATOR . '/components/com_virtuemart/models/customfields.php');
				
				$product_attributes = VirtueMartModelCustomfields::CustomsFieldOrderDisplay($item, 'FE');
				$product_attributes = !empty($product_attributes) ? str_replace(array('<br />', '<br/>'), array('|[]|', '|[]|'), $product_attributes) : $product_attributes;
				
				if (!empty($product_attributes))
				{
					if (strpos($product_attributes, '|[]|'))
					{
						$product_attributes = explode('|[]|', $product_attributes);
					}
					else
					{
						$product_attributes = array($product_attributes);
					}
					
					foreach($product_attributes as $key => &$variant)
					{
						$variant = $this->escape($variant);
						$variant = trim($variant, ' ');
						
						if (str_replace(' ', '', $variant) == '')
						{
							unset($product_attributes[$key]);
						}
						else
						{
							$product_attributes[$key] = $variant;
						}
					}

					$product->variant = implode(', ', $product_attributes);
				}
			}
			
			if ($currency_type == 'user')
			{
				$product->price    = (string) $currency->roundForDisplay($item->product_final_price, $order->user_currency_id);
				$product->quantity = (int) $item->product_quantity;
				$product->currency = (string) $this->escape($order->user_currency_code);
			}
			else
			{
				$product->price    = (string) $currency->roundForDisplay($item->product_final_price);
				$product->quantity = (int) $item->product_quantity;
				$product->currency = (string) $this->escape($order->order_currency_code);
			}
			
			$products[] = $product;
		}
		
		$transaction = new stdClass;
		
		if ($enhanced)
		{
			$transaction->ecommerce           = new stdClass;
			$transaction->ecommerce->purchase = new stdClass;
			$actionField                      = new stdClass;
			
			$actionField->id          = (string) (!empty($order->order_number)) ? $this->escape($order->order_number) : $order->virtuemart_order_id;
			$actionField->affiliation = !empty($order->vendor->vendor_store_name) ? $this->escape($order->vendor->vendor_store_name) : $this->escape($order->vendor->vendor_name);
			
			if ($currency_type == 'user')
			{
				$actionField->revenue  = (string) $currency->roundForDisplay($order->order_total, $order->user_currency_id);
				$actionField->shipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax), $order->user_currency_id);
				$actionField->tax      = (string) $currency->roundForDisplay($order->order_billTaxAmount, $order->user_currency_id);
				$actionField->currency = $this->escape($order->user_currency_code);
			}
			else
			{
				$actionField->revenue  = (string) $currency->roundForDisplay($order->order_total);
				$actionField->shipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax));
				$actionField->tax      = (string) $currency->roundForDisplay($order->order_billTaxAmount);
				$actionField->currency = (string) $this->escape($order->order_currency_code);
			}
			
			$actionField->coupon = (string) $this->escape($order->coupon_code);
			
			$transaction->ecommerce->purchase->actionField = $actionField;
			$transaction->ecommerce->purchase->products    = $products;
		}
		else
		{
			$transaction->transactionId          = (string) (!empty($order->order_number)) ? $this->escape($order->order_number) : $order->virtuemart_order_id;
			$transaction->transactionAffiliation = !empty($order->vendor->vendor_store_name) ? $this->escape($order->vendor->vendor_store_name) : $this->escape($order->vendor->vendor_name);
			$transaction->transactionType        = 'sale';
			
			if ($currency_type == 'user')
			{
				$transaction->transactionTotal    = (string) $currency->roundForDisplay($order->order_total, $order->user_currency_id);
				$transaction->transactionShipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax), $order->user_currency_id);
				$transaction->transactionTax      = (string) $currency->roundForDisplay($order->order_billTaxAmount, $order->user_currency_id);
				$transaction->transactionCurrency = $this->escape($order->user_currency_code);
			}
			else
			{
				$transaction->transactionTotal    = (string) $currency->roundForDisplay($order->order_total);
				$transaction->transactionShipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax));
				$transaction->transactionTax      = (string) $currency->roundForDisplay($order->order_billTaxAmount);
				$transaction->transactionCurrency = (string) $this->escape($order->order_currency_code);
			}
			
			$transaction->transactionProducts = $products;
		}
		
		$snippet  = 'window.' . $dataLayerName . ' = window.' . $dataLayerName . ' || [];' . $lineEnd;
		$snippet .= $tab . $tab . $dataLayerName . '.push(' . json_encode($transaction, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . ');';
		
		return $snippet;
	}
	
	
	protected function getGA4GtmConversionSnippet($currency_type, $dataLayerName)
	{
		$order = is_object($this->order) ? clone($this->order) : $this->order;
		
		if (!($order instanceof VPCTHelperOrder))
		{
			$order = plgSystemVPConversionTrackingHelper::getInstance()->getOrder();
		}
		
		if (!$order || empty($order->virtuemart_order_id))
		{
			$this->setError(__METHOD__ . '() failed. No order data available.');
			return false;
		}
		
		$currency = $order->getCurrency($currency_type);
		
		if (empty($currency))
		{
			$this->setError(__METHOD__ . '() failed. Invalid Currency object.');
			return false;
		}
		
		$doc      = JFactory::getDocument();
		$tab      = $doc->_getTab();
		$lineEnd  = $doc->_getLineEnd();
		$products = array();
		
		foreach($order->items as $item)
		{
			$product = new stdClass;
			
			$product->item_id       = !empty($item->order_item_sku) ? $this->escape($item->order_item_sku) : $item->virtuemart_product_id;
			$product->item_name     = $this->escape($item->order_item_name);
			$product->item_category = $this->escape($item->category_name);
			$product->item_brand    = $this->escape($item->mf_name);
			$product->item_variant  = '';
			
			JLoader::register('VirtueMartModelCustomfields', JPATH_ADMINISTRATOR . '/components/com_virtuemart/models/customfields.php');
			
			$product_attributes = VirtueMartModelCustomfields::CustomsFieldOrderDisplay($item, 'FE');
			$product_attributes = !empty($product_attributes) ? str_replace(array('<br />', '<br/>'), array('|[]|', '|[]|'), $product_attributes) : $product_attributes;
			
			if (!empty($product_attributes))
			{
				if (strpos($product_attributes, '|[]|'))
				{
					$product_attributes = explode('|[]|', $product_attributes);
				}
				else
				{
					$product_attributes = array($product_attributes);
				}
				
				foreach($product_attributes as $key => &$variant)
				{
					$variant = $this->escape($variant);
					$variant = trim($variant, ' ');
					
					if (str_replace(' ', '', $variant) == '')
					{
						unset($product_attributes[$key]);
					}
					else
					{
						$product_attributes[$key] = $variant;
					}
				}

				$product->item_variant = implode(', ', $product_attributes);
			}
			
			if ($currency_type == 'user')
			{
				$product->item_price = (string) $currency->roundForDisplay($item->product_final_price, $order->user_currency_id);
				$product->quantity   = (int) $item->product_quantity;
			}
			else
			{
				$product->item_price = (string) $currency->roundForDisplay($item->product_final_price);
				$product->quantity   = (int) $item->product_quantity;
			}
			
			$products[] = $product;
		}
		
		$transaction = new stdClass;
		
		$transaction->ecommerce           = new stdClass;
		$transaction->ecommerce->purchase = new stdClass;

		$transaction->ecommerce->purchase->transaction_id = (string) (!empty($order->order_number)) ? $this->escape($order->order_number) : $order->virtuemart_order_id;
		$transaction->ecommerce->purchase->affiliation    = !empty($order->vendor->vendor_store_name) ? $this->escape($order->vendor->vendor_store_name) : $this->escape($order->vendor->vendor_name);

		if ($currency_type == 'user')
		{
			$transaction->ecommerce->purchase->value  = (string) $currency->roundForDisplay($order->order_total, $order->user_currency_id);
			$transaction->ecommerce->purchase->shipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax), $order->user_currency_id);
			$transaction->ecommerce->purchase->tax      = (string) $currency->roundForDisplay($order->order_billTaxAmount, $order->user_currency_id);
			$transaction->ecommerce->purchase->currency = $this->escape($order->user_currency_code);
		}
		else
		{
			$transaction->ecommerce->purchase->value  = (string) $currency->roundForDisplay($order->order_total);
			$transaction->ecommerce->purchase->shipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax));
			$transaction->ecommerce->purchase->tax      = (string) $currency->roundForDisplay($order->order_billTaxAmount);
			$transaction->ecommerce->purchase->currency = (string) $this->escape($order->order_currency_code);
		}
		
		$transaction->ecommerce->purchase->coupon = (string) $this->escape($order->coupon_code);
		$transaction->ecommerce->purchase->items  = $products;

		$snippet  = 'window.' . $dataLayerName . ' = window.' . $dataLayerName . ' || [];' . $lineEnd;
		$snippet .= $tab . $tab . $dataLayerName . '.push(' . json_encode($transaction, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . ');';
		
		return $snippet;
	}
	
	
	protected function getGtagConversionSnippet($enhanced, $currency_type)
	{
		$order = is_object($this->order) ? clone($this->order) : $this->order;
		
		if (!($order instanceof VPCTHelperOrder))
		{
			$order = plgSystemVPConversionTrackingHelper::getInstance()->getOrder();
		}
		
		if (!$order || empty($order->virtuemart_order_id))
		{
			$this->setError(__METHOD__ . '() failed. No order data available.');
			return false;
		}
		
		$currency = $order->getCurrency($currency_type);
		
		if (empty($currency))
		{
			$this->setError(__METHOD__ . '() failed. Invalid Currency object.');
			return false;
		}
		
		$doc      = JFactory::getDocument();
		$tab      = $doc->_getTab();
		$lineEnd  = $doc->_getLineEnd();
		$products = array();
		$i        = 0;
		
		foreach($order->items as $item)
		{
			$i++;
			
			$product = new stdClass;
			
			$product->id            = !empty($item->order_item_sku) ? $this->escape($item->order_item_sku) : $item->virtuemart_product_id;
			$product->name          = $this->escape($item->order_item_name);
			$product->sku           = $this->escape($item->order_item_sku);
			$product->variant       = '';
			$product->brand         = $this->escape($item->mf_name);
			$product->category      = $this->escape($item->category_name);
			$product->list_name     = 'Cart';
			$product->list_position = $i;
			
			JLoader::register('VirtueMartModelCustomfields', JPATH_ADMINISTRATOR . '/components/com_virtuemart/models/customfields.php');
			
			$product_attributes = VirtueMartModelCustomfields::CustomsFieldOrderDisplay($item, 'FE');
			$product_attributes = !empty($product_attributes) ? str_replace(array('<br />', '<br/>'), array('|[]|', '|[]|'), $product_attributes) : $product_attributes;
			
			if (!empty($product_attributes))
			{
				if (strpos($product_attributes, '|[]|'))
				{
					$product_attributes = explode('|[]|', $product_attributes);
				}
				else
				{
					$product_attributes = array($product_attributes);
				}
				
				foreach($product_attributes as $key => &$variant)
				{
					$variant = $this->escape($variant);
					$variant = trim($variant, ' ');
					
					if (str_replace(' ', '', $variant) == '')
					{
						unset($product_attributes[$key]);
					}
					else
					{
						$product_attributes[$key] = $variant;
					}
				}

				$product->variant = implode(', ', $product_attributes);
			}
			
			if ($currency_type == 'user')
			{
				$product->price    = (string) $currency->roundForDisplay($item->product_final_price, $order->user_currency_id);
				$product->quantity = (int) $item->product_quantity;
				
				if ($enhanced)
				{
					$product->currency = (string) $this->escape($order->user_currency_code);
				}
			}
			else
			{
				$product->price    = (string) $currency->roundForDisplay($item->product_final_price);
				$product->quantity = (int) $item->product_quantity;
				
				if ($enhanced)
				{
					$product->currency = (string) $this->escape($order->order_currency_code);
				}
			}
			
			$products[] = $product;
		}
		
		$transaction = new stdClass;
		
		$transaction->transaction_id  = (string) (!empty($order->order_number)) ? $this->escape($order->order_number) : $order->virtuemart_order_id;
		$transaction->affiliation     = !empty($order->vendor->vendor_store_name) ? $this->escape($order->vendor->vendor_store_name) : $this->escape($order->vendor->vendor_name);
		
		if ($currency_type == 'user')
		{
			$transaction->revenue  = (string) $currency->roundForDisplay($order->order_total, $order->user_currency_id);
			$transaction->value    = (string) $currency->roundForDisplay($order->order_total, $order->user_currency_id);
			$transaction->shipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax), $order->user_currency_id);
			$transaction->tax      = (string) $currency->roundForDisplay($order->order_billTaxAmount, $order->user_currency_id);
			$transaction->currency = $this->escape($order->user_currency_code);
		}
		else
		{
			$transaction->revenue  = (string) $currency->roundForDisplay($order->order_total);
			$transaction->value    = (string) $currency->roundForDisplay($order->order_total);
			$transaction->shipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax));
			$transaction->tax      = (string) $currency->roundForDisplay($order->order_billTaxAmount);
			$transaction->currency = (string) $this->escape($order->order_currency_code);
		}
		
		$transaction->items = $products;
		
		$snippet = "gtag('event', 'purchase', " . json_encode($transaction, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . ");";

		
		return $snippet;
	}
	
	protected function getGA4GtagConversionSnippet($currency_type)
	{
		$order = is_object($this->order) ? clone($this->order) : $this->order;
		
		if (!($order instanceof VPCTHelperOrder))
		{
			$order = plgSystemVPConversionTrackingHelper::getInstance()->getOrder();
		}
		
		if (!$order || empty($order->virtuemart_order_id))
		{
			$this->setError(__METHOD__ . '() failed. No order data available.');
			return false;
		}
		
		$currency = $order->getCurrency($currency_type);
		
		if (empty($currency))
		{
			$this->setError(__METHOD__ . '() failed. Invalid Currency object.');
			return false;
		}
		
		$doc      = JFactory::getDocument();
		$tab      = $doc->_getTab();
		$lineEnd  = $doc->_getLineEnd();
		$products = array();
		$i        = 0;
		
		foreach($order->items as $item)
		{
			$i++;
			
			$product = new stdClass;
			
			$product->item_id        = !empty($item->order_item_sku) ? $this->escape($item->order_item_sku) : $item->virtuemart_product_id;
			$product->item_name      = $this->escape($item->order_item_name);
			$product->item_sku       = $this->escape($item->order_item_sku);
			$product->item_variant   = '';
			$product->item_brand     = $this->escape($item->mf_name);
			$product->item_category  = $this->escape($item->category_name);
			$product->item_list_name = 'Cart';
			$product->item_list_id   = 'CART';
			$product->index          = $i;
			$product->affiliation    = !empty($order->vendor->vendor_store_name) ? $this->escape($order->vendor->vendor_store_name) : $this->escape($order->vendor->vendor_name);
			
			JLoader::register('VirtueMartModelCustomfields', JPATH_ADMINISTRATOR . '/components/com_virtuemart/models/customfields.php');
			
			$product_attributes = VirtueMartModelCustomfields::CustomsFieldOrderDisplay($item, 'FE');
			$product_attributes = !empty($product_attributes) ? str_replace(array('<br />', '<br/>'), array('|[]|', '|[]|'), $product_attributes) : $product_attributes;
			
			if (!empty($product_attributes))
			{
				if (strpos($product_attributes, '|[]|'))
				{
					$product_attributes = explode('|[]|', $product_attributes);
				}
				else
				{
					$product_attributes = array($product_attributes);
				}
				
				foreach($product_attributes as $key => &$variant)
				{
					$variant = $this->escape($variant);
					$variant = trim($variant, ' ');
					
					if (str_replace(' ', '', $variant) == '')
					{
						unset($product_attributes[$key]);
					}
					else
					{
						$product_attributes[$key] = $variant;
					}
				}

				$product->item_variant = implode(', ', $product_attributes);
			}
			
			if ($currency_type == 'user')
			{
				$product->price    = (string) $currency->roundForDisplay($item->product_final_price, $order->user_currency_id);
				$product->quantity = (int) $item->product_quantity;
			}
			else
			{
				$product->price    = (string) $currency->roundForDisplay($item->product_final_price);
				$product->quantity = (int) $item->product_quantity;
			}
			
			$products[] = $product;
		}
		
		$transaction = new stdClass;
		
		$transaction->transaction_id  = (string) (!empty($order->order_number)) ? $this->escape($order->order_number) : $order->virtuemart_order_id;
		
		if ($currency_type == 'user')
		{
			$transaction->value    = (string) $currency->roundForDisplay($order->order_total, $order->user_currency_id);
			$transaction->shipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax), $order->user_currency_id);
			$transaction->tax      = (string) $currency->roundForDisplay($order->order_billTaxAmount, $order->user_currency_id);
			$transaction->currency = $this->escape($order->user_currency_code);
		}
		else
		{
			$transaction->value    = (string) $currency->roundForDisplay($order->order_total);
			$transaction->shipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax));
			$transaction->tax      = (string) $currency->roundForDisplay($order->order_billTaxAmount);
			$transaction->currency = (string) $this->escape($order->order_currency_code);
		}
		
		$transaction->coupon = (string) $this->escape($order->coupon_code);
		
		$transaction->items = $products;
		
		$snippet = "gtag('event', 'purchase', " . json_encode($transaction, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . ");";

		
		return $snippet;
	}
	
	protected function getAnalyticsConversionSnippet($client_id, $enhanced, $currency_type, $location = 'HEAD')
	{
		$order = is_object($this->order) ? clone($this->order) : $this->order;
		
		if (!($order instanceof VPCTHelperOrder))
		{
			$order = plgSystemVPConversionTrackingHelper::getInstance()->getOrder();
		}
		
		if (!$order || empty($order->virtuemart_order_id))
		{
			$this->setError(__METHOD__ . '() failed. No order data available.');
			return false;
		}
		
		$currency = $order->getCurrency($currency_type);
		
		if (empty($currency))
		{
			$this->setError(__METHOD__ . '() failed. Invalid Currency object.');
			return false;
		}
		
		$client_id = (string) ($client_id ? str_replace(' ', '', $client_id) : $client_id);
		
		$doc      = JFactory::getDocument();
		$tab      = $doc->_getTab();
		$lineEnd  = $doc->_getLineEnd();
		
		$gaFunctions = array();
		
		if (!$enhanced)
		{
			if (!$analytics_loaded)
			{
				$gaFunctions[] = "ga('send', 'pageview');";
			}
			
			$gaFunctions[] = "ga('require', 'ecommerce');";
			
			$transaction = new stdClass;
			
			$transaction->id          = (string) (!empty($order->order_number)) ? $order->order_number : $order->virtuemart_order_id;
			$transaction->affiliation = !empty($order->vendor->vendor_store_name) ? $order->vendor->vendor_store_name : $order->vendor->vendor_name;
			
			if ($currency_type == 'user')
			{
				$transaction->revenue  = (string) $currency->roundForDisplay($order->order_total, $order->user_currency_id);
				$transaction->shipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax), $order->user_currency_id);
				$transaction->tax      = (string) $currency->roundForDisplay($order->order_billTaxAmount, $order->user_currency_id);
				$transaction->currency = $this->escape($order->user_currency_code);
			}
			else
			{
				$transaction->revenue  = (string) $currency->roundForDisplay($order->order_total);
				$transaction->shipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax));
				$transaction->tax      = (string) $currency->roundForDisplay($order->order_billTaxAmount);
				$transaction->currency = $this->escape($order->order_currency_code);
			}
			
			$gaFunctions[] = "ga('ecommerce:addTransaction', " . json_encode($transaction, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . ");";
			
			foreach($order->items as $product)
			{
				$item = new stdClass;

				$item->id       = !empty($product->order_item_sku) ? $this->escape($product->order_item_sku) : $product->virtuemart_product_id;
				$item->name     = $this->escape($product->order_item_name);
				$item->sku      = $this->escape($product->order_item_sku);
				$item->category = $this->escape($product->category_name);
				
				if ($currency_type == 'user')
				{
					$item->price    = (string) $currency->roundForDisplay($product->product_final_price, $order->user_currency_id);
					$item->quantity = (string) $product->product_quantity;
					$item->currency = (string) $this->escape($order->user_currency_code);
				}
				else
				{
					$item->price    = (string) $currency->roundForDisplay($product->product_final_price);
					$item->quantity = (string) $product->product_quantity;
					$item->currency = (string) $this->escape($order->user_currency_code);
				}
				
				$gaFunctions[] = "ga('ecommerce:addItem', " . json_encode($item, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . ");";
			}
			
			$gaFunctions[] = "ga('ecommerce:send');";
		}
		else
		{
			$gaFunctions[] = "ga('require', 'ec');";
			
			if ($currency_type == 'user')
			{
				$currency_code = (string) $order->user_currency_code;
			}
			else
			{
				$currency_code = (string) $order->order_currency_code;
			}
			
			$gaFunctions[] = "ga('set', '&cu', '" . $this->escape($currency_code) . "');";
			
			foreach($order->items as $item)
			{
				$product = new stdClass;

				$product->id       = !empty($item->order_item_sku) ? $this->escape($item->order_item_sku) : $item->virtuemart_product_id;
				$product->name     = $this->escape($item->order_item_name);
				$product->sku      = $this->escape($item->order_item_sku);
				$product->category = $this->escape($item->category_name);
				$product->brand    = $this->escape($item->mf_name);
				$product->variant  = '';
				
				JLoader::register('VirtueMartModelCustomfields', JPATH_ADMINISTRATOR . '/components/com_virtuemart/models/customfields.php');
				
				$product_attributes = VirtueMartModelCustomfields::CustomsFieldOrderDisplay($item, 'FE');
				$product_attributes = !empty($product_attributes) ? str_replace(array('<br />', '<br/>'), array('|[]|', '|[]|'), $product_attributes) : $product_attributes;
				
				if (!empty($product_attributes))
				{
					if (strpos($product_attributes, '|[]|'))
					{
						$product_attributes = explode('|[]|', $product_attributes);
					}
					else
					{
						$product_attributes = array($product_attributes);
					}
					
					foreach($product_attributes as $key => &$variant)
					{
						$variant = $this->escape($variant);
						$variant = trim($variant, ' ');
						
						if (str_replace(' ', '', $variant) == '')
						{
							unset($product_attributes[$key]);
						}
						else
						{
							$product_attributes[$key] = $variant;
						}
					}

					$product->variant = implode(', ', $product_attributes);
				}

				if ($currency_type == 'user')
				{
					$product->price    = (string) $currency->roundForDisplay($item->product_final_price, $order->user_currency_id);
					$product->quantity = (float) $item->product_quantity;
				}
				else
				{
					$product->price    = (string) $currency->roundForDisplay($item->product_final_price);
					$product->quantity = (float) $item->product_quantity;
				}
				
				$gaFunctions[] = "ga('ec:addProduct', " . json_encode($product, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . ");";
			}
			
			$action = new stdClass;
			
			$action->id          = (string) (!empty($order->order_number)) ? $order->order_number : $order->virtuemart_order_id;
			$action->affiliation = !empty($order->vendor->vendor_store_name) ? $order->vendor->vendor_store_name : $order->vendor->vendor_name;
			
			if ($currency_type == 'user')
			{
				$action->revenue  = (string) $currency->roundForDisplay($order->order_total, $order->user_currency_id);
				$action->shipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax), $order->user_currency_id);
				$action->tax      = (string) $currency->roundForDisplay($order->order_billTaxAmount, $order->user_currency_id);
			}
			else
			{
				$action->revenue  = (string) $currency->roundForDisplay($order->order_total);
				$action->shipping = (string) $currency->roundForDisplay(($order->order_shipment + $order->order_shipment_tax));
				$action->tax      = (string) $currency->roundForDisplay($order->order_billTaxAmount);
			}
			
			$action->coupon = $this->escape($order->coupon_code);
			
			$gaFunctions[] = "ga('ec:setAction', 'purchase', " . json_encode($action, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . ");";
			
			if (!$analytics_loaded)
			{
				$gaFunctions[] = "ga('send', 'pageview');";
			}
			else
			{
				$gaFunctions[] = "ga('send', 'event', 'ecommerce', 'purchase', {'nonInteraction': true});";
			}
		}
		
		return implode($lineEnd . $tab . $tab, $gaFunctions);
	}

	protected function getBody()
	{
		$html = $this->app->getBody();
		
		if (strpos($html, '<body') === false || strpos($html, '</body>') === false)
		{
			return array('', $html, '');
		}

		$html_split = explode('<body', $html, 2);
		$prefix     = $html_split['0'];
		$body       = '<body' . $html_split['1'];
		$body_split = explode('</body>', $body);
		$suffix     = array_pop($body_split);
		$body       = implode('</body>', $body_split) . '</body>';

		return array($prefix, $body, $suffix);
	}

	/**
	* Method to get a new Mustache engine instance.
	* 
	* @return mixed (object/boolean) False in case of failure
	*/
	protected function getMustache()
	{
		if (self::$mustache === null)
		{
			// Register Mustache Autoloader class
			JLoader::register('Mustache_Autoloader', VPCT_PATH . '/libraries/Mustache/Autoloader.php');
			
			// If Mustache Autoloader class is not found throw an error
			if (!class_exists('Mustache_Autoloader'))
			{
				$this->setError('Mustache library not loaded.');
				self::$mustache = false;

				return self::$mustache;
			}
			
			// Register Mustache Autoloader
			Mustache_Autoloader::register();
			
			// Build a new Mustache engine instance
			$mustache = new Mustache_Engine(array(
			    'escape' => function($value) {
			        return $value;
			    },
			    'charset' => 'UTF-8',
			    'strict_callables' => false
			));
			
			self::$mustache = $mustache;
		}

		return self::$mustache;
	}
	
	protected function escape($string)
	{
		$string = (string) $string;
		
		return htmlspecialchars(strip_tags($string), ENT_COMPAT, 'UTF-8');
	}
}