<?php

/**
 * This class configures hide admin notices
 *
 * Github: https://github.com/alexkovalevv
 *
 * @author        Alexander Kovalev <alex.kovalevv@gmail.com>
 * @copyright (c) 2018 Webraftic Ltd
 * @version       1.0
 */

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

class WDN_ConfigHideNotices extends Wbcr_FactoryClearfy219_Configurate {

	public function registerActionsAndFilters()
	{
		if( is_admin() ) {
			$hide_notices_type = $this->getPopulateOption('hide_admin_notices');

			if( $hide_notices_type != 'not_hide' ) {
				add_action('admin_print_scripts', [$this, 'catchNotices'], 999);

				if( empty($hide_notices_type) || $hide_notices_type == 'only_selected' ) {
					add_action('admin_head', [$this, 'printNotices'], 999);
				}

				if( !empty($hide_notices_type) ) {
					add_action('admin_bar_menu', [$this, 'notificationsPanel'], 999);
					add_action('admin_enqueue_scripts', [$this, 'notificationsPanelStyles']);
				}
			}
		}
	}

	public function printNotices()
	{
		if( is_multisite() && is_network_admin() ) {
			add_action('network_admin_notices', [$this, 'noticesCollection']);
		} else {
			add_action('admin_notices', [$this, 'noticesCollection']);
		}
	}


	public function notificationsPanelStyles()
	{
		if( !$this->getPopulateOption('show_notices_in_adminbar', false) && current_user_can('manage_network') ) {
			return;
		}

		wp_enqueue_style('wbcr-notification-panel-styles', WDN_PLUGIN_URL . '/admin/assets/css/notifications-panel.css', [], $this->plugin->getPluginVersion());
		wp_enqueue_script('wbcr-notification-panel-scripts', WDN_PLUGIN_URL . '/admin/assets/js/notifications-panel.js', [], $this->plugin->getPluginVersion());
	}

	public function notificationsPanel(&$wp_admin_bar)
	{
		if( !$this->getPopulateOption('show_notices_in_adminbar', false) ) {
			return;
		}

		if( current_user_can('manage_options') || current_user_can('manage_network') ) {
			$titles = [];

			$notifications = get_user_meta(get_current_user_id(), WDN_Plugin::app()->getOptionName('hidden_notices'), true);

			if( empty($notifications) ) {
				return;
			}

			$cont_notifications = sizeof($notifications);

			// Add top menu
			$wp_admin_bar->add_menu([
				'id' => 'wbcr-han-notify-panel',
				'parent' => 'top-secondary',
				'title' => sprintf(__('Notifications %s', 'disable-admin-notices'), '<span class="wbcr-han-adminbar-counter">' . $cont_notifications . '</span>'),
				'href' => false
			]);

			// loop
			if( !empty($notifications) ) {
				$i = 0;
				foreach($notifications as $notice_id => $message) {
					$message = $this->getExcerpt(stripslashes($message), 0, 350);
					$message .= '<div class="wbcr-han-panel-restore-notify-line">';
					$message .= '<a href="#" data-nonce="' . wp_create_nonce($this->plugin->getPluginName() . '_ajax_restore_notice_nonce');
					$message .= '" data-notice-id="' . esc_attr($notice_id) . '" class="wbcr-han-panel-restore-notify-link">';
					$message .= __('Restore notice', 'clearfy') . (isset($titles[$notice_id]) ? ' (' . $titles[$notice_id] . ')' : '');
					$message .= '</a></div>';

					$wp_admin_bar->add_menu([
						'id' => 'wbcr-han-notify-panel-item-' . $i,
						'parent' => 'wbcr-han-notify-panel',
						'title' => $message,
						'href' => false,
						'meta' => [
							'class' => ''
						]
					]);

					$i++;
				}
			}
		}
	}

