<?php
/*
* SPEEDYCACHE
* https://speedycache.com/
* (c) SpeedyCache Team
*/

namespace SpeedyCache;

if( !defined('SPEEDYCACHE_PRO_VERSION') ){
	die('HACKING ATTEMPT!');
}

class LazyLoad{
	static function init(){
		global $speedycache;
		
		$speedycache->lazy_load = array();
		$speedycache->lazy_load['exclude'] = array();
		$speedycache->lazy_load['host'] = '';
		$speedycache->lazy_load['placeholder'] = '';
		$url = parse_url(site_url());
		$speedycache->lazy_load['host'] = $url['host'];

		if(!empty($speedycache->options['lazy_load_keywords']) && $speedycache->options['lazy_load_keywords']){
			if(is_string($speedycache->options['lazy_load_keywords'])){
				$speedycache->lazy_load['exclude'] = explode(',', $speedycache->options['lazy_load_keywords']);
			} else {
				$speedycache->lazy_load['exclude'] = $speedycache->options['lazy_load_keywords'];
			}
		}
		
		self::set_placeholder();
	}

	static function set_placeholder(){
		global $speedycache;
		
		if(!empty($speedycache->options['lazy_load_placeholder']) && $speedycache->options['lazy_load_placeholder']){
			
			if($speedycache->options['lazy_load_placeholder'] === 'default'){
				$speedycache->lazy_load['placeholder'] = SPEEDYCACHE_PRO_URL . '/assets/images/image-palceholder.png';
			} else if($speedycache->options['lazy_load_placeholder'] === 'base64'){
				$speedycache->lazy_load['placeholder'] = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
			} else if($speedycache->options['lazy_load_placeholder'] === 'custom' && !empty($speedycache->options['lazy_load_placeholder_custom_url'])){
				$speedycache->lazy_load['placeholder'] = $speedycache->options['lazy_load_placeholder_custom_url'];
			}
			
			return;
		} 
		
		$speedycache->lazy_load['placeholder'] = SPEEDYCACHE_PRO_URL . '/assets/images/image-palceholder.png';
		return;
	}

	static function instagram($tag){
		$src = false;

		if(preg_match("/src\s*\=\s*[\"\']([^\"\']+sb-instagram\.min\.js)/", $tag, $out)){
			$src = $out[1];
		}

		if(empty($src)){
			return $tag;
		}

		$tmp_script = '<script type="text/javascript">'.
		"window.addEventListener('scroll',function(){".
		"(function(d,s){".
		"if(document.querySelectorAll("."\"script[src='\""." + s + "."\"']\"".").length > 0){return;}".
		"var t = d.createElement('script');".
		't.setAttribute("src", s);'.
		"d.body.appendChild(t);".
		'})(document, "'.$src.'");'.
		"});".
		"</script>\n";

		return $tmp_script;
	}

	static function mark_images($content){
		global $speedycache;

		if(speedycache_is_mobile()){
			return $content;
		}

		preg_match_all('/<img[^\>]+>/i', $content, $matches);

		if(count($matches[0]) <= 0){
			return $content;
		}

		foreach($matches[0] as $img){
			if(self::is_thumbnail($img) || self::is_third_party($img) || !self::is_full($img)){
				continue;
			}

			$tmp_img = $img;

			if(strpos($img, 'decoding') === FALSE){
				$tmp_img = preg_replace("/<img\s/", '<img decoding="async" ', $img);
			}

			$tmp_img = preg_replace("/<img\s/", '<img speedycache-lazyload-disable="true" ', $tmp_img);

			$content = str_replace($img, $tmp_img, $content);
		}

		return $content;
	}

	static function mark_attachment_page_images($attr, $attachment){

		if(speedycache_is_mobile()){
			return $attr;
		}

		if(isset($attr['src'])){
			if(self::is_thumbnail($attr['src'])){
				return $attr;
			}

			if(self::is_third_party($attr['src'])){
				return $attr;
			}

			if(!self::is_full('<img src="' . $attr['src'] . '" class="' . $attr['class'] . '">')){
				return $attr;
			}
		}

		if(empty($attachment)){
			return $attr;
		}

		$attr['speedycache-lazyload-disable'] = 'true';

		return $attr;
	}

