<?php
/*
	DevSaver Web Framework
	Copyright (c) 2002-2018 DevSaver. 
	All rights reserved.
		web:  www.devsaver.com
		mail: support@devsaver.com
*/

if (!defined("STPBase")) {
	die("This file can't be accessed directly!");
}

/**
* description
*
* @library	
* @author	
* @since	
*/
class CMinify {

	var $folder			= "";
	var $minify			= true;
	var $concatenate	= true;
	var $files			= array(
		"first"	=> array(),
		"files"	=> array(),
		"last"	=> array(),
	);

	
	/**
	* description
	*
	* @var type
	*
	* @access type
	*/
	var $type;
	

	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	public static function newInstance() {
		return new self();
	}

	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function __construct() {
		$this->time = microtime(true);
	}
	

	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function setTypeCss() {
		$this->type = "css";
		return $this;
	}

	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function setTypeJs() {
		$this->type = "js";
		return $this;
	}

	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function setTypeHtml() {
		$this->type = "html";
		return $this;
	}

	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function setVersion($ver) {
		$this->version = $ver;
		return $this;
	}

	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function setNoCache($val) {
		$this->nocache = $val;

//		$this->setCacheFile(null);
		return $this;
	}
	
	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function addFiles($files = array(), $type = "files") {
		if (is_array($files)) {
			foreach ($files as $key => $val) {
				if (file_exists($val)) {
					$this->files[$type][$val] = array(					
						"path"	=> str_replace(DIRECTORY_SEPARATOR , '/', $val),
						"file"	=> substr(str_replace(dirname($val) , "" , $val),1),
						"date"	=> filemtime($val),
					);
				}
				
			}			
		}

		return $this;
	}
	
	

	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function addFilesByPrefix($folder , $prefix , $ext , $type = "files") {

		if ($this->tmp_folder != $folder) {

			$_files = CDir::GetFiles($folder , $ext);
			sort($_files);

			if (is_array($_files)) {
				foreach ($_files as $key => $val) {
					$tmp = substr(str_replace($folder , "" , $val) , 1);

					$this->tmp_files[$val] = array(
						"path"	=> str_replace(DIRECTORY_SEPARATOR , '/', $val),
						"file"	=> $tmp,
						"date"	=> filemtime($val)
					);
				}				
			}		
			$this->tmp_folder = $folder;
		}
		


		foreach ($this->tmp_files as $key => $val) {

			if (strpos($val["file"] , $prefix) === 0) {
				$this->files[$type][$key] = $val;
			}
			
		}

		return $this;

	}
	
	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function setCacheFile($cache) {
		$this->cache_file = $cache;

		return $this;
	}

	
	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function output($write = true) {
		$content = null;

		if ($this->cache_file) {
			$this->cache_file .= "-" . $this->GenerateCacheName() . ".cache";
		}		


		if ($this->cache_file && !$this->nocache && file_exists($this->cache_file) && filesize($this->cache_file)) {
			$content = CFile::Get($this->cache_file);
		}

		if ($content === null) {
			$content = $this->getProcessed();
		}

		
		if ($this->cache_file && !$this->nocache) {
			//process the files

			$fp = fopen($this->cache_file, "w+");

			$lock = false;			
			do {
				$lock = flock($fp, LOCK_EX | LOCK_NB);

				//if not locked wait 200miliseconds and try again, until will be released
				if (!$lock) {
					usleep(200000);
				}
				
			} while (!$lock );

			fwrite($fp, $content);
			fclose($fp);
			flock($fp, LOCK_UN);
/*			

			Cfile::Save(
				$this->cache_file,
				$content
			);
*/
		}


		if ($write) {
			$this->setHeaders();


			echo $content;
			die();
		} else {
			return $content;
		}
		
	}


	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function getLastChangeDate() {
		$min = 0;

		foreach ($this->files as $key => $val) {
			if (is_array($val) && count($val)) {
				foreach ($val as $k => $v) {
					$min = max($min , $v["date"]);
				}				
			}			
		}
		
		return $min;
	}
	

	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function getProcessed() {

		if ($this->concatenate && $this->minify) {
			return $this->getMinified();
		} elseif  ($this->concatenate) {
			return $this->getConcatenated();
		} else {
			return $this->getSplitList();
		}	
	}


	private function getSplitList() {

		if ($this->nocache) {
			$suf ="?stamp=" . time();
		} elseif( $this->version ) {
			$suf = "?{$this->version}";
		}

		$base = $_SERVER["DOCUMENT_ROOT"];


		if (($base[strlen($base)-1] == "/" ) && (strlen($base) > 1)) {
			$base = substr($base , 0 , -1 );
		}

//			debug($this->files,1);

//		debug($base);
//		debug($base[strlen($base)-1],1);

		switch ($this->type) {
			case "css":
				if (count($this->files["first"])) {
					foreach ($this->files["first"] as $key => $val) {
						$val["file"] = str_replace($base , "" , $val["path"]);
						$content .= "@import url('{$val[file]}{$suf}'); \n";
					}			
				}

				if (count($this->files["files"])) {
					foreach ($this->files["files"] as $key => $val) {
						$val["file"] = str_replace($base , "" , $val["path"]);
						$content .= "@import url('{$val[file]}{$suf}'); \n";
					}			
				}

				if (count($this->files["last"])) {
					foreach ($this->files["last"] as $key => $val) {
						$val["file"] = str_replace($base , "" , $val["path"]);
						$content .= "@import url('{$val[file]}{$suf}'); \n";
					}			
				}
			break;

			case "js":
				if (count($this->files["first"])) {
					foreach ($this->files["first"] as $key => $val) {
						$val["file"] = str_replace($base , "" , $val["path"]);
						$content .= "document.write('<script src=\"{$val[file]}{$suf}\"></script>'); \n";												
					}			
				}

				if (count($this->files["files"])) {
					foreach ($this->files["files"] as $key => $val) {
						$val["file"] = str_replace($base , "" , $val["path"]);
						$content .= "document.write('<script src=\"{$val[file]}{$suf}\"></script>'); \n";			
					}			
				}

				if (count($this->files["last"])) {
					foreach ($this->files["last"] as $key => $val) {
						$val["file"] = str_replace($base , "" , $val["path"]);
						$content .= "document.write('<script src=\"{$val[file]}{$suf}\"></script>'); \n";			
					}			
				}

			break;
		}

		return $content;		
	}

	private function getConcatenated() {
		if (count($this->files["first"])) {
			foreach ($this->files["first"] as $key => $val) {
				$content .= Cfile::Get($val["path"]);
			}			
		}

		if (count($this->files["files"])) {
			foreach ($this->files["files"] as $key => $val) {
				$content .= Cfile::Get($val["path"]);
			}			
		}

		if (count($this->files["last"])) {
			foreach ($this->files["last"] as $key => $val) {
				$content .= Cfile::Get($val["path"]);
			}			
		}

		return $content;
	}

	private function getMinified() {

		switch ($this->type) {
			case "css":
				$minifier = new MatthiasMullie\Minify\CSS();
			break;

			case "js":
				$minifier = new MatthiasMullie\Minify\JS();
			break;
		}
		

		if (count($this->files["first"])) {
			foreach ($this->files["first"] as $key => $val) {
				$minifier->add($val["path"]);
			}			
		}

		if (count($this->files["files"])) {
			foreach ($this->files["files"] as $key => $val) {
				$minifier->add($val["path"]);
			}			
		}

		if (count($this->files["last"])) {
			foreach ($this->files["last"] as $key => $val) {
				$minifier->add($val["path"]);
			}			
		}

		return $minifier->minify();
	}

	
	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function setHeaders() {

		//set last change date
		header("ETag: " . filemtime($this->cache_file));
		
		//set length
		if ($this->cache_file) {
			$fsize = filesize($this->cache_file);

			if ($fsize) {
				header("Content-Length: " . $fsize); 
			}
			
		}
		

		//set encoding type
		switch ($this->type) {
			case "css":
				header("Content-type: text/css");
			break;

			case "js":
				header("Content-type: application/x-javascript");
			break;
		}
		
		//other stuff
		header("Cache-Control: max-age=2692000, public");
		header("Vary: Accept-Encoding");

	}

	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function setConcatenate($val) {
		$this->concatenate = $val;
		return $this;
	}
	
	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function setMinify($val) {
		$this->minify = $val;
		return $this;
	}

	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function removeFilesBySuffix($suffix) {

		foreach ($this->files as $key => $val) {
			foreach ($val as $k => $v) {
				foreach ($suffix as $_k => $_v) {
					if (stristr($k , $_v)) {
						unset($this->files[$key][$k]);
					}
				}
			}
		}

		return $this;
	}


	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function keepFilesBySuffix($suffix) {

		foreach ($this->files as $key => $val) {
			foreach ($val as $k => $v) {
				$keep = false;
				foreach ($suffix as $_k => $_v) {
					if (stristr($k , $_v)) {
						$keep = true;
					}
				}

				if (!$keep) {
					unset($this->files[$key][$k]);
				}			
			}
		}

		return $this;
	}

	
	
	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function debugFiles() {
		debug($this->files);

		return $this;
	}


	/**
	* description
	*
	* @param
	*
	* @return
	*
	* @access
	*/
	function GenerateCacheName() {
		return md5(serialize($this->files));
	}
	


}