	public function noticesCollection()
	{
		global $wbcr_dan_plugin_all_notices;

		if( empty($wbcr_dan_plugin_all_notices) ) {
			return;
		}
		?>
		<!-- Disable admin notices plugin (Clearfy tools) -->
		<style>
			.wbcr-dan-hide-notices {
				position: initial;
				padding: 5px 5px 0;
				background: transparent;
			}

			.wbcr-dan-hide-notices > div {
				margin: 0 !important;
			}

			.wbcr-dan-hide-notice-link {
				display: block;
				text-align: right;
				margin: 5px 0 5px 5px;
				font-weight: bold;
				color: #F44336;
			}

			.is-dismissible .wbcr-dan-hide-notice-link {
				margin-right: -30px;
			}

			.wbcr-dan-hide-notice-link:active, .wbcr-dan-hide-notice-link:focus {
				box-shadow: none;
				outline: none;
			}
		</style>
		<!-- Disable admin notices plugin (Clearfy tools) -->
		<script>
			jQuery(document).ready(function($) {
				$(document).on('click', '.wbcr-dan-hide-notice-link', function() {
					var self = $(this),
						noticeID = self.data('notice-id'),
						nonce = self.data('nonce'),
						noticeHtml = self.closest('.wbcr-dan-hide-notices').clone(),
						contanierEl = self.closest('.wbcr-dan-hide-notices').parent();

					noticeHtml.find('.wbcr-dan-hide-notice-link').remove();

					if( !noticeID ) {
						alert('Undefinded error. Please report the bug to our support forum.');
					}

					contanierEl.hide();

					$.ajax(ajaxurl, {
						type: 'post',
						dataType: 'json',
						data: {
							action: 'wbcr-dan-hide-notices',
							security: nonce,
							notice_id: noticeID,
							notice_html: noticeHtml.html()
						},
						success: function(response) {
							if( !response || !response.success ) {

								if( response.data.error_message ) {
									console.log(response.data.error_message);
									self.closest('li').show();
								} else {
									console.log(response);
								}

								contanierEl.show();
								return;
							}

							contanierEl.remove();
						},
						error: function(xhr, ajaxOptions, thrownError) {
							console.log(xhr.status);
							console.log(xhr.responseText);
							console.log(thrownError);
						}
					});

					return false;
				});
			});
		</script>
		<?php
		foreach($wbcr_dan_plugin_all_notices as $val) {
			echo $val;
		}
	}

