<?php
/**
 * Handles the Button block.
 *
 * @package GenerateBlocks
 */

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

/**
 * Add Button related functions.
 */
class GenerateBlocks_Block_Button {
	/**
	 * Keep track of all blocks of this type on the page.
	 *
	 * @var array $block_ids The current block id.
	 */
	private static $block_ids = [];

	/**
	 * Keep track of CSS we want to output once per block type.
	 *
	 * @var boolean
	 */
	private static $singular_css_added = false;

	/**
	 * Block defaults.
	 */
	public static function defaults() {
		return [
			'backgroundColor' => '',
			'backgroundColorHover' => '',
			'backgroundColorCurrent' => '',
			'textColor' => '',
			'textColorHover' => '',
			'textColorCurrent' => '',
			'fontFamilyFallback' => '',
			'googleFont' => false,
			'googleFontVariants' => '',
			'icon' => '',
			'hasIcon' => false,
			'iconLocation' => 'left',
			'removeText' => false,
			'ariaLabel' => '',
			'gradient' => false,
			'gradientDirection' => '',
			'gradientColorOne' => '',
			'gradientColorOneOpacity' => '',
			'gradientColorStopOne' => '',
			'gradientColorTwo' => '',
			'gradientColorTwoOpacity' => '',
			'gradientColorStopTwo' => '',
			'hasButtonContainer' => false,
			'variantRole' => '',
			'buttonType' => 'link',
			// Deprecated attributes.
			'backgroundColorOpacity' => 1,
			'backgroundColorHoverOpacity' => 1,
			'borderColorHoverOpacity' => 1,
			'borderColorOpacity' => 1,
			'fontSize' => false,
			'fontSizeTablet' => false,
			'fontSizeMobile' => false,
			'fontSizeUnit' => 'px',
			'letterSpacing' => '',
			'letterSpacingTablet' => '',
			'letterSpacingMobile' => '',
			'fontWeight' => '',
			'textTransform' => '',
			'alignment' => '',
			'alignmentTablet' => '',
			'alignmentMobile' => '',
			'fontFamily' => '',
			'iconPaddingTop' => '',
			'iconPaddingRight' => '0.5',
			'iconPaddingBottom' => '',
			'iconPaddingLeft' => '',
			'iconPaddingTopTablet' => '',
			'iconPaddingRightTablet' => '',
			'iconPaddingBottomTablet' => '',
			'iconPaddingLeftTablet' => '',
			'iconPaddingTopMobile' => '',
			'iconPaddingRightMobile' => '',
			'iconPaddingBottomMobile' => '',
			'iconPaddingLeftMobile' => '',
			'iconPaddingUnit' => 'em',
			'iconSize' => 1,
			'iconSizeTablet' => '',
			'iconSizeMobile' => '',
			'iconSizeUnit' => 'em',
			'borderColor' => '',
			'borderColorHover' => '',
			'borderColorCurrent' => '',
		];
	}

	/**
	 * Store our block ID in memory.
	 *
	 * @param string $id The block ID to store.
	 */
	public static function store_block_id( $id ) {
		self::$block_ids[] = $id;
	}

	/**
	 * Check if our block ID exists.
	 *
	 * @param string $id The block ID to store.
	 */
	public static function block_id_exists( $id ) {
		return in_array( $id, (array) self::$block_ids );
	}

