<?php
/**
 * WooCommerce Memberships
 *
 * This source file is subject to the GNU General Public License v3.0
 * that is bundled with this package in the file license.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/gpl-3.0.html
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@skyverge.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade WooCommerce Memberships to newer
 * versions in the future. If you wish to customize WooCommerce Memberships for your
 * needs please refer to https://docs.woocommerce.com/document/woocommerce-memberships/ for more information.
 *
 * @author    SkyVerge
 * @copyright Copyright (c) 2014-2020, SkyVerge, Inc. (info@skyverge.com)
 * @license   http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
 */

namespace SkyVerge\WooCommerce\Memberships\Blocks;

use SkyVerge\WooCommerce\PluginFramework\v5_7_1 as Framework;

defined('ABSPATH') or exit;

/**
 * Block handler.
 *
 * @since 1.15.0
 */
abstract class Block {


	/** @var string the block namespace it belongs to */
	protected $block_namespace;

	/** @var string the block type */
	protected $block_type = '';

	/** @var string the block name */
	protected $block_name;

	/** @var array optional associative array of block arguments */
	protected $block_args = [];

	/** @var string the block HTML class */
	protected $block_class;


	/**
	 * Block constructor.
	 *
	 * @since 1.15.0
	 */
	public function __construct() {

		$this->block_namespace = $this->block_namespace ?: 'woocommerce-memberships';
		$this->block_name      = $this->block_name ?: $this->block_namespace . '/' . $this->block_type;
		$this->block_class     = sprintf( 'wp-block-%1$s-%2$s', $this->block_namespace, $this->block_type );

		$this->register();
	}


	/**
	 * Registers the block.
	 *
	 * @since 1.15.0
	 */
	protected function register() {

		$block_args = [
			'editor_script' => 'wc-memberships-blocks',
			'editor_style'  => 'wc-memberships-blocks',
		];

		if ( $this instanceof Dynamic_Content_Block ) {
			$block_args['render_callback'] = [ $this, 'render' ];
		}

		register_block_type( $this->block_name, wp_parse_args( $this->block_args, $block_args ) );
	}


	/**
	 * Strips an excerpt generated by WordPress from the block's contents.
	 *
	 * Internal function which children blocks can use by adding to their constructor:
	 * `add_filter( 'wc_memberships_trimmed_restricted_excerpt', [ $this, 'remove_block_from_restricted_content_excerpt' ], 1, 4 );`
	 * Otherwise, if the content where the block content appears is also restricted entirely by a content restriction rule, its contents may be added to the visible excerpt.
	 *
	 * Note: suppressing PHP warnings is intentional here as DOM might complain about HTML irregularities or invalid markup which is still accepted by the browser.
	 * @see https://stackoverflow.com/questions/6090667/php-domdocument-errors-warnings-on-html5-tags
	 * Warnings and notices might also be dependable on PHP and DOM module extension versions in use.
	 *
	 * @internal
	 *
	 * @since 1.15.0
	 *
	 * @param string $trimmed_excerpt trimmed excerpt
	 * @param string $original_excerpt may contain blocks HTML
	 * @param int $excerpt_length the intended excerpt length
	 * @param string $excerpt_more the text or symbol to append at the end of the excerpt
	 * @return string
	 */
	public function remove_block_from_restricted_content_excerpt( $trimmed_excerpt, $original_excerpt, $excerpt_length, $excerpt_more = '' ) {

		if ( '' !== $trimmed_excerpt && '' !== $original_excerpt ) {

			// detect encoding from input HTML
			$encoding = mb_detect_encoding( $original_excerpt );

			// if that fails, use the site's charset
			if ( ! $encoding ) {
				$encoding = get_bloginfo( 'charset' );
			}

			$document = new \DOMDocument();
			@$document->loadHTML( mb_convert_encoding( $original_excerpt, 'HTML-ENTITIES', $encoding ) );

			$selector = new \DOMXPath( $document );
			$class    = str_replace( $this->block_type, '', $this->block_class );
			$blocks   = @$selector->query( "//div[starts-with(@class, '{$class}')]" );

			if ( $blocks ) {

				foreach ( $blocks as $el ) {
					/** @type \DOMNode $el DOM element */
					@$el->parentNode->removeChild( $el );
				}

				$trimmed_excerpt = wp_trim_words( @$document->saveHTML( $document->documentElement ), $excerpt_length, $excerpt_more );
			}
		}

		return $trimmed_excerpt;
	}


}