	static function is_thumbnail($src){
		
		$resolution_pregs = array(
			'/\-[12]\d{0,2}x[12]\d{0,2}\.(jpg|jpeg|png)/i', // < 299x299
			'/\-[12]\d{0,2}x\d{0,2}\.(jpg|jpeg|png)/i', // < 299x99
			'/\-\d{0,2}x[12]\d{0,2}\.(jpg|jpeg|png)/i', // < 99x299
			'/\-\d{0,2}x\d{0,2}\.(jpg|jpeg|png)/i' // < 99x99
		);
		
		foreach($resolution_pregs as $resolution_preg){
			if(preg_match($resolution_preg, $src)){
				return true;
			}
		}

		return false;
	}

	static function is_third_party($src){
		global $speedycache;
		
		if(preg_match('/' . preg_quote($speedycache->lazy_load['host'], '/') . '/i', $src)){
			return false;
		}

		return true;
	}

	static function is_full($img){
		
		// to check homepage. sometimes is_home() does not work
		if(isset($_SERVER['REQUEST_URI']) && strlen($_SERVER['REQUEST_URI']) < 2){
			return false;
		}

		if(is_home() || is_archive()){
			return false;
		}

		if(preg_match("/-\d+x\d+\.(jpg|jpeg|png)/i", $img)){
			if(preg_match("/\sclass\=[\"\'][^\"\']*size-medium[^\"\']*[\"\']/", $img)){
				return false;
			}
		}

		return true;
	}

	static function is_exclude($source){
		global $speedycache;
		
		/*
			to disable lazy load for rav-slider images
			<img data-bgposition="center center" data-bgparallax="8" data-bgfit="cover" data-bgrepeat="no-repeat"class="rev-slidebg" data-no-retina>
			<img width="1920" height="600" data-parallax="8" class="rev-slidebg" data-no-retina>
		*/
		if(preg_match('/class\="rev-slidebg"/i', $source) && preg_match("/data-(bg)*parallax\=/i", $source)){
			return true;
		}

		/*
			to exclude img tag which exists in json
			var xxx = {"content":"<a href=\"https:\/\/www.abc.com\"><img src='https:\/\/www.abc.com\/img.gif' \/><\/a>"}
		*/
		if(preg_match("/\\\\\//", $source)){
			return true;
		}

		/*
			<img src="my-image.jpg" data-no-lazy="1" alt="" width="100" width="100" />
			<img src="my-image.jpg" data-skip-lazy="1" alt="" width="100" width="100" />
		*/
		if(preg_match("/data-(no|skip)-lazy\s*\=\s*[\"\']\s*1\s*[\"\']/i", $source)){
			return true;
		}

		//Slider Revolution
		//<img src="dummy.png" data-lazyload="transparent.png" data-bgposition="center center" data-bgfit="cover" data-bgrepeat="no-repeat" data-bgparallax="off" class="rev-slidebg" data-no-retina>
		if(preg_match("/\sdata-lazyload\=[\"\']/i", $source)){
			return true;
		}

		//<img src="dummy.png" data-lazy-src="transparent.png">
		//<img src="dummy.png" data-gg-lazy-src="transparent.png">
		if(preg_match("/\sdata-([a-z-]*)lazy-src\=[\"\']/i", $source)){
			return true;
		}

		//<div style="background-image:url(&#039;https://www.g.com/site-data/plugins/bold-page-builder/img/image-palceholder.png&#039;);background-position:top;background-size:cover;" data-background_image_src="https://www.g.com/site-data/1.jpg">
		if(preg_match("/\sdata-background_image_src\=[\"\']/i", $source)){
			return true;
		}

		/*
		Smash Balloon Social Photo Feed
		<img src="https://site.com/site-data/plugins/instagram-feed/img/placeholder.png"
		*/
		if(preg_match('/instagram-feed\/img\/placeholder\.png/i', $source)){
			return true;
		}

		// don't to the replacement if the image is a data-uri
		if(preg_match("/src\=[\'\"]data\:image/i", $source)){
			return true;
		}


		foreach((array)$speedycache->lazy_load['exclude'] as $key => $value){
			if(preg_match('/' . preg_quote($value, '/') . '/i', $source)){
				return true;
			}
		}

		return false;
	}

	static function video($data, $inline_scripts){
		global $speedycache;
		
		if(isset($speedycache->settings['noscript'])){
			$inline_scripts = $inline_scripts . $speedycache->settings['noscript'];
		}

		$video_list = array();
		$video_start_index = false;

		for ($i = 0; $i < strlen($data); $i++){
			if(isset($data[$i - 5])){
				if(substr($data, $i - 5, 6) == '<video'){
					$video_start_index = $i - 5;
				}
			}

			if(isset($data[$i - 7])){
				if($video_start_index){
					if(substr($data, $i - 7, 8) == '</video>'){
						array_push($video_list, array('start' => $video_start_index, 'end' => $i));
						$video_start_index = false;
					}
				}
			}
		}

		if(!empty($video_list)){
			foreach(array_reverse($video_list) as $key => $value){
				$video_html = substr($data, $value['start'], ($value['end'] - $value['start'] + 1));

				if(self::is_exclude($video_html)){
					continue;
				}

				$video_html = '<noscript data-type="speedycache">' . $video_html . '</noscript>';

				$data = substr_replace($data, $video_html, $value['start'], ($value['end'] - $value['start'] + 1));
			}
		}

		return $data;
	}