	/**
	 * Compile our CSS data based on our block attributes.
	 *
	 * @param array $attributes Our block attributes.
	 */
	public static function get_css_data( $attributes ) {
		$css = new GenerateBlocks_Dynamic_CSS();
		$desktop_css = new GenerateBlocks_Dynamic_CSS();
		$tablet_css = new GenerateBlocks_Dynamic_CSS();
		$tablet_only_css = new GenerateBlocks_Dynamic_CSS();
		$mobile_css = new GenerateBlocks_Dynamic_CSS();
		$css_data = [];

		$defaults = generateblocks_get_block_defaults();

		$settings = wp_parse_args(
			$attributes,
			$defaults['button']
		);

		$id = $attributes['uniqueId'];
		$blockVersion = ! empty( $settings['blockVersion'] ) ? $settings['blockVersion'] : 1;

		// Use legacy settings if needed.
		if ( $blockVersion < 2 ) {
			$settings = GenerateBlocks_Legacy_Attributes::get_settings( '1.4.0', 'button', $settings, $attributes );
		}

		// Map deprecated settings.
		$settings = GenerateBlocks_Map_Deprecated_Attributes::map_attributes( $settings );

		$selector = generateblocks_get_css_selector( 'button', $attributes );
		$use_visited_selector = generateblocks_use_visited_selector( 'button', $attributes );
		$using_global_style = isset( $settings['useGlobalStyle'] ) && $settings['useGlobalStyle'];

		// Back-compatibility for when icon held a value.
		if ( $settings['icon'] ) {
			$settings['hasIcon'] = true;
		}

		$gradientColorStopOneValue = '';
		$gradientColorStopTwoValue = '';

		if ( $settings['gradient'] ) {
			if ( $settings['gradientColorOne'] && '' !== $settings['gradientColorStopOne'] ) {
				$gradientColorStopOneValue = ' ' . $settings['gradientColorStopOne'] . '%';
			}

			if ( $settings['gradientColorTwo'] && '' !== $settings['gradientColorStopTwo'] ) {
				$gradientColorStopTwoValue = ' ' . $settings['gradientColorStopTwo'] . '%';
			}
		}

		// Only add this CSS once.
		if ( ! self::$singular_css_added ) {
			$css->set_selector( '.gb-button' );
			$css->add_property( 'text-decoration', 'none' );

			$css->set_selector( '.gb-icon svg' );
			$css->add_property( 'fill', 'currentColor' );

			do_action(
				'generateblocks_block_one_time_css_data',
				'button',
				$settings,
				$css
			);

			self::$singular_css_added = true;
		}

		$visited_selector = $use_visited_selector
			? ', ' . $selector . ':visited'
			: '';

		$css->set_selector( $selector . $visited_selector );
		generateblocks_add_layout_css( $css, $settings );
		generateblocks_add_sizing_css( $css, $settings );
		generateblocks_add_flex_child_css( $css, $settings );
		generateblocks_add_typography_css( $css, $settings );
		generateblocks_add_spacing_css( $css, $settings );
		generateblocks_add_border_css( $css, $settings );
		$css->add_property( 'background-color', generateblocks_hex2rgba( $settings['backgroundColor'], $settings['backgroundColorOpacity'] ) );
		$css->add_property( 'color', $settings['textColor'] );

		if ( $settings['gradient'] ) {
			$css->add_property( 'background-image', 'linear-gradient(' . $settings['gradientDirection'] . 'deg, ' . generateblocks_hex2rgba( $settings['gradientColorOne'], $settings['gradientColorOneOpacity'] ) . $gradientColorStopOneValue . ', ' . generateblocks_hex2rgba( $settings['gradientColorTwo'], $settings['gradientColorTwoOpacity'] ) . $gradientColorStopTwoValue . ')' );
		}

		if ( $blockVersion < 3 && ! $using_global_style ) {
			$css->add_property( 'display', 'inline-flex' );
			$css->add_property( 'align-items', 'center' );
			$css->add_property( 'justify-content', 'center' );
			$css->add_property( 'text-align', 'center' );
		}

		$css->set_selector( $selector . ':hover, ' . $selector . ':active, ' . $selector . ':focus' );
		generateblocks_add_border_color_css( $css, $settings, 'Hover' );
		$css->add_property( 'background-color', generateblocks_hex2rgba( $settings['backgroundColorHover'], $settings['backgroundColorHoverOpacity'] ) );
		$css->add_property( 'color', $settings['textColorHover'] );

		$visited_selector = $use_visited_selector
			? ', ' . $selector . '.gb-block-is-current:visited'
			: '';

		$current_selector = sprintf(
			'%1$s.gb-block-is-current, %1$s.gb-block-is-current:hover, %1$s.gb-block-is-current:active, %1$s.gb-block-is-current:focus',
			$selector
		);

		$css->set_selector( $current_selector . $visited_selector );
		generateblocks_add_border_color_css( $css, $settings, 'Current' );
		$css->add_property( 'background-color', $settings['backgroundColorCurrent'] );
		$css->add_property( 'color', $settings['textColorCurrent'] );

		if ( $settings['hasIcon'] ) {
			$css->set_selector( $selector . ' .gb-icon' );

			if ( $blockVersion < 4 ) {
				$css->add_property( 'font-size', $settings['iconSize'], $settings['iconSizeUnit'] );
			}

			$css->add_property( 'line-height', '0' );

			if ( ! $settings['removeText'] ) {
				if ( $blockVersion < 4 ) {
					// Need to  check for blockVersion here instead of mapping as iconPaddingRight has a default.
					$css->add_property( 'padding', array( $settings['iconPaddingTop'], $settings['iconPaddingRight'], $settings['iconPaddingBottom'], $settings['iconPaddingLeft'] ), $settings['iconPaddingUnit'] );
				} else {
					$css->add_property(
						'padding',
						array(
							generateblocks_get_array_attribute_value( 'paddingTop', $settings['iconStyles'] ),
							generateblocks_get_array_attribute_value( 'paddingRight', $settings['iconStyles'] ),
							generateblocks_get_array_attribute_value( 'paddingBottom', $settings['iconStyles'] ),
							generateblocks_get_array_attribute_value( 'paddingLeft', $settings['iconStyles'] ),
						)
					);
				}
			}

			if ( $blockVersion < 3 ) {
				$css->add_property( 'align-items', 'center' );
				$css->add_property( 'display', 'inline-flex' );
			}

			$css->set_selector( $selector . ' .gb-icon svg' );

			if ( $blockVersion < 4 ) {
				$css->add_property( 'height', '1em' );
				$css->add_property( 'width', '1em' );
			}

			$css->add_property( 'width', generateblocks_get_array_attribute_value( 'width', $settings['iconStyles'] ) );
			$css->add_property( 'height', generateblocks_get_array_attribute_value( 'height', $settings['iconStyles'] ) );
		}

		$tablet_css->set_selector( $selector );
		generateblocks_add_layout_css( $tablet_css, $settings, 'Tablet' );
		generateblocks_add_sizing_css( $tablet_css, $settings, 'Tablet' );
		generateblocks_add_flex_child_css( $tablet_css, $settings, 'Tablet' );
		generateblocks_add_typography_css( $tablet_css, $settings, 'Tablet' );
		generateblocks_add_spacing_css( $tablet_css, $settings, 'Tablet' );
		generateblocks_add_border_css( $tablet_css, $settings, 'Tablet' );

		if ( $settings['hasIcon'] ) {
			$tablet_css->set_selector( $selector . ' .gb-icon' );

			if ( $blockVersion < 4 ) {
				$tablet_css->add_property( 'font-size', $settings['iconSizeTablet'], $settings['iconSizeUnit'] );
			}

			if ( ! $settings['removeText'] ) {
				if ( $blockVersion < 4 ) {
					$tablet_css->add_property( 'padding', array( $settings['iconPaddingTopTablet'], $settings['iconPaddingRightTablet'], $settings['iconPaddingBottomTablet'], $settings['iconPaddingLeftTablet'] ), $settings['iconPaddingUnit'] );
				} else {
					$tablet_css->add_property(
						'padding',
						array(
							generateblocks_get_array_attribute_value( 'paddingTopTablet', $settings['iconStyles'] ),
							generateblocks_get_array_attribute_value( 'paddingRightTablet', $settings['iconStyles'] ),
							generateblocks_get_array_attribute_value( 'paddingBottomTablet', $settings['iconStyles'] ),
							generateblocks_get_array_attribute_value( 'paddingLeftTablet', $settings['iconStyles'] ),
						)
					);
				}
			}

			$tablet_css->set_selector( $selector . ' .gb-icon svg' );
			$tablet_css->add_property( 'width', generateblocks_get_array_attribute_value( 'widthTablet', $settings['iconStyles'] ) );
			$tablet_css->add_property( 'height', generateblocks_get_array_attribute_value( 'heightTablet', $settings['iconStyles'] ) );
		}

		$mobile_css->set_selector( $selector );
		generateblocks_add_layout_css( $mobile_css, $settings, 'Mobile' );
		generateblocks_add_sizing_css( $mobile_css, $settings, 'Mobile' );
		generateblocks_add_flex_child_css( $mobile_css, $settings, 'Mobile' );
		generateblocks_add_typography_css( $mobile_css, $settings, 'Mobile' );
		generateblocks_add_spacing_css( $mobile_css, $settings, 'Mobile' );
		generateblocks_add_border_css( $mobile_css, $settings, 'Mobile' );

		if ( $settings['hasIcon'] ) {
			$mobile_css->set_selector( $selector . ' .gb-icon' );

			if ( $blockVersion < 4 ) {
				$mobile_css->add_property( 'font-size', $settings['iconSizeMobile'], $settings['iconSizeUnit'] );
			}

			if ( ! $settings['removeText'] ) {
				if ( $blockVersion < 4 ) {
					$mobile_css->add_property( 'padding', array( $settings['iconPaddingTopMobile'], $settings['iconPaddingRightMobile'], $settings['iconPaddingBottomMobile'], $settings['iconPaddingLeftMobile'] ), $settings['iconPaddingUnit'] );
				} else {
					$mobile_css->add_property(
						'padding',
						array(
							generateblocks_get_array_attribute_value( 'paddingTopMobile', $settings['iconStyles'] ),
							generateblocks_get_array_attribute_value( 'paddingRightMobile', $settings['iconStyles'] ),
							generateblocks_get_array_attribute_value( 'paddingBottomMobile', $settings['iconStyles'] ),
							generateblocks_get_array_attribute_value( 'paddingLeftMobile', $settings['iconStyles'] ),
						)
					);
				}
			}

			$mobile_css->set_selector( $selector . ' .gb-icon svg' );
			$mobile_css->add_property( 'width', generateblocks_get_array_attribute_value( 'widthMobile', $settings['iconStyles'] ) );
			$mobile_css->add_property( 'height', generateblocks_get_array_attribute_value( 'heightMobile', $settings['iconStyles'] ) );
		}

		// Store this block ID in memory.
		self::store_block_id( $id );

		/**
		 * Do generateblocks_block_css_data hook
		 *
		 * @since 1.0
		 *
		 * @param string $name The name of our block.
		 * @param array  $settings The settings for the current block.
		 * @param object $css Our desktop/main CSS data.
		 * @param object $desktop_css Our desktop only CSS data.
		 * @param object $tablet_css Our tablet CSS data.
		 * @param object $tablet_only_css Our tablet only CSS data.
		 * @param object $mobile_css Our mobile CSS data.
		 */
		do_action(
			'generateblocks_block_css_data',
			'button',
			$settings,
			$css,
			$desktop_css,
			$tablet_css,
			$tablet_only_css,
			$mobile_css
		);

		return [
			'main'        => $css->css_output(),
			'desktop'     => $desktop_css->css_output(),
			'tablet'      => $tablet_css->css_output(),
			'tablet_only' => $tablet_only_css->css_output(),
			'mobile'      => $mobile_css->css_output(),
		];
	}

