<?php
// Exit if accessed directly
if( !defined('ABSPATH') ) {
	exit;
}

class WWLL_Configurate {

	/**
	 * @param WCL_Plugin $plugin
	 */
	public function __construct($plugin)
	{
		if( !$plugin instanceof WCL_Plugin ) {
			throw new \Exception('Invalid $plugin argument type passed.');
		}

		$this->plugin = $plugin;

		$this->register_actions_and_filters();
	}

	/**
	 * Register actions and filters
	 */
	public function register_actions_and_filters()
	{
		add_action('wp', array($this, 'disable_on_apm'));
		add_action('wp_footer', array($this, 'lazy_load_script'), PHP_INT_MAX);
		add_action('wp_enqueue_scripts', array($this, 'lazy_load_enqueue'), PHP_INT_MAX);
		add_filter('get_avatar', array($this, 'lazy_load_images'), PHP_INT_MAX);
		add_filter('the_content', array($this, 'lazy_load_images'), PHP_INT_MAX);
		add_filter('widget_text', array($this, 'lazy_load_images'), PHP_INT_MAX);
		add_filter('get_image_tag', array($this, 'lazy_load_images'), PHP_INT_MAX);
		add_filter('post_thumbnail_html', array($this, 'lazy_load_images'), PHP_INT_MAX);
		add_filter('wbcr/wll/lazyload_html', array($this, 'lazyload_on_scrset'));
		add_filter('wp_get_attachment_image_attributes', array($this, 'lazyload_get_attachment_image'), 11);
		add_action('init', array($this, 'lazyload_smilies'));
		add_filter('the_content', array($this, 'lazyload_iframes'), PHP_INT_MAX);
		add_filter('widget_text', array($this, 'lazyload_iframes'), PHP_INT_MAX);
	}

	/**
	 * Removes LazyLoad when on an AMP version of a post with the AMP for WordPress plugin from Auttomatic
	 */
	public function disable_on_apm()
	{
		if( function_exists('is_amp_endpoint') && is_amp_endpoint() ) {
			add_filter('wbcr/wll/lazyload', '__return_false');
			add_filter('wbcr/wll/lazyload_iframes', '__return_false');
		}
	}

	/**
	 * Set lazyload options
	 */
	public function lazy_load_script()
	{
		if( !$this->plugin->getPopulateOption('images', false) && !$this->plugin->getPopulateOption('iframes', false) || !apply_filters('wbcr/wll/lazyload', true) ) {
			return;
		}

		$suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';

		/**
		 * Filters the threshold at which lazyload is triggered
		 *
		 * @param int $threshold Threshold value.
		 */
		$threshold = apply_filters('wbcr/wll/lazyload_threshold', 300);

		$elements = array();

		if( $this->plugin->getPopulateOption('images', false) ) {
			$elements[] = 'img';
		}

		if( $this->plugin->getPopulateOption('iframes', false) ) {
			$elements[] = 'iframe';
		}

		$js_url = WWLL_PLUGIN_URL . '/assets/js/';

		echo '<script>(function(w, d){
	var b = d.getElementsByTagName("body")[0];
	var s = d.createElement("script"); s.async = true;
	s.src = !("IntersectionObserver" in w) ? "' . $js_url . 'lazyload-8.11' . $suffix . '.js" : "' . $js_url . 'lazyload-10.11.1' . $suffix . '.js";
	w.lazyLoadOptions = {
		elements_selector: "' . esc_attr(implode(',', $elements)) . '",
		data_src: "lazy-src",
		data_srcset: "lazy-srcset",
		data_sizes: "lazy-sizes",
		skip_invisible: false,
		class_loading: "lazyloading",
		class_loaded: "lazyloaded",
		threshold: ' . esc_attr($threshold) . ',
		callback_load: function(element) {
			if ( element.tagName === "IFRAME" && element.dataset.rocketLazyload == "fitvidscompatible" ) {
				if (element.classList.contains("lazyloaded") ) {
					if (typeof window.jQuery != "undefined") {
						if (jQuery.fn.fitVids) {
							jQuery(element).parent().fitVids();
						}
					}
				}
			}
		}
	};
	b.appendChild(s);
}(window, document));