	static function background($content, $inline_scripts){
		global $speedycache;

		if(isset($speedycache->settings['noscript'])){
			$inline_scripts = $inline_scripts . $speedycache->settings['noscript'];
		}

		preg_match_all('/<(div|span|a|section|li)\s[^\>]*style\s*\=\s*[\"\'][^\"\']*(background\-image\s*\:\s*url\s*\(([^\)\(]+)\)\;?)[^\"\']*[\"\'][^\>]*>/i', $content, $matches, PREG_SET_ORDER);

		if(count($matches) > 0){
			/*
				[0] = full
				[1] = tag
				[2] = backgound image
				[3] = url
			*/
			foreach($matches as $key => $div){
				// don't to the replacement if the image appear in js
				if(preg_match("/" . preg_quote($div[0], '/') . '/i', $inline_scripts)){
					continue;
				}

				if(self::is_exclude($div[0])){
					continue;
				}

				$tmp = $div[0];
				//to remove backgound attribute
				$tmp = str_replace($div[2], '', $tmp);
				//to add lazy load attribute
				$div[3] = preg_replace("/[\"\']/", '', $div[3]);
				$tmp = preg_replace("/<([a-z]{1,4})\s/i", "<$1 data-speedycache-original-src='" . $div[3] . "' ", $tmp);

				$content = str_replace($div[0], $tmp, $content);
			}
		}

		return $content;
	}

	static function images($content, $inline_scripts){
		global $speedycache;

		if(isset($speedycache->settings['noscript'])){
			$inline_scripts = $inline_scripts . $speedycache->settings['noscript'];
		}

		$offset = 2;

		preg_match_all('/<img[^\>]+>/i', $content, $matches);
		$count = 0;
		if(count($matches[0]) > 0){
			foreach($matches[0] as $key => $img){
				$count++;
				$tmp_img = false;
				
				if(preg_match("/onload=[\"\']/i", $img)){
					continue;
				}

				if(preg_match("/src\s*\=\s*[\'\"]\s*[\'\"]/i", $img)){
					continue;
				}
				
				// Excluding images from lazy loading and adding fetchpriority to high,
				// as we need to load that image faster if we are not lazy loading them
				if(!empty($speedycache->options['exclude_above_fold']) && is_numeric($speedycache->options['exclude_above_fold'])){
					if($count < $speedycache->options['exclude_above_fold']){
						$tmp_img = $img;
						$img = preg_replace('/fetchpriority=["\'].*["\']/Us', '', $img);
						$img = preg_replace('/loading=["\'].*["\']/Us', '', $img);
						$img = preg_replace('/decoding=["\'].*["\']/Us', '', $img);
						
						$img = str_replace('<img', '<img fetchpriority="high" loading="eager" decoding="async" ', $img);
						$content = str_replace($tmp_img, $img, $content);

						continue;
					}
				}

				$should_continue = self::replace_img($inline_scripts, $img, $content);
				
				if(!empty($should_continue)){
					continue;
				}

				$tmp_img = preg_replace("/\sspeedycache-lazyload-disable\=[\"\']true[\"\']\s*/", " ", $img);
				$content = str_replace($img, $tmp_img, $content);
			}
		}

		return $content;
	}

	static function inject_data_src($img){
		global $speedycache;
		
		if(!preg_match("/\ssrc\s*\=[\"\'][^\"\']+[\"\']/i", $img)){
			return $img;
		}
		
		if(preg_match("/mc\.yandex\.ru\/watch/i", $img)){
			return $img;
		}

		$tmp_img = $img;
		$tmp_img = preg_replace('/\ssrc\s*\=/i', ' data-speedycache-original-src=', $tmp_img);
		$tmp_img = preg_replace('/\ssrcset\s*\=/i', ' data-speedycache-original-srcset=', $tmp_img);
		$tmp_img = preg_replace('/\ssizes\s*\=/i', ' data-speedycache-original-sizes=', $tmp_img);
		$tmp_img = preg_replace('/<img\s/i', '<img onload="speedycachell.r(this,true);" src="' . $speedycache->lazy_load['placeholder'] . "$2\" ", $tmp_img);

		// to add alt attribute for seo
		$tmp_img = preg_replace('/\salt\s*\=\s*[\"|\']\s*[\"|\']/', ' alt="blank"', $tmp_img);
		if(!preg_match('/\salt\s*\=\s*/i', $tmp_img)){
			$tmp_img = preg_replace('/<img\s+/i', '<img alt="blank" ', $tmp_img);
		}

		return $tmp_img;
	}

