<?php
function minifyCSS($styles) {
	global $registry;
	$combinedStyles = array();
	$result = array();
	$oc_root = dirname(DIR_APPLICATION);
	$cache = NULL;
	$cachefile = NULL;
	$recache = false;
	$filename = NULL;
	$megaHashes = array();
	
	if (!defined('DS')) {
		define('DS', DIRECTORY_SEPARATOR);
	}
	
	//load NitroCache
	require_once $oc_root.DS.'system'.DS.'nitro'.DS.'config.php';
	require_once $oc_root.DS.'system'.DS.'nitro'.DS.'core'.DS.'core.php';
	require_once $oc_root.DS.'system'.DS.'nitro'.DS.'core'.DS.'cdn.php';
	
	$nitroSettings = getNitroPersistence();

	if (empty($nitroSettings['Nitro']['Enabled']) || $nitroSettings['Nitro']['Enabled'] != 'yes' || empty($nitroSettings['Nitro']['Mini']['Enabled']) || empty($nitroSettings['Nitro']['Mini']['CSS']) || $nitroSettings['Nitro']['Mini']['Enabled'] != 'yes' || $nitroSettings['Nitro']['Mini']['CSS'] != 'yes' || (function_exists('areWeInIgnoredUrl') && areWeInIgnoredUrl())) {
		return $styles;
	}
	
	if (!file_exists($oc_root.DS.'assets')) {
		mkdir($oc_root.DS.'assets');
	}
	
	if (!file_exists($oc_root.DS.'assets'.DS.'style')) {
		mkdir($oc_root.DS.'assets'.DS.'style');
	}
	
	$cssExclude = array();
	$excludedCSS = array();
	$includedCSS = 0;
	
	if (!empty($nitroSettings['Nitro']['Mini']['CSSExclude'])) {
		$cssExclude = trim($nitroSettings['Nitro']['Mini']['CSSExclude'], "\n\r ");
		$cssExclude = explode("\n", $cssExclude);
		foreach ($cssExclude as $k=>$stylename) {
			$stylename = trim($stylename, "\n\r ");
			if (!empty($stylename)) {
				$cssExclude[$k] = $stylename;
			}
		}
	}
	
	//extract local fylesystem path
	foreach($styles as $hash=>$style) {
		$url_info = parse_url($style['href']);
		if (!empty($url_info['path'])) {
			$f = trim($url_info['path'], '/');
			if (file_exists($oc_root.DS.$f)) {
				if (empty($url_info['query'])) {
					$styles[$hash]['href'] = $f;
				} else { //it is a local file but generates CSS dynamically, we will treat it as a URL
					if (!preg_match('@^(https?:)?//.*$@', $style['href'])) { //this is probably relatively defined resource, we will make its URL absolute, so we can fetch it later
						if (isset($_SERVER['HTTPS']) && (($_SERVER['HTTPS'] == 'on') || ($_SERVER['HTTPS'] == '1'))) {
							$webshopUrl = $registry->get('config')->get('config_ssl');
						} else {
							$webshopUrl = $registry->get('config')->get('config_url');
						}
						$webshopUrl = rtrim(preg_replace('~^https?\:~i', '', $webshopUrl), '/');
						$styles[$hash]['href'] = $webshopUrl.'/'.$style['href'];
					}
				}
			} else if (!preg_match('@^(https?:)?//.*$@', $style['href'])) { //if this is not an URL we do not know how to handle it, so we will exclude it
				if (empty($nitroSettings['Nitro']['Mini']['CSSExclude'])) {
					$nitroSettings['Nitro']['Mini']['CSSExclude'] = '';
				}
				
				$cssExclude[] = basename($style['href']);
			}
		} else if (!preg_match('@^(https?:)?//.*$@', $style['href'])) { //if this is not an URL we do not know how to handle it, so we will exclude it
			if (empty($nitroSettings['Nitro']['Mini']['CSSExclude'])) {
				$nitroSettings['Nitro']['Mini']['CSSExclude'] = '';
			}
			
			$cssExclude[] = basename($style['href']);
		}
	}
	
	
	if (!empty($nitroSettings['Nitro']['Mini']['CSSCombine']) && $nitroSettings['Nitro']['Mini']['CSSCombine'] == 'yes') {
		
		$cachefile = $oc_root.DS.'assets'.DS.'style'.DS.getSSLCachePrefix().'styles-combined.cache';
		
		if (!file_exists($cachefile)) {
			touch($cachefile);
			file_put_contents($cachefile, json_encode(array()));
		}
		
		$cache = json_decode(file_get_contents($cachefile), true);
		
		//build combination hash
		foreach ($styles as $hash=>$style) {
			if (!in_array(basename($style['href']), $cssExclude)) {
				if (empty($megaHashes[$style['rel'].$style['media']])) {
					$megaHashes[$style['rel'].$style['media']] = '';
				}
				
				$megaHashes[$style['rel'].$style['media']] .= $hash;
				$includedCSS++;
			} else {
				$excludedCSS[$hash] = $style;
			}
		}
		
		foreach ($megaHashes as $k=>$megaHash) {
			$megaHashes[$k] = md5($megaHash);
		}
		
		// Check the cache if we should recache
		foreach ($styles as $hash=>$style) {
			if (empty($style)) continue;
		
			if (!in_array(basename($style['href']), $cssExclude)) {
				$filename = $oc_root.DS.trim(str_replace('/', DS, $style['href']), DS); //convert relative url to absolute filesystem specific path (all of this, because of Windows)
				
				if (file_exists($filename)) {
					$comboKey = $megaHashes[$style['rel'].$style['media']];
					
					if (empty($cache[$comboKey]) || !is_array($cache[$comboKey])) {
						$cache[$comboKey] = array();
					}
					
					if (array_key_exists($filename, $cache[$comboKey])) {
						if ($cache[$comboKey][$filename] != filemtime($filename)) {
							$recache = true;
							break;
						}
					} else {
						$recache = true;
						break;
					}
				} else { // this must be an URL, we will not recache
					continue;
				}
			}
		}
		//end of check
		
		if (isset($_SERVER['HTTPS']) && (($_SERVER['HTTPS'] == 'on') || ($_SERVER['HTTPS'] == '1'))) {
			$webshopUrl = $registry->get('config')->get('config_ssl');
		} else {
			$webshopUrl = $registry->get('config')->get('config_url');
		}
		$webshopUrl = rtrim(preg_replace('~^https?\:~i', '', $webshopUrl), '/');
		
		include_once $oc_root.DS.'system'.DS.'nitro'.DS.'lib'.DS.'minifier'.DS.'CSSMin.php';

		foreach ($styles as $hash=>$style) {
			if (empty($style)) continue;
			
			if (!in_array(basename($style['href']), $cssExclude)) {
				
				$target = '/assets/style/'.getSSLCachePrefix().'nitro-combined-' . $megaHashes[$style['rel'].$style['media']] . '.css';
				$targetAbsolutePath = $oc_root.DS.trim(str_replace('/', DS, $target), DS);
				
				$filename = $oc_root.DS.trim(str_replace('/', DS, $style['href']), DS);
				$comboHash = $megaHashes[$style['rel'].$style['media']];
				
				if (empty($combinedStyles[$style['rel'].$style['media']])) {
					$combinedStyles[$style['rel'].$style['media']] = array('rel' => $style['rel'], 'media' => $style['media'], 'content' => '', 'megaHash' => $comboHash);
				}
					
				if ($recache || !file_exists($targetAbsolutePath)) {
					
					if (empty($counters[$style['rel'].$style['media']])) {
						$counters[$style['rel'].$style['media']] = 0;
					}
					
					if (file_exists($filename)) {
						$urlToCurrentDir = $webshopUrl.dirname('/'.trim($style['href'], '/'));
						
						/* replace relative urls with absolute ones */
						$tmpContent = preg_replace('/(url\()(?![\'\"]?(?:(?:https?\:\/\/)|(?:data\:)|(?:\/)))([\'\"]?)\/?(?!\/)/', '$1$2'.$urlToCurrentDir.'/', file_get_contents($filename));
					} else { //this must be an URL, so try to get its content
						$tmpContent = fetchRemoteContent($style['href']);
					}
					
					if (!empty($tmpContent)) {
						//minify
						$tmpContent = Nitro_Minify_CSS_Compressor::process($tmpContent);
						
						
						$combinedStyles[$style['rel'].$style['media']]['content'] .= $tmpContent;
						unset($tmpContent);
					}
					
					if (file_exists($filename)) {
						$cache[$comboHash][$filename] = filemtime($filename);
					}
				}
			}
		}
		
		file_put_contents($cachefile, json_encode($cache));
		
		foreach ($combinedStyles as $key=>$value) {
			$target = '/assets/style/'.getSSLCachePrefix().'nitro-combined-' . $megaHashes[$key] . '.css';
			$targetAbsolutePath = $oc_root.DS.trim(str_replace('/', DS, $target), DS);
			
			if ($recache || !file_exists($targetAbsolutePath)) {
				
				/* pull imports to the top and include their content if possible */
				$tmpContent = $value['content'];
				$imports = array();
				preg_match_all('/\@import[^\;]*\;/', $tmpContent, $imports);
				if (!empty($imports)) {
					$imports = array_reverse($imports[0]);
					foreach ($imports as $import) {
						$importUrl = preg_replace('/[\w\W]*url[\w\W]+(\/\/[^\"\'\)]*)[\w\W]*/', '$1', $import);
						$isLocalFile = false;
						if (!empty($nitroSettings['Nitro']['Mini']['CSSFetchImport']) && $nitroSettings['Nitro']['Mini']['CSSFetchImport'] == 'yes') {
							if (strpos($importUrl, $webshopUrl) !== false) {
								$localFile = dirname(DIR_APPLICATION).str_replace($webshopUrl, '', $importUrl);
								if (file_exists($localFile)) {
									$isLocalFile = true;
									$tmpImportContent = file_get_contents($localFile);
								}
							}
							
							if (!$isLocalFile) {
								$tmpImportContent = fetchRemoteContent($importUrl);
							}
						}
						
						if (!empty($tmpImportContent)) {
							$tmpContent = $tmpImportContent.str_replace($import, '', $tmpContent);
						} else {
							$tmpContent = $import.str_replace($import, '', $tmpContent);
						}
					}
				}
				
				file_put_contents($targetAbsolutePath, $tmpContent);
			}
			
			$result[$megaHashes[$key]] = array('rel' => $value['rel'], 'media' => $value['media'], 'href' => trim($target, '/'));
		}
		
		if ($includedCSS > 0) {
			return array_merge($excludedCSS, $result);
		} else {
			return $excludedCSS;
		}
	} else {
		
		$cachefile = $oc_root.DS.'assets'.DS.'style'.DS.getSSLCachePrefix().'styles.cache';
		
		if (!file_exists($cachefile)) {
			touch($cachefile);
			file_put_contents($cachefile, json_encode(array()));
		}
		
		$cache = json_decode(file_get_contents($cachefile), true);
		
		if (isset($_SERVER['HTTPS']) && (($_SERVER['HTTPS'] == 'on') || ($_SERVER['HTTPS'] == '1'))) {
			$webshopUrl = $registry->get('config')->get('config_ssl');
		} else {
			$webshopUrl = $registry->get('config')->get('config_url');
		}
		$webshopUrl = rtrim(preg_replace('~^https?\:~i', '', $webshopUrl), '/');
		
		include_once $oc_root.DS.'system'.DS.'nitro'.DS.'lib'.DS.'minifier'.DS.'CSSMin.php';
		
		foreach ($styles as $hash=>$style) {
			if (empty($style)) continue;
			$recache = false;
		
			if (!in_array(trim(basename($style['href']), "\r\n"), $cssExclude)) {
				$filename = $oc_root.DS.trim(str_replace('/', DS, $style['href']), DS);
				
				$basefilename = basename($style['href'], '.css');
				$target = '/assets/style/'.getSSLCachePrefix().'nitro-mini-' . $basefilename . '.css';
				$targetAbsolutePath = $oc_root.DS.trim(str_replace('/', DS, $target), DS);
				
				if (array_key_exists($filename, $cache)) {
					if ($cache[$filename] != filemtime($filename)) {
						$recache = true;
					}
				} else {
					$recache = true;
				}
				
				if ($recache || !file_exists($targetAbsolutePath)) {
					$urlToCurrentDir = $webshopUrl.dirname('/'.trim($style['href'], '/'));
					
					/* replace relative urls with absolute ones */
					$tmpContent = preg_replace('/(url\()(?![\'\"]?(?:(?:https?\:\/\/)|(?:data\:)|(?:\/)))([\'\"]?)\/?(?!\/)/', '$1$2'.$urlToCurrentDir.'/', file_get_contents($filename));
					
					//minify
					$tmpContent = Nitro_Minify_CSS_Compressor::process($tmpContent);
					
					file_put_contents($targetAbsolutePath, $tmpContent);
					
					unset($tmpContent);
					
					$cache[$filename] = filemtime($filename);
				}
				
				$styles[$hash]['href'] = trim($target, '/');
			}
		}
		
		file_put_contents($cachefile, json_encode($cache));
	
		return $styles;
	}
}