	public function catchNotices()
	{
		global $wbcr_dan_plugin_all_notices;

		try {
			if( is_multisite() && is_network_admin() ) {
				$wp_filter_admin_notices = &$this->getWPFilter('network_admin_notices');
			} else {
				$wp_filter_admin_notices = &$this->getWPFilter('admin_notices');
			}
			//todo: Доработать all admin notices

		} catch( Exception $e ) {
			$wp_filter_admin_notices = null;
		}

		$hide_notices_type = $this->getPopulateOption('hide_admin_notices');

		if( empty($hide_notices_type) || $hide_notices_type == 'only_selected' ) {
			$get_hidden_notices = get_user_meta(get_current_user_id(), WDN_Plugin::app()->getOptionName('hidden_notices'), true);

			$content = [];
			foreach((array)$wp_filter_admin_notices as $filters) {
				foreach($filters as $callback_name => $callback) {

					if( 'usof_hide_admin_notices_start' == $callback_name || 'usof_hide_admin_notices_end' == $callback_name ) {
						continue;
					}

					ob_start();

					// #CLRF-140 fix bug for php7
					// when the developers forgot to delete the argument in the function of implementing the notification.
					$args = [];
					$accepted_args = isset($callback['accepted_args']) && !empty($callback['accepted_args']) ? $callback['accepted_args'] : 0;

					if( $accepted_args > 0 ) {
						for($i = 0; $i < (int)$accepted_args; $i++) {
							$args[] = null;
						}
					}
					//===========

					call_user_func_array($callback['function'], $args);
					$cont = ob_get_clean();

					if( empty($cont) ) {
						continue;
					}

					$salt = is_multisite() ? get_current_blog_id() : '';
					$uniq_id1 = md5($cont . $salt);
					$uniq_id2 = md5($callback_name . $salt);

					if( is_array($callback['function']) && sizeof($callback['function']) == 2 ) {
						$class = $callback['function'][0];
						if( is_object($class) ) {
							$class_name = get_class($class);
							$method_name = $callback['function'][1];
							$uniq_id2 = md5($class_name . ':' . $method_name);
						}
					}
					//838339d1a188e17fec838c2df3058603
					//838339d1a188e17fec838c2df3058603
					if( !empty($get_hidden_notices) ) {

						$skip_notice = true;
						foreach((array)$get_hidden_notices as $key => $notice) {
							$splited_notice_id = explode('_', $key);
							if( empty($splited_notice_id) || sizeof($splited_notice_id) < 2 ) {
								continue;
							}
							$compare_notice_id_1 = $splited_notice_id[0];
							$compare_notice_id_2 = $splited_notice_id[1];

							if( $compare_notice_id_1 == $uniq_id1 || $compare_notice_id_2 == $uniq_id2 ) {
								$skip_notice = false;
							}
						}

						if( !$skip_notice ) {
							continue;
						}
					}

					$hide_link = '<a href="#" data-nonce="' . wp_create_nonce($this->plugin->getPluginName() . '_ajax_hide_notices_nonce') . '" data-notice-id="' . $uniq_id1 . '_' . $uniq_id2 . '" class="wbcr-dan-hide-notice-link">[' . __('Hide notification forever', 'disable-admin-notices') . ']</a>';

					// Fix for Woocommerce membership
					if( $cont != '<div class="js-wc-memberships-admin-notice-placeholder"></div>' ) {
						$cont = preg_replace('/<(script|style)([^>]+)?>(.*?)<\/(script|style)>/is', '', $cont);
						$cont = rtrim(trim($cont));
						$cont = preg_replace('/^(<div[^>]+>)(.*?)(<\/div>)$/is', '$1<div class="wbcr-dan-hide-notices">$2' . $hide_link . '</div>$3', $cont);
					}

					if( empty($cont) ) {
						continue;
					}
					$content[] = $cont;
				}
			}

			$wbcr_dan_plugin_all_notices = $content;
		}

		try {
			$wp_filter_user_admin_notices = &$this->getWPFilter('user_admin_notices');
		} catch( Exception $e ) {
			$wp_filter_user_admin_notices = null;
		}

		try {
			$wp_filter_network_admin_notices = &$this->getWPFilter('network_admin_notices');
		} catch( Exception $e ) {
			$wp_filter_network_admin_notices = null;
		}

		if( is_user_admin() && $wp_filter_user_admin_notices !== null ) {
			$wp_filter_user_admin_notices = null;
		} else if( is_network_admin() && $wp_filter_network_admin_notices !== null ) {
			//unset($wp_filter['network_admin_notices']);
			foreach($wp_filter_network_admin_notices as $f_key => $f) {
				foreach($f as $c_name => $clback) {
					if( is_array($clback['function']) && sizeof($clback['function']) == 2 ) {
						$class = $clback['function'][0];
						if( is_object($class) ) {
							$class_name = get_class($class);
						}
					}

					unset($wp_filter_network_admin_notices[$f_key][$c_name]);
				}
			}
		} else if( $wp_filter_admin_notices !== null ) {
			foreach($wp_filter_admin_notices as $f_key => $f) {
				foreach($f as $c_name => $clback) {
					if( is_array($clback['function']) && sizeof($clback['function']) == 2 ) {
						$class = $clback['function'][0];
						if( is_object($class) ) {
							$class_name = get_class($class);
						}
					}

					unset($wp_filter_admin_notices[$f_key][$c_name]);
				}
			}

			unset($f_key);
			unset($f);
		}

		try {
			$wp_filter_all_admin_notices = &$this->getWPfilter('all_admin_notices');
		} catch( Exception $e ) {
			$wp_filter_all_admin_notices = null;
		}

		if( $wp_filter_all_admin_notices !== null ) {
			foreach($wp_filter_all_admin_notices as $f_key => $f) {
				foreach($f as $c_name => $clback) {
					if( is_array($clback['function']) && sizeof($clback['function']) == 2 ) {
						$class = $clback['function'][0];
						if( is_object($class) ) {
							$class_name = get_class($class);

							#Fix for Learn dash && Woocommerce membership && YITH WooCommerce Gift Cards
							if( $class_name == 'Learndash_Admin_Menus_Tabs' || $class_name == 'WC_Memberships_Admin' || $class_name == 'YIT_Plugin_Panel_WooCommerce' ) {
								continue;
							}
						}
					}

					#Fix for Divi theme
					if( $c_name == 'et_pb_export_layouts_interface' ) {
						continue;
					}

					unset($wp_filter_all_admin_notices[$f_key][$c_name]);
				}
			}

			unset($f_key);
			unset($f);
		}
	}


	/**
	 * Get excerpt from string
	 *
	 * @param String $str String to get an excerpt from
	 * @param Integer $startPos Position int string to start excerpt from
	 * @param Integer $maxLength Maximum length the excerpt may be
	 *
	 * @return String excerpt
	 */
	public function getExcerpt($str, $startPos = 0, $maxLength = 100)
	{
		if( strlen($str) > $maxLength ) {
			$excerpt = substr($str, $startPos, $maxLength - 3);
			$lastSpace = strrpos($excerpt, ' ');
			$excerpt = substr($excerpt, 0, $lastSpace);
			$excerpt .= '...';
		} else {
			$excerpt = $str;
		}

		return $excerpt;
	}

	/**
	 * Access to global variable $wp_filter in WP core.
	 * Migration from WP 4.2 to 4.9
	 *
	 * @see https://codex.wordpress.org/Version_4.7 WP 4.7 changelog (WP_Hook)
	 *
	 * @param $key string filter name
	 *
	 * @return array $wp_filter callbacks array by link
	 * @throws Exception if key not exists
	 */
	private function &getWPFilter($key)
	{
		global $wp_version, $wp_filter;

		if( !isset($wp_filter[$key]) ) {
			throw new Exception('key not exists');
		}
		if( version_compare($wp_version, '4.7.0', '>=') ) {
			return $wp_filter[$key]->callbacks;
		} else {
			return $wp_filter[$key];
		}
	}
}