	static function replace_img($inline_scripts, $img, &$content){
		
		$tmp_img = false;
		
		// Don't do the replacement if the image appear in js
		if(preg_match('/' . preg_quote($img, '/') . '/i', $inline_scripts)){
			return false;
		}

		// Don't do the replacement if quote of src does not exist
		if(!preg_match("/\ssrc\s*\=[\"\']/i", $img) && preg_match("/<img/i", $img)){
			return true;
		}

		if(self::is_exclude($img)){
			$tmp_img = preg_replace('/\sspeedycache-lazyload-disable\=[\"\']true[\"\']\s*/', ' ', $img);
		} else if(preg_match('/speedycache-lazyload-disable/', $img)){
			$tmp_img = preg_replace('/\sspeedycache-lazyload-disable\=[\"\']true[\"\']\s*/', ' ', $img);
		} else {
			$tmp_img = self::inject_data_src($img);
		}
		
		if($tmp_img){
			$content = str_replace($img, $tmp_img, $content);
		}
		
		return true;
	}

	static function iframe($content, $inline_scripts){
		
		preg_match_all('/<iframe[^\>]+>/i', $content, $matches);

		if(count($matches[0]) > 0){
			foreach($matches[0] as $iframe){
				if(self::is_exclude($iframe)){
					continue;
				}

				self::iframe_replace($inline_scripts, $iframe, $content);
			}
		}

		return $content;
	}

	static function iframe_replace($inline_scripts, $iframe, &$content){
		// don't to the replacement if the frame appear in js
		if(preg_match('/' . preg_quote($iframe, "/") . '/i', $inline_scripts)){
			return;
		}

		if(preg_match("/onload=[\"\']/i", $iframe)){
			return;
		}

		if(preg_match("/(youtube|youtube-nocookie)\.com\/embed/i", $iframe) && !preg_match("/videoseries\?list/i", $iframe)){
			// to exclude /videoseries?list= because of problem with getting thumbnail
			$tmp_iframe = preg_replace("/\ssrc\=[\"\'](https?\:)?\/\/(www\.)?(youtube|youtube-nocookie)\.com\/embed\/([^\"\']+)[\"\']/i", " onload=\"speedycachell.r(this,true);\" data-speedycache-original-src=\"" . SPEEDYCACHE_WP_CONTENT_URL . "/plugins/".SPEEDYCACHE_PRO_BASE_NAME."/main/youtube.html#$4\"", $iframe);
		} else {
			$tmp_iframe = preg_replace("/\ssrc\=/i", " onload=\"speedycachell.r(this,true);\" data-speedycache-original-src=", $iframe);
		}

		$content = str_replace($iframe, $tmp_iframe, $content);

	}

	static function get_js_source(){
		
		$js = "\n<script data-speedycache-render=\"false\">" . file_get_contents(SPEEDYCACHE_PRO_DIR . '/assets/js/lazy-load.js') . "</script>\n";

		/**
		  * Structure of this array is
		  * searchable => replacer
		*/
		$js_replaces = array(
			'/\/\*[^\n]+\*\//' =>  '', //to remove comments
			'/var\sself/' => 'var s',
			'/self\./' => 's.',
			'/speedycache_lazy_load/' => 'speedycachell',
			'/(\.?)init(\:?)/' => '$1i$2',
			'/(\.?)load_images(\:?)/' => '$1li$2',
			'/\s*(\+|\=|\:|\;|\{|\}|\,)\s*/' => '$1',
			'/originalsrcset/' => 'ot',
			'/originalsrc/' => 'oc',
			'/load_sources/' => 'ls',
			'/set_source/' => 'ss',
			'/sources/' => 's',
			'/winH/' => 'w',
			'/number/' => 'n',
			'/elemRect/' => 'er',
			'/parentRect/' => 'pr',
			'/parentOfE/' => 'p',
			'/top(\=|\+)/' => 't$1'
		);
		
		foreach($js_replaces as $search => $replace){
			$js = preg_replace($search, $replace, $js);
		}

		return $js;
	}

}

