<?php
/** MainWP Editor Connector. */

namespace WP_MainWP_Stream;

/**
 * Class Connector_Editor
 * @package WP_MainWP_Stream
 */
class Connector_Editor extends Connector {
	/**
	 * Connector slug
	 *
	 * @var string
	 */
	public $name = 'editor';

	/**
	 * Actions registered for this connector
	 *
	 * @var array
	 */
	public $actions = array();

	/**
	 * Actions registered for this connector
	 *
	 * @var array
	 */
	private $edited_file = array();

	/**
	 * Register connector in the WP Frontend
	 *
	 * @var bool
	 */
	public $register_frontend = false;

	/**
	 * Register all context hooks
	 *
	 * @return void
	 */
	public function register() {
		parent::register();
		add_action( 'load-theme-editor.php', array( $this, 'get_edition_data' ) );
		add_action( 'load-plugin-editor.php', array( $this, 'get_edition_data' ) );
		add_filter( 'wp_redirect', array( $this, 'log_changes' ) );
	}

	/**
	 * Return translated connector label
	 *
	 * @return string Translated connector label
	 */
	public function get_label() {
		return esc_html__( 'Editor', 'mainwp-child-reports' );
	}

	/**
	 * Return translated action labels
	 *
	 * @return array Action label translations
	 */
	public function get_action_labels() {
		return array(
			'updated' => esc_html__( 'Updated', 'mainwp-child-reports' ),
		);
	}

	/**
	 * Return translated context labels
	 *
	 * @return array Context label translations
	 */
	public function get_context_labels() {
		/**
		 * Filter available context labels for the Editor connector
		 *
		 * @return array Array of context slugs and their translated labels
		 */
		return apply_filters(
			'wp_mainwp_stream_editor_context_labels',
			array(
				'themes'  => esc_html__( 'Themes', 'mainwp-child-reports' ),
				'plugins' => esc_html__( 'Plugins', 'mainwp-child-reports' ),
			)
		);
	}

	/**
	 * Get the context based on wp_redirect location
	 *
	 * @param  string $location The URL of the redirect
	 * @return string           Context slug
	 */
	public function get_context( $location ) {
		$context = null;

		if ( false !== strpos( $location, 'theme-editor.php' ) ) {
			$context = 'themes';
		}

		if ( false !== strpos( $location, 'plugin-editor.php' ) ) {
			$context = 'plugins';
		}

		/**
		 * Filter available contexts for the Editor connector
		 *
		 * @param  string  $context  Context slug
		 * @param  string  $location The URL of the redirect
		 * @return string            Context slug
		 */
		return apply_filters( 'wp_mainwp_stream_editor_context', $context, $location );
	}

	/**
	 * Get the message format for file updates
	 *
	 * @return string Translated string
	 */
	public function get_message() {
		// translators: Placeholders refer to a file name, and a theme / plugin name (e.g. "index.php", "Stream").
		return _x(
			'"%1$s" in "%2$s" updated',
			'1: File name, 2: Theme/plugin name',
			'mainwp-child-reports'
		);
	}

	/**
	 * Add action links to Stream drop row in admin list screen
	 *
	 * @filter wp_mainwp_stream_action_links_{connector}
	 *
	 * @param array  $links  Previous links registered
	 * @param object $record Stream record
	 *
	 * @return array Action links
	 */
	public function action_links( $links, $record ) {
		if ( current_user_can( 'edit_theme_options' ) ) {
			$file_name = $record->get_meta( 'file', true );
			$file_path = $record->get_meta( 'file_path', true );

			if ( ! empty( $file_name ) && ! empty( $file_path ) ) {
				$theme_slug    = $record->get_meta( 'theme_slug', true );
				$plugin_slug   = $record->get_meta( 'plugin_slug', true );
				$theme_exists  = ( ! empty( $theme_slug ) && file_exists( $file_path ) );
				$plugin_exists = ( ! empty( $plugin_slug ) && file_exists( $file_path ) );

				if ( $theme_exists ) {
					$links[ esc_html__( 'Edit File', 'mainwp-child-reports' ) ] = add_query_arg(
						array(
							'theme' => rawurlencode( $theme_slug ),
							'file'  => rawurlencode( $file_name ),
						),
						self_admin_url( 'theme-editor.php' )
					);

					$links[ esc_html__( 'Theme Details', 'mainwp-child-reports' ) ] = add_query_arg(
						array(
							'theme' => rawurlencode( $theme_slug ),
						),
						self_admin_url( 'themes.php' )
					);
				}

				if ( $plugin_exists ) {
					$links[ esc_html__( 'Edit File', 'mainwp-child-reports' ) ] = add_query_arg(
						array(
							'plugin' => rawurlencode( $plugin_slug ),
							'file'   => rawurlencode( str_ireplace( trailingslashit( WP_PLUGIN_DIR ), '', $file_path ) ),
						),
						self_admin_url( 'plugin-editor.php' )
					);
				}
			}
		}

		return $links;
	}

