<?php
/**
 * Gravity Forms bridge: the parts that only make sense when Gravity Forms is
 * running. Direct upload URLs in entry views and notification emails are
 * rewritten to Upload Vault proxy links once protection is installed, so
 * nothing the admin already relies on breaks.
 *
 * Every Gravity Forms surface is feature-detected; the plugin never fatals
 * without it.
 *
 * @package Upload_Vault
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class Uvgf_Gf_Bridge
 */
class Uvgf_Gf_Bridge {

	/**
	 * Wire hooks (call only when GFForms exists).
	 */
	public static function init() {
		$settings = get_option( 'uvgf_settings', array() );

		if ( ! empty( $settings['rewrite_entry_links'] ) ) {
			add_filter( 'gform_entry_field_value', array( __CLASS__, 'filter_entry_field_value' ), 20, 4 );
		}
		if ( ! empty( $settings['rewrite_notifications'] ) ) {
			add_filter( 'gform_notification', array( __CLASS__, 'filter_notification' ), 20, 3 );
		}
	}

	/**
	 * Should rewriting happen at all?
	 *
	 * @return bool
	 */
	private static function active() {
		return Uvgf_Protector::rules_installed();
	}

	/**
	 * Rewrite upload URLs inside a rendered entry field value (admin entry view).
	 *
	 * @param string $value Rendered value (may contain anchors).
	 * @param object $field Field.
	 * @param array  $entry Entry.
	 * @param array  $form  Form.
	 * @return string
	 */
	public static function filter_entry_field_value( $value, $field, $entry, $form ) {
		unset( $field, $entry, $form );
		if ( ! is_string( $value ) || '' === $value || ! self::active() ) {
			return $value;
		}
		return self::rewrite_urls( $value );
	}

	/**
	 * Rewrite upload URLs inside a notification message + subject.
	 *
	 * @param array $notification Notification.
	 * @param array $form         Form.
	 * @param array $entry        Entry.
	 * @return array
	 */
	public static function filter_notification( $notification, $form, $entry ) {
		unset( $form, $entry );
		if ( ! self::active() || ! is_array( $notification ) ) {
			return $notification;
		}
		if ( isset( $notification['message'] ) && is_string( $notification['message'] ) ) {
			$notification['message'] = self::rewrite_urls( $notification['message'] );
		}
		return $notification;
	}

	/**
	 * Replace every direct upload-base URL in a blob of text/HTML with the
	 * corresponding proxy URL.
	 *
	 * @param string $text Text or HTML.
	 * @return string
	 */
	public static function rewrite_urls( $text ) {
		$base_url = Uvgf_Locator::base_url();
		if ( '' === $base_url || false === strpos( $text, $base_url ) ) {
			return $text;
		}

		$pattern = '#' . preg_quote( $base_url, '#' ) . '/[^\s"\'<>\\)\\]]+#i';
		if ( ! preg_match_all( $pattern, $text, $matches ) ) {
			return $text;
		}

		$replacements = array();
		foreach ( array_unique( $matches[0] ) as $url ) {
			$proxy = self::url_to_proxy( $url, $base_url );
			if ( '' !== $proxy ) {
				$replacements[ $url ] = $proxy;
			}
		}

		if ( empty( $replacements ) ) {
			return $text;
		}
		return strtr( $text, $replacements );
	}

	/**
	 * Map one direct URL to its proxy URL ('' when unmappable).
	 *
	 * @param string $url      Direct URL.
	 * @param string $base_url Upload base URL.
	 * @return string
	 */
	private static function url_to_proxy( $url, $base_url ) {
		$relpath = rawurldecode( ltrim( substr( $url, strlen( $base_url ) ), '/' ) );
		// Trailing punctuation the regex may have swept up from prose.
		$relpath = rtrim( $relpath, '.,;:' );
		if ( '' === $relpath ) {
			return '';
		}

		$row = Uvgf_Indexer::get_by_relpath( $relpath );
		if ( ! $row ) {
			// Freshly submitted upload the periodic sync hasn't seen yet.
			$row = Uvgf_Indexer::register_file( $relpath );
		}
		return $row ? Uvgf_Proxy::url( (int) $row->id ) : '';
	}
}