// Listen to the Initialized event
window.addEventListener(\'LazyLoad::Initialized\', function (e) {
	// Get the instance and puts it in the lazyLoadInstance variable
	var lazyLoadInstance = e.detail.instance;

	var observer = new MutationObserver(function(mutations) {
		mutations.forEach(function(mutation) {
			lazyLoadInstance.update();
		} );
	} );
	
	var b      = document.getElementsByTagName("body")[0];
	var config = { childList: true, subtree: true };
	
	observer.observe(b, config);
}, false);
</script>';

		if( $this->plugin->getPopulateOption('youtube', false) ) {
			/**
			 * Filters the resolution of the YouTube thumbnail
			 *
			 * @param string $thumbnail_resolution The resolution of the thumbnail. Accepted values: default, mqdefault, sddefault, hqdefault, maxresdefault
			 */
			$thumbnail_resolution = apply_filters('wbcr/wll/lazyload_youtube_thumbnail_resolution', 'hqdefault');

			echo <<<HTML
		<script>function lazyLoadThumb(e){var t='<img src="https://i.ytimg.com/vi/ID/$thumbnail_resolution.jpg">',a='<div class="play"></div>';return t.replace("ID",e)+a}function lazyLoadYoutubeIframe(){var e=document.createElement("iframe"),t="https://www.youtube.com/embed/ID?autoplay=1";t+=0===this.dataset.query.length?'':'&'+this.dataset.query;e.setAttribute("src",t.replace("ID",this.dataset.id)),e.setAttribute("frameborder","0"),e.setAttribute("allowfullscreen","1"),this.parentNode.replaceChild(e,this)}document.addEventListener("DOMContentLoaded",function(){var e,t,a=document.getElementsByClassName("rll-youtube-player");for(t=0;t<a.length;t++)e=document.createElement("div"),e.setAttribute("data-id",a[t].dataset.id),e.setAttribute("data-query", a[t].dataset.query),e.innerHTML=lazyLoadThumb(a[t].dataset.id),e.onclick=lazyLoadYoutubeIframe,a[t].appendChild(e)});</script>
HTML;
		}
	}

	/**
	 * Enqueue the lazyload script
	 */
	public function lazy_load_enqueue()
	{
		if( !$this->plugin->getPopulateOption('images', true) && !$this->plugin->getPopulateOption('iframes', true) || !apply_filters('wbcr/wll/lazyload', true) ) {
			return;
		}

		if( $this->plugin->getPopulateOption('youtube', true) ) {
			$css = '.rll-youtube-player{position:relative;padding-bottom:56.23%;height:0;overflow:hidden;max-width:100%;background:#000;margin:5px}.rll-youtube-player iframe{position:absolute;top:0;left:0;width:100%;height:100%;z-index:100;background:0 0}.rll-youtube-player img{bottom:0;display:block;left:0;margin:auto;max-width:100%;width:100%;position:absolute;right:0;top:0;border:none;height:auto;cursor:pointer;-webkit-transition:.4s all;-moz-transition:.4s all;transition:.4s all}.rll-youtube-player img:hover{-webkit-filter:brightness(75%)}.rll-youtube-player .play{height:72px;width:72px;left:50%;top:50%;margin-left:-36px;margin-top:-36px;position:absolute;background:url(' . WWLL_PLUGIN_URL . '/assets/img/youtube.png) no-repeat;cursor:pointer}';

			wp_register_style('wbcr-wll', false);
			wp_enqueue_style('wbcr-wll');
			wp_add_inline_style('wbcr-wll', $css);
		}
	}

	/**
	 * Replace Gravatar, thumbnails, images in post content and in widget text by LazyLoad
	 *
	 * @param string $html HTML code to parse.
	 * @return string Updated HTML code
	 */
	public function lazy_load_images($html)
	{
		// Don't LazyLoad if the thumbnail is in admin, a feed, REST API or a post preview.
		if( !$this->plugin->getPopulateOption('images', false) || is_admin() || is_feed() || is_preview() || (defined('REST_REQUEST') && REST_REQUEST) || empty($html) || (defined('DONOTLAZYLOAD') && DONOTLAZYLOAD) || wp_script_is('twentytwenty-twentytwenty', 'enqueued') ) {
			return $html;
		}

		// You can stop the LalyLoad process with a hook.
		if( !apply_filters('wbcr/wll/lazyload', true) ) {
			return $html;
		}

		return preg_replace_callback('#<img([^>]*) src=("(?:[^"]+)"|\'(?:[^\']+)\'|(?:[^ >]+))([^>]*)>#', array(
			$this,
			'lazy_load_replace_callback'
		), $html);
	}

	/**
	 * Used to check if we have to LazyLoad this or not
	 *
	 * @param string $matches a string matching the pattern to find images in HTML code.
	 * @return string Updated string with lazyload data
	 */
	function lazy_load_replace_callback($matches)
	{
		if( function_exists('wr2x_picture_rewrite') ) {
			if( wr2x_get_retina(trailingslashit(ABSPATH) . wr2x_get_pathinfo_from_image_src(trim($matches[2], '"'))) ) {
				return $matches[0];
			}
		}

		$excluded_attributes = apply_filters('wbcr/wll/lazyload_excluded_attributes', array(
			'data-no-lazy=',
			'data-lazy-original=',
			'data-lazy-src=',
			'data-src=',
			'data-lazysrc=',
			'data-lazyload=',
			'data-bgposition=',
			'data-envira-src=',
			'fullurl=',
			'lazy-slider-img=',
			'data-srcset=',
			'class="ls-l',
			'class="ls-bg',
		));

		$excluded_src = apply_filters('wbcr/wll/lazyload_excluded_src', array(
			'/wpcf7_captcha/',
			'timthumb.php?src',
		));

		if( $this->is_excluded_lazyload($matches[1] . $matches[3], $excluded_attributes) || $this->is_excluded_lazyload($matches[2], $excluded_src) ) {
			return $matches[0];
		}

		/**
		 * Filter the LazyLoad placeholder on src attribute
		 *
		 * @param string $placeholder Placeholder that will be printed.
		 */
		$placeholder = apply_filters('wbcr/wll/lazyload_placeholder', '');

		$img = sprintf('<img%1$s src="%4$s" data-lazy-src=%2$s%3$s>', $matches[1], $matches[2], $matches[3], $placeholder);

		$img_noscript = sprintf('<noscript><img%1$s src=%2$s%3$s></noscript>', $matches[1], $matches[2], $matches[3]);

		/**
		 * Filter the LazyLoad HTML output
		 *
		 * @param array $img Output that will be printed
		 */
		$img = apply_filters('wbcr/wll/lazyload_html', $img, true);

		return $img . $img_noscript;
	}

	/**
	 * Determine if the current image should be excluded from lazyload
	 *
	 * @param string $string String to search.
	 * @param array $excluded_values Array of excluded values to search in the string.
	 * @return bool True if one of the excluded values was found, false otherwise
	 */
	function is_excluded_lazyload($string, $excluded_values)
	{
		foreach($excluded_values as $excluded_value) {
			if( strpos($string, $excluded_value) !== false ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Compatibility with images with srcset attribute
	 *
	 * @param string $html the HTML code to parse.
	 * @return string the updated HTML code
	 */
	function lazyload_on_scrset($html)
	{
		if( preg_match('/srcset=("(?:[^"]+)"|\'(?:[^\']+)\'|(?:[^ >]+))/i', $html) ) {
			$html = str_replace('srcset=', 'data-lazy-srcset=', $html);
		}

		if( preg_match('/sizes=("(?:[^"]+)"|\'(?:[^\']+)\'|(?:[^ >]+))/i', $html) ) {
			$html = str_replace('sizes=', 'data-lazy-sizes=', $html);
		}

		return $html;
	}

	/**
	 * Applies lazyload on images displayed using wp_get_attachment_image()
	 *
	 * @param array $attr Attributes for the image markup.
	 * @return array
	 */
	function lazyload_get_attachment_image($attr)
	{
		// Don't LazyLoad if the thumbnail is in admin, a feed, REST API or a post preview.
		if( !$this->plugin->getPopulateOption('images', false) || is_admin() || is_feed() || is_preview() || (defined('REST_REQUEST') && REST_REQUEST) || empty($attr) || (defined('DONOTLAZYLOAD') && DONOTLAZYLOAD) || wp_script_is('twentytwenty-twentytwenty', 'enqueued') ) {
			return $attr;
		}

		// You can stop the LalyLoad process with a hook.
		if( !apply_filters('wbcr/wll/lazyload', true) ) {
			return $attr;
		}

		$attr['data-lazy-src'] = $attr['src'];
		$attr['src'] = apply_filters('wbcr/wll/lazyload_placeholder', '');

		if( isset($attr['srcset']) ) {
			$attr['data-lazy-srcset'] = $attr['srcset'];
			unset($attr['srcset']);
		}

		if( isset($attr['sizes']) ) {
			$attr['data-lazy-sizes'] = $attr['sizes'];
			unset($attr['sizes']);
		}

		return $attr;
	}

	/**
	 * Replace WordPress smilies by Lazy Load
	 *
	 * @since 1.0
	 */
	function lazyload_smilies()
	{
		if( !$this->plugin->getPopulateOption('images', false) || !apply_filters('wbcr/wll/lazyload', true) ) {
			return;
		}

		remove_filter('the_content', 'convert_smilies');
		remove_filter('the_excerpt', 'convert_smilies');
		remove_filter('comment_text', 'convert_smilies', 20);

		add_filter('the_content', array($this, 'convert_smilies'));
		add_filter('the_excerpt', array($this, 'convert_smilies'));
		add_filter('comment_text', array($this, 'convert_smilies'), 20);
	}

	/**
	 * Convert text equivalent of smilies to images.
	 *
	 * @param string $text Text to process.
	 * @return string Modified text
	 */
	function convert_smilies($text)
	{
		global $wp_smiliessearch;

		if( !get_option('use_smilies') || empty($wp_smiliessearch) ) {
			return $text;
		}

		$output = '';
		// HTML loop taken from texturize function, could possible be consolidated.
		$textarr = preg_split('/(<.*>)/U', $text, -1, PREG_SPLIT_DELIM_CAPTURE); // capture the tags as well as in between.
		$stop = count($textarr);// loop stuff.

		// Ignore proessing of specific tags.
		$tags_to_ignore = 'code|pre|style|script|textarea';
		$ignore_block_element = '';

		for($i = 0; $i < $stop; $i++) {
			$content = $textarr[$i];

			// If we're in an ignore block, wait until we find its closing tag.
			if( '' === $ignore_block_element && preg_match('/^<(' . $tags_to_ignore . ')>/', $content, $matches) ) {
				$ignore_block_element = $matches[1];
			}

			// If it's not a tag and not in ignore block.
			if( '' === $ignore_block_element && strlen($content) > 0 && '<' !== $content[0] ) {
				$content = preg_replace_callback($wp_smiliessearch, array($this, 'translate_smiley'), $content);
			}

			// did we exit ignore block.
			if( '' !== $ignore_block_element && '</' . $ignore_block_element . '>' === $content ) {
				$ignore_block_element = '';
			}

			$output .= $content;
		}

		return $output;
	}

	/**
	 * Convert one smiley code to the icon graphic file equivalent.
	 *
	 * @param array $matches An array of matching content.
	 * @return string HTML code for smiley
	 */
	function translate_smiley($matches)
	{
		global $wpsmiliestrans;

		if( count($matches) === 0 ) {
			return '';
		}

		$smiley = trim(reset($matches));
		$img = $wpsmiliestrans[$smiley];

		$matches = array();
		$ext = preg_match('/\.([^.]+)$/', $img, $matches) ? strtolower($matches[1]) : false;
		$image_exts = array('jpg', 'jpeg', 'jpe', 'gif', 'png');

		// Don't convert smilies that aren't images - they're probably emoji.
		if( !in_array($ext, $image_exts, true) ) {
			return $img;
		}

		/**
		 * Filter the Smiley image URL before it's used in the image element.
		 *
		 * @param string $smiley_url URL for the smiley image.
		 * @param string $img Filename for the smiley image.
		 * @param string $site_url Site URL, as returned by site_url().
		 * @since 2.9.0
		 *
		 */
		$src_url = apply_filters('smilies_src', includes_url("images/smilies/$img"), $img, site_url());

		// Don't LazyLoad if process is stopped for these reasons.
		if( !apply_filters('wbcr/wll/lazyload', true) || is_feed() || is_preview() ) {
			return sprintf(' <img src="%s" alt="%s" class="wp-smiley" /> ', esc_url($src_url), esc_attr($smiley));
		}

		$placeholder = apply_filters('wbcr/wll/lazyload_placeholder', '');

		return sprintf(' <img src="%s" data-lazy-src="%s" alt="%s" class="wp-smiley" /> ', $placeholder, esc_url($src_url), esc_attr($smiley));
	}

	/**
	 * Replace iframes by LazyLoad
	 *
	 * @param string $html the HTML code to parse.
	 * @return string the updated HTML code
	 */
	function lazyload_iframes($html)
	{
		// Don't LazyLoad if process is stopped for these reasons.
		if( !$this->plugin->getPopulateOption('iframes', false) || !apply_filters('wbcr/wll/lazyload_iframes', true) || is_feed() || is_preview() || (defined('REST_REQUEST') && REST_REQUEST) || empty($html) || (defined('DONOTLAZYLOAD') && DONOTLAZYLOAD) ) {
			return $html;
		}

		preg_match_all('/<iframe.*\ssrc=["|\'](.+)["|\'].*(>\s*<\/iframe>)/iU', $html, $matches, PREG_SET_ORDER);

		if( empty($matches) ) {
			return $html;
		}

		foreach($matches as $iframe) {
			// Don't mess with the Gravity Forms ajax iframe.
			if( strpos($iframe[0], 'gform_ajax_frame') ) {
				continue;
			}

			// Don't lazyload if iframe has data-no-lazy attribute.
			if( strpos($iframe[0], 'data-no-lazy=') ) {
				continue;
			}

			if( $this->plugin->getPopulateOption('youtube', false) && false !== strpos($iframe[1], 'youtube') ) {
				$youtube_id = $this->lazyload_get_youtube_id_from_url($iframe[1]);

				if( !$youtube_id ) {
					continue;
				}

				$query = wp_parse_url($iframe[1], PHP_URL_QUERY);

				/**
				 * Filter the LazyLoad HTML output on Youtube iframes
				 *
				 * @param array $html Output that will be printed.
				 * @since 1.4.3
				 *
				 */
				$youtube_lazyload = apply_filters('wbcr/wll/lazyload_youtube_html', '<div class="rll-youtube-player" data-id="' . esc_attr($youtube_id) . '" data-query="' . esc_attr($query) . '"></div>');
				$youtube_lazyload .= '<noscript>' . $iframe[0] . '</noscript>';

				$html = str_replace($iframe[0], $youtube_lazyload, $html);

				continue;
			}

			/**
			 * Filter the LazyLoad placeholder on src attribute
			 *
			 * @param string $placeholder placeholder that will be printed.
			 * @since 1.1
			 *
			 */
			$placeholder = apply_filters('wbcr/wll/lazyload_placeholder', 'about:blank');
			$iframe_noscript = '<noscript>' . $iframe[0] . '</noscript>';
			$iframe_lazyload = str_replace($iframe[1], $placeholder, $iframe[0]);
			$iframe_lazyload = str_replace($iframe[2], ' data-rocket-lazyload="fitvidscompatible" data-lazy-src="' . esc_url($iframe[1]) . '"' . $iframe[2], $iframe_lazyload);

			/**
			 * Filter the LazyLoad HTML output on iframes
			 *
			 * @param array $html Output that will be printed.
			 */
			$iframe_lazyload = apply_filters('wbcr/wll/lazyload_iframe_html', $iframe_lazyload);
			$iframe_lazyload .= $iframe_noscript;

			$html = str_replace($iframe[0], $iframe_lazyload, $html);
		}

		return $html;
	}

	/**
	 * Gets youtube video ID from URL
	 *
	 * @param string $url URL to parse.
	 * @return string     Youtube video id or false if none found.
	 */
	function lazyload_get_youtube_id_from_url($url)
	{
		$pattern = '#^(?:https?://)?(?:www\.)?(?:youtu\.be|youtube\.com|youtube-nocookie\.com)/(?:embed/|v/|watch/?\?v=)([\w-]{11})#iU';
		$result = preg_match($pattern, $url, $matches);

		if( !$result ) {
			return false;
		}

		if( 'videoseries' === $matches[1] ) {
			return false;
		}

		return $matches[1];
	}

}