	/**
	 * Retrieves data submitted on the screen, and prepares it for the appropriate context type
	 *
	 * @action load-theme-editor.php
	 * @action load-plugin-editor.php
	 */
	public function get_edition_data() {
		if (
			(
				isset( $_SERVER['REQUEST_METHOD'] )
				&&
				'POST' !== esc_attr( $_SERVER['REQUEST_METHOD'] )
			)
			||
			'update' !== wp_mainwp_stream_filter_input( INPUT_POST, 'action' )
		) {
			return;
		}

		$theme_slug = wp_mainwp_stream_filter_input( INPUT_POST, 'theme' );
		if ( $theme_slug ) {
			$this->edited_file = $this->get_theme_data( $theme_slug );
		}

		$plugin_slug = wp_mainwp_stream_filter_input( INPUT_POST, 'plugin' );
		if ( $plugin_slug ) {
			$this->edited_file = $this->get_plugin_data( $plugin_slug );
		}
	}

	/**
	 * Retrieve theme data needed for the log message
	 *
	 * @param string $slug The theme slug (e.g. twentyfourteen)
	 *
	 * @return mixed $output Compacted variables
	 */
	public function get_theme_data( $slug ) {
		$theme = wp_get_theme( $slug );

		if ( ! $theme->exists() || ( $theme->errors() && 'theme_no_stylesheet' === $theme->errors()->get_error_code() ) ) {
			return false;
		}

		$allowed_files = $theme->get_files( 'php', 1 );
		$style_files   = $theme->get_files( 'css' );
		$file          = wp_mainwp_stream_filter_input( INPUT_POST, 'file' );

		$allowed_files['style.css'] = $style_files['style.css'];

		if ( empty( $file ) ) {
			$file_name = 'style.css';
			$file_path = $allowed_files['style.css'];
		} else {
			$file_name = $file;
			$file_path = sprintf( '%s/%s', $theme->get_stylesheet_directory(), $file_name );
		}

		$file_md5 = md5_file( $file_path );
		$name     = $theme->get( 'Name' );

		$output = compact(
			'file_name',
			'file_path',
			'file_md5',
			'slug',
			'name'
		);

		return $output;
	}

	/**
	 * Retrieve plugin data needed for the log message
	 *
	 * @param  string $slug   The plugin file base name (e.g. akismet/akismet.php)
	 * @return mixed  $output Compacted variables
	 */
	public function get_plugin_data( $slug ) {
		$base      = null;
		$name      = null;
		$slug      = current( explode( '/', $slug ) );
		$file_name = wp_mainwp_stream_filter_input( INPUT_POST, 'file' );
		$file_path = WP_PLUGIN_DIR . '/' . $file_name;
		$file_md5  = md5_file( $file_path );
		$plugins   = get_plugins();

		foreach ( $plugins as $key => $plugin_data ) {
			if ( 0 === strpos( $key, $slug ) ) {
				$base = $key;
				$name = $plugin_data['Name'];
				break;
			}
		}

		$file_name = str_ireplace( trailingslashit( $slug ), '', $file_name );
		$slug      = ! empty( $base ) ? $base : $slug;

		$output = compact(
			'file_name',
			'file_path',
			'file_md5',
			'slug',
			'name'
		);

		return $output;
	}

    /**
     * Log Changes.
     *
     * @filter wp_redirect
     *
     * @param string $location Log location.
     * @return string $location Log location.
     *
     * @uses \WP_MainWP_Stream\Connector_Editor::get_context()
     * @uses \WP_MainWP_Stream\Connector_Editor::get_message()
     */
	public function log_changes( $location ) {
		if ( ! empty( $this->edited_file ) ) {
			// TODO: phpcs fix
			if ( md5_file( $this->edited_file['file_path'] ) !== $this->edited_file['file_md5'] ) {
				$context = $this->get_context( $location );

				switch ( $context ) {
					case 'themes':
						$name_key = 'theme_name';
						$slug_key = 'theme_slug';
						break;
					case 'plugins':
						$name_key = 'plugin_name';
						$slug_key = 'plugin_slug';
						break;
					default:
						$name_key = 'name';
						$slug_key = 'slug';
				}

				$this->log(
					$this->get_message(),
					array(
						'file'      => (string) $this->edited_file['file_name'],
						$name_key   => (string) $this->edited_file['name'],
						$slug_key   => (string) $this->edited_file['slug'],
						'file_path' => (string) $this->edited_file['file_path'],
					),
					null,
					$context,
					'updated'
				);
			}
		}

		return $location;
	}
}