	/**
	 * Wrapper function for our dynamic buttons.
	 *
	 * @since 1.6.0
	 * @param array    $attributes The block attributes.
	 * @param string   $content The dynamic text to display.
	 * @param WP_Block $block Block instance.
	 */
	public static function render_block( $attributes, $content, $block ) {
		if ( ! isset( $attributes['hasUrl'] ) && strpos( trim( $content ), '<a' ) === 0 ) {
			$attributes['hasUrl'] = true;
		}

		if ( ! isset( $attributes['useDynamicData'] ) || ! $attributes['useDynamicData'] ) {
			// Add styles to this block if needed.
			$content = generateblocks_maybe_add_block_css(
				$content,
				[
					'class_name' => 'GenerateBlocks_Block_Button',
					'attributes' => $attributes,
					'block_ids' => self::$block_ids,
				]
			);

			return $content;
		}

		$allow_empty_content = false;

		// Add an attribute showing we're working with the Button block.
		$attributes['isButton'] = true;

		if ( empty( $attributes['dynamicContentType'] ) ) {
			$dynamic_content = GenerateBlocks_Dynamic_Content::get_static_content( $content );

			if ( ! empty( $attributes['hasIcon'] ) && ! empty( $attributes['removeText'] ) ) {
				// Allow icon-only items to continue.
				$allow_empty_content = true;
			}
		} else {
			$dynamic_content = GenerateBlocks_Dynamic_Content::get_content( $attributes, $block );
		}

		if ( ! $dynamic_content && '0' !== $dynamic_content && ! $allow_empty_content ) {
			return '';
		}

		$defaults = generateblocks_get_block_defaults();

		$settings = wp_parse_args(
			$attributes,
			$defaults['button']
		);

		$classNames = array(
			'gb-button',
			'gb-button-' . $settings['uniqueId'],
		);

		if ( ! empty( $settings['className'] ) ) {
			$classNames[] = $settings['className'];
		}

		if ( empty( $settings['hasIcon'] ) ) {
			$classNames[] = 'gb-button-text';
		}

		$relAttributes = array();

		if ( ! empty( $settings['relNoFollow'] ) ) {
			$relAttributes[] = 'nofollow';
		}

		if ( ! empty( $settings['target'] ) ) {
			$relAttributes[] = 'noopener';
			$relAttributes[] = 'noreferrer';
		}

		if ( ! empty( $settings['relSponsored'] ) ) {
			$relAttributes[] = 'sponsored';
		}

		$icon_html = '';

		// Extract our icon from the static HTML.
		if ( $settings['hasIcon'] ) {
			$icon_html = GenerateBlocks_Dynamic_Content::get_icon_html( $content );
		}

		// Add styles to this block if needed.
		$output = generateblocks_maybe_add_block_css(
			'',
			[
				'class_name' => 'GenerateBlocks_Block_Button',
				'attributes' => $attributes,
				'block_ids' => self::$block_ids,
			]
		);

		foreach ( (array) $dynamic_content as $content ) {
			$tagName = 'span';

			$dynamic_link = GenerateBlocks_Dynamic_Content::get_dynamic_url( $attributes, $block );

			if ( ! empty( $content['attributes']['href'] ) || $dynamic_link ) {
				$tagName = 'a';
			}

			if ( 'button' === $settings['buttonType'] ) {
				$tagName = 'button';
			}

			$button_attributes = array(
				'id' => ! empty( $settings['anchor'] ) ? $settings['anchor'] : null,
				'class' => implode( ' ', $classNames ),
				'href' => 'a' === $tagName ? $dynamic_link : null,
				'rel' => ! empty( $relAttributes ) ? implode( ' ', $relAttributes ) : null,
				'target' => ! empty( $settings['target'] ) ? '_blank' : null,
				'aria-label' => ! empty( $settings['ariaLabel'] ) ? $settings['ariaLabel'] : null,
			);

			if ( isset( $content['attributes'] ) ) {
				foreach ( $content['attributes'] as $attribute => $value ) {
					if ( 'class' === $attribute ) {
						$button_attributes[ $attribute ] .= ' ' . $value;
					} else {
						$button_attributes[ $attribute ] = $value;
					}
				}
			}

			$output .= sprintf(
				'<%1$s %2$s>',
				$tagName,
				generateblocks_attr(
					'dynamic-button',
					$button_attributes,
					$settings,
					$block
				)
			);

			if ( $icon_html ) {
				if ( 'left' === $settings['iconLocation'] ) {
					$output .= $icon_html;
				}

				$output .= '<span class="gb-button-text">';
			}

			if ( isset( $content['content'] ) ) {
				$output .= $content['content'];
			} else {
				$output .= $content;
			}

			if ( $icon_html ) {
				$output .= '</span>';

				if ( 'right' === $settings['iconLocation'] ) {
					$output .= $icon_html;
				}
			}

			$output .= sprintf(
				'</%s>',
				$tagName
			);
		}

		return $output;
	}
}