function fetchRemoteContent($url) {
	if (strpos($url, '//') === 0) {
		if (isset($_SERVER['HTTPS']) && (($_SERVER['HTTPS'] == 'on') || ($_SERVER['HTTPS'] == '1'))) {
			$url = 'https:'.$url;
		} else {
			$url = 'http:'.$url;
		}
	}
	
	if (ini_get('allow_url_fopen')) {
		$content = file_get_contents($url);
		return $content;
	} else {
		$ch = curl_init($url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_ENCODING, "");
		$content = curl_exec($ch);
		curl_close($ch);
		return $content;
	}
	return false;
}

function minifyJS($scripts) {
	global $registry;
	$oc_root = dirname(DIR_APPLICATION);
	$cache = NULL;
	$cachefile = NULL;
	$filename = NULL;
	
	if (!defined('DS')) {
		define('DS', DIRECTORY_SEPARATOR);
	}
	
	//load NitroCache
	require_once $oc_root.DS.'system'.DS.'nitro'.DS.'config.php';
	require_once $oc_root.DS.'system'.DS.'nitro'.DS.'core'.DS.'core.php';
	require_once $oc_root.DS.'system'.DS.'nitro'.DS.'core'.DS.'cdn.php';
	
	$nitroSettings = getNitroPersistence();
	
	if (empty($nitroSettings['Nitro']['Enabled']) || $nitroSettings['Nitro']['Enabled'] != 'yes' || empty($nitroSettings['Nitro']['Mini']['Enabled']) || empty($nitroSettings['Nitro']['Mini']['JS']) || $nitroSettings['Nitro']['Mini']['Enabled'] != 'yes' || $nitroSettings['Nitro']['Mini']['JS'] != 'yes' || (function_exists('areWeInIgnoredUrl') && areWeInIgnoredUrl())) {
		return $scripts;
	}
	
	if (!file_exists($oc_root.DS.'assets')) {
		mkdir($oc_root.DS.'assets');
	}
	
	if (!file_exists($oc_root.DS.'assets'.DS.'script')) {
		mkdir($oc_root.DS.'assets'.DS.'script');
	}
	
	$jsExclude = array();
	
	if (!empty($nitroSettings['Nitro']['Mini']['JSExclude'])) {
		$jsExclude = trim($nitroSettings['Nitro']['Mini']['JSExclude'], "\n\r ");
		$jsExclude = explode("\n", $jsExclude);
		foreach ($jsExclude as $k=>$script) {
			$script = trim($script, "\n\r ");
			if (!empty($script)) {
				$jsExclude[$k] = $script;
			}
		}
	}
	
	//extract local fylesystem path

	foreach($scripts as $hash=>$script) {
		$url_info = parse_url($script);
		if (!empty($url_info['path'])) {
			$f = trim($url_info['path'], '/');
			if (file_exists($oc_root.DS.$f)) {
				if (empty($url_info['query'])) {
					$scripts[$hash] = $f;
				} else { //it is a local file but generates JS dynamically, we will treat it as a URL
					if (!preg_match('@^(https?:)?//.*$@', $script)) { //this is probably relatively defined resource, we will make its URL absolute, so we can fetch it later
						if (isset($_SERVER['HTTPS']) && (($_SERVER['HTTPS'] == 'on') || ($_SERVER['HTTPS'] == '1'))) {
							$webshopUrl = $registry->get('config')->get('config_ssl');
						} else {
							$webshopUrl = $registry->get('config')->get('config_url');
						}
						$webshopUrl = rtrim(preg_replace('~^https?\:~i', '', $webshopUrl), '/');
						$scripts[$hash] = $webshopUrl.'/'.$script;
					}
				}
			} else if (!preg_match('@^(https?:)?//.*$@', $script)) { //if this is not an URL we do not know how to handle it, so we will exclude it
				if (empty($nitroSettings['Nitro']['Mini']['JSExclude'])) {
					$nitroSettings['Nitro']['Mini']['JSExclude'] = '';
				}
				
				$jsExclude[] = basename($script);
			}
		} else if (!preg_match('@^(https?:)?//.*$@', $script)) {//if this is not an URL we do not know how to handle it, so we will exclude it
			if (empty($nitroSettings['Nitro']['Mini']['JSExclude'])) {
				$nitroSettings['Nitro']['Mini']['JSExclude'] = '';
			}
			
			$jsExclude[] = basename($script);
		}
	}

	if (!empty($nitroSettings['Nitro']['Mini']['JSCombine']) && $nitroSettings['Nitro']['Mini']['JSCombine'] == 'yes') {
		$cachefile = $oc_root.DS.'assets'.DS.'script'.DS.getSSLCachePrefix().'scripts-combined.cache';
		
		if (!file_exists($cachefile)) {
			touch($cachefile);
			file_put_contents($cachefile, json_encode(array()));
		}
		
		$cache = json_decode(file_get_contents($cachefile), true);
		
		$comboHash = '';
		$excludedScripts = array();
		$includedScripts = 0;
		
		foreach ($scripts as $hash=>$script) {
			if (!in_array(trim(basename($script), "\r\n"), $jsExclude)) {
				$comboHash .= $hash;
				$includedScripts++;
			} else {
				$excludedScripts[$hash] = $script;
			}
		}
		
		$comboHash = md5($comboHash);
		$target = '/assets/script/'.getSSLCachePrefix().'nitro-combined-' . $comboHash . '.js';
		$targetAbsolutePath = $oc_root.DS.trim(str_replace('/', DS, $target), DS);
		
		$recache = false;
		
		foreach ($scripts as $hash=>$script) {
			if (!in_array(trim(basename($script), "\r\n"), $jsExclude)) {
				$filename = $oc_root.DS.trim(str_replace('/', DS, $script), DS);
				
				if (!empty($cache[$comboHash][$filename])) {
					if ($cache[$comboHash][$filename] != filemtime($filename)) {
						$recache = true;
						break;
					}
				} else {
					$recache = true;
					break;
				}
			} else { // this must be an URL, we will not recache
				continue;
			}
		}
		
		$minifiedCombined = '';
		
		if ($recache || !file_exists($targetAbsolutePath)) {
			include_once $oc_root.DS.'system'.DS.'nitro'.DS.'lib'.DS.'minifier'.DS.'JSMin.php';

			$counter = 0;
			
			foreach ($scripts as $hash=>$script) {
				if (!in_array(trim(basename($script), "\r\n"), $jsExclude)) {
					$filename = $oc_root.DS.trim(str_replace('/', DS, $script), DS);
					
					if (file_exists($filename)) {
						$scriptSrc = file_get_contents($filename);
					} else {
						$scriptSrc = fetchRemoteContent($script);
					}
					
					if (!empty($scriptSrc)) {
						//minify
						$scriptSrc = Nitro_JSMin::minify($scriptSrc);
						
						if (substr($scriptSrc, -1) == ')') {
							$scriptSrc .= ';';
						}
						$minifiedCombined .= (($counter > 0) ? PHP_EOL : '') . $scriptSrc;
						unset($scriptSrc);
						$counter++;
					}
					
					if (file_exists($filename)) {
						$cache[$comboHash][$filename] = filemtime($filename);
					}
				}
			}
			
			file_put_contents($targetAbsolutePath, $minifiedCombined);
		}
		
		file_put_contents($cachefile, json_encode($cache));
		
		if ($includedScripts > 0) {
			return array_merge($excludedScripts, array(md5($target) => trim($target, '/')));
		} else {
			return $excludedScripts;
		}
	} else {
		$cachefile = $oc_root.DS.'assets'.DS.'script'.DS.getSSLCachePrefix().'scripts.cache';
		
		if (!file_exists($cachefile)) {
			touch($cachefile);
			file_put_contents($cachefile, json_encode(array()));
		}
		
		$cache = json_decode(file_get_contents($cachefile), true);
		
		include_once $oc_root.DS.'system'.DS.'nitro'.DS.'lib'.DS.'minifier'.DS.'JSMin.php';
		
		foreach ($scripts as $hash=>$script) {
			$recache = false;
			
			if (!in_array(trim(basename($script), "\r\n"), $jsExclude)) {
				$filename = $oc_root.DS.trim(str_replace('/', DS, $script), DS);
				$basefilename = basename($script, '.js');
				$target = '/assets/script/'.getSSLCachePrefix().'nitro-mini-' . $basefilename . '.js';
				$targetAbsolutePath = $oc_root.DS.trim(str_replace('/', DS, $target), DS);
				
				if (!empty($cache[$filename])) {
					if ($cache[$filename] != filemtime($filename)) {
						$recache = true;
					}
				} else {
					$recache = true;
				}
				
				if ($recache || !file_exists($targetAbsolutePath)) {
					touch($targetAbsolutePath);
					$scriptSrc = file_get_contents($filename);
					
					//minify
					$scriptSrc = Nitro_JSMin::minify($scriptSrc);
					
					file_put_contents($targetAbsolutePath, $scriptSrc);
					
					$cache[$filename] = filemtime($filename);
				}
				
				$scripts[$hash] = trim($target, '/');
			}
		}
		
		file_put_contents($cachefile, json_encode($cache));
		
		return $scripts;
	}
}