<?php
/**
 * @package Subtitles
 */

/**
 * Do not load this file directly
 *
 * @since 1.0.0
 */
if ( ! defined( 'ABSPATH' ) ) {
	die( '-1' );
}

/**
 * Checks for the existence of Subtitles_Admin before defining it.
 *
 * @link http://www.php.net//manual/en/function.class-exists.php
 *
 * @since 1.0.0
 */
if ( ! class_exists( 'Subtitles_Admin' ) ) {
	/**
	 * Define Subtitles_Admin class.
	 *
	 * Within classes constants and variables are called properties.
	 * Within classes functions are called methods.
	 *
	 * @link http://php.net/manual/en/language.oop5.php
	 *
	 * @since 1.0.0
	 */
	class Subtitles_Admin extends Subtitles {
		/**
		 * Hold the singleton instance of Subtitles_Admin.
		 *
		 * @since 1.0.3
		 */
		private static $instance = null;

		public static function getinstance() {
			if ( ! self::$instance ) {
				self::$instance = new Subtitles_Admin;
			}

			return self::$instance;
		} // end method getinstance()

		protected function __clone() {}

		public function __wakeup() {
			throw new Exception( 'This Singleton cannot be unserialized.' );
		}

		/**
		 * Declare constructor methods for the class Subtitles.
		 *
		 * Classes which have a constructor method call this method on each newly-created object,
		 * so it is suitable for any initialization that the object may need before it is used.
		 *
		 * Access is set to protected to prevent outside access to the method for anything other than
		 * the class or a child class. Otherwise `new` could be used to kick off this constructor if
		 * it were public.
		 *
		 * @access protected
		 *
		 * @since 1.0.0
		 */
		protected function __construct() {
			/**
			 * Build the subtitle input field.
			 *
			 * To find out the number and name of arguments for any action in WordPress,
			 * search Core for the matching do_action call. For example, searching for
			 * "do_action( 'save_post'" reveals that two arguments, $post_id and $post are used.
			 *
			 * add_action accepts:
			 *
			 * - $tag The name of the action to which the $function_to_add is hooked.
			 * - callback function The name of the function you wish to be called.
			 * - int $priority optional. Used to specify the order in which the functions
			 *   associated with a particular action are executed (default: 10).
			 *   Lower numbers correspond with earlier execution, and functions with the
			 *   same priority are executed in the order in which they were added to the action.
			 * - int $accepted_args optional. The number of arguments the function accept (default: 1).
			 *
			 * @see add_action()
			 * @link http://codex.wordpress.org/Function_Reference/add_action
			 *
			 * @since 1.0.0
			 */
			if ( version_compare( $GLOBALS['wp_version'], '4.1-alpha', '<' ) ) {
				add_action( 'edit_form_after_title', array( &$this, 'build_subtitle_input' ) );
			} else {
				add_action( 'edit_form_before_permalink', array( &$this, 'build_subtitle_input' ) );
			}

			/**
			 * Validate and update the subtitle input field.
			 *
			 * @see add_action()
			 * @link http://codex.wordpress.org/Function_Reference/add_action
			 * @link http://codex.wordpress.org/Data_Validation
			 *
			 * @since 1.0.0
			 */
			add_action( 'save_post', array( &$this, 'update_subtitle_data' ), 10, 3 );

			/**
			 * Enqueue backend scripts and styles.
			 *
			 * @see add_action()
			 * @link http://codex.wordpress.org/Function_Reference/add_action
			 *
			 * @since 1.0.0
			 */
			add_action( 'admin_enqueue_scripts', array( &$this, 'subtitle_admin_scripts' ) );

			/**
			 * Add subtitles into post, page, and custom post type columns in the Dashboard.
			 *
			 * @since 2.1.0
			 */
			add_action( 'manage_posts_columns', array( &$this, 'build_subtitles_column_head' ), 10, 2 );
			add_action( 'manage_posts_custom_column', array( &$this, 'build_subtitles_column_content' ), 10, 2 );
			add_action( 'manage_pages_columns', array( &$this, 'build_subtitles_column_head' ) );
			add_action( 'manage_pages_custom_column', array( &$this, 'build_subtitles_column_content' ), 10, 2 );
		} // end method __construct()

		/**
		 * Build the subtitle input field.
		 *
		 * @access public
		 *
		 * @since 1.0.0
		 */
		public function build_subtitle_input( $post ) {
			/**
			 * Bail if we're not on an admin screen
			 *
			 * @since 1.0.0
			 */
			if ( ! is_admin() ) {
				return;
			}

			/**
			 * Bail if the current post type doesn't support subtitles.
			 *
			 * By default both posts and pages automatically support subtitles.
			 *
			 * Support for subtitles is kicked off in Subtitles->add_subtitles_support();
			 *
			 * @since 1.0.0
			 */
			$screen = (object) get_current_screen();
			$post_type_support = post_type_supports( $screen->post_type, self::SUBTITLE_FEATURE_SUPPORT );

			if ( ! $post_type_support ) {
				return;
			}

			$post_id = (int) absint( $post->ID ); // post ID should always be a non-negative integer

			/**
			 * get_post_meta() takes the following arguments:
			 * - $post_id for the ID of the post
			 * - $key for the meta key to retrieve
			 * - $single for whether or not to return a single value
			 *   (in effect either choosing an array or a single value to be returned)
			 */
			$subtitle = (string) get_post_meta( $post_id, self::SUBTITLE_META_KEY, true );

			// nonces ("number used once") are used to protect the custom meta box forms from being misused.
			wp_nonce_field(
				basename( __FILE__ ), // $action, Action name
				self::SUBTITLE_NONCE_NAME // $name, Nonce name
			); ?>

			<div id="subtitlediv">
				<div id="subtitlewrap">
					<label class="screen-reader-text" id="subtitle-prompt-text" for="<?php echo esc_attr( self::SUBTITLE_META_KEY ); ?>">
						<?php echo esc_html( apply_filters( 'enter_subtitle_here', __( 'Enter subtitle here', 'subtitles' ), $post ) ); ?>
					</label><!-- #subtitle-prompt-text -->
					<input type="text" name="<?php echo esc_attr( self::SUBTITLE_META_KEY ); ?>" size="30" value="<?php echo esc_attr( $subtitle ); ?>" id="subtitle" autocomplete="off" />
				</div><!-- #subtitlewrap -->
			</div><!-- #subtitlediv --><?php

			do_action( 'edit_form_after_subtitle', $post );
		} // end build_subtitle_input()

		/**
		 * Validate and save custom metadata associated with Subtitles.
		 *
		 * @link http://codex.wordpress.org/Data_Validation
		 * @access public
		 *
		 * @since 1.0.0
		 */
		public function update_subtitle_data( $post_id, $post, $update ) {
			/**
			 * Check current save status of post
			 */
			$is_post_autosave = (bool) wp_is_post_autosave( $post_id ); // Autosave, found in wp-includes/revisison.php
			$is_post_revision = (bool) wp_is_post_revision( $post_id ); // Revision, found in wp-includes/revision.php

			/**
			 * Check current subtitle nonce status of post
			 */
			$is_nonce_set = (bool) isset( $_POST[ self::SUBTITLE_NONCE_NAME ] );
			/**
			 * If the nonce is set then check if it's verified.
			 * This gets rid of undefined index notices for _subtitle_data_nonce.
			 */
			if ( $is_nonce_set ) {
				$nonce = sanitize_key( $_POST[ self::SUBTITLE_NONCE_NAME ] );
				$is_verified_nonce = (bool) wp_verify_nonce( $nonce, basename( __FILE__ ) );
			} else {
				$is_verified_nonce = null;
			}

			/**
			 * Bail if the save status or nonce status of the post isn't correct
			 */
			if ( $is_post_autosave || $is_post_revision || ! $is_verified_nonce || ! $is_nonce_set ) {
				return;
			}

			/**
			 * Bail if the current user doesn't have permission to edit the current post type
			 */
			$post_type_object = (object) get_post_type_object( $post->post_type );
			$can_edit_post_type = (bool) current_user_can( $post_type_object->cap->edit_post, $post_id );

			if ( ! $can_edit_post_type ) {
				return;
			}

			/**
			 * Data validation and sanitization before inputting it into the database.
			 *
			 * Always remember to validate on both input and output. We're using wp_kses
			 * here, and only allowing users to input italicized and bold text in their
			 * subtitles.
			 *
			 * @link http://codex.wordpress.org/Function_Reference/wp_kses
			 * @since 1.0.0
			 *
			 * @since 2.1.0 We have added in a way for developers to allow more tags in subtitles input.
			 */
			$subtitles_allowed_tags = array(
				'i' => array(), // italicized text
				'em' => array(), // emphasized text
				'strong' => array(), // strong text
			);
			/**
			 * @since 2.1.0 We have added in a way for developers to allow more tags in subtitles input.
			 */
			$subtitles_allowed_tags = apply_filters( 'subtitles_allowed_tags', $subtitles_allowed_tags );
			// grab the subtitles meta key
			$subtitle_meta_key = (string) self::SUBTITLE_META_KEY;
			// If a new subtitle has been posted, then use it; otherwise assign an empty value to the subtitle
			$new_subtitle = (string) isset( $_POST[ $subtitle_meta_key ] ) ? wp_kses( $_POST[ $subtitle_meta_key ], $subtitles_allowed_tags ) : null;
			// Get the current subtitle assigned to the post
			$current_subtitle = (string) wp_kses( get_post_meta( $post_id, $subtitle_meta_key, true ), $subtitles_allowed_tags );

			/**
			 * Add meta when key is new or empty for post
			 *
			 * If the current subtitle is empty (hasn't been entered yet) then set it
			 */
			if ( $current_subtitle && '' === $current_subtitle ) {
				add_post_meta(
					$post_id,				// $post_id the post ID
					$subtitle_meta_key,		// $meta_key the metadata name
					$new_subtitle,			// $meta_value the metadata value
					false					// $unique, if this is set to true then the key cannot be re-used
				);
			}

			/**
			 * If the current meta value and the newly entered meta value are different,
			 * then update the post meta
			 */
			if ( ( $new_subtitle && $new_subtitle !== $current_subtitle ) ) {
				update_post_meta(
					$post_id,				// $post_id the post ID
					$subtitle_meta_key,		// $meta_key the metadata name
					$new_subtitle			// $meta_value the metadata value
				);
			}

			/**
			 * If the new subtitle entered is blank
			 */
			if ( '' === $new_subtitle && $current_subtitle ) {
				delete_post_meta(
					$post_id,				// $post_id the post ID
					$subtitle_meta_key,		// $meta_key the metadata name
					$new_subtitle			// $meta_value the metadata value
				);
			}
		} // end update_subtitle_data()

		/**
		 * Enqueue admin scripts and styles.
		 *
		 * @since 1.0.0
		 * @access public
		 */
		public function subtitle_admin_scripts( $hook ) {
			/**
			 * Bail on these scripts and styles if we're not on a post edit screen
			 * or an add new post screen.
			 *
			 * @since 1.0.0
			 */
			if ( 'post-new.php' != $hook && 'post.php' != $hook ) {
				return;
			}

			/**
			 * Load in main Subtitles admin stylesheet
			 *
			 * wp_enqueue_style accepts
			 * - $handle Name of the stylesheet.
			 * - $src    Path to the stylesheet from the root directory of WordPress. Example: '/css/mystyle.css'.
			 * - $deps   An array of registered style handles this stylesheet depends on. Default empty array.
			 * - $ver    String specifying the stylesheet version number, if it has one. This parameter is used
			 *           to ensure that the correct version is sent to the client regardless of caching, and so
			 *           should be included if a version number is available and makes sense for the stylesheet.
			 * - $media  Optional. The media for which this stylesheet has been defined.
			 *           Default 'all'. Accepts 'all', 'aural', 'braille', 'handheld', 'projection', 'print',
			 *           'screen', 'tty', or 'tv'.
			 *
			 * @link http://codex.wordpress.org/Function_Reference/wp_enqueue_style
			 * @since 1.0.0
			 */
			wp_enqueue_style( self::PLUGIN_SLUG . '-admin-style', plugins_url( 'assets/css/subtitles.css' , __FILE__ ), array(), self::VERSION );

			/**
			 * Load in main Subtitles scripts
			 *
			 * wp_enqueue_script accepts
			 * - $handle    Name of the script.
			 * - $src       Path to the script from the root directory of WordPress. Example: '/js/myscript.js'.
			 * - $deps      An array of registered handles this script depends on. Default empty array.
			 * - $ver       Optional. String specifying the script version number, if it has one. This parameter
			 *              is used to ensure that the correct version is sent to the client regardless of caching,
			 *              and so should be included if a version number is available and makes sense for the script.
			 * - $in_footer Optional. Whether to enqueue the script before </head> or before </body>.
			 *              Default 'false'. Accepts 'false' or 'true'.
			 *
			 * @link http://codex.wordpress.org/Function_Reference/wp_enqueue_script
			 * @since 1.0.0
			 */
			wp_enqueue_script( self::PLUGIN_SLUG . '-admin-scripts', plugins_url( 'assets/js/subtitles.js' , __FILE__ ), array( 'jquery' ), self::VERSION, true );
		} // end subtitle_admin_scripts()

		/**
		 * Build Subtitle column headers for post, pages, and custom post types.
		 *
		 * @see    function esc_html__
		 * @see    function is_admin
		 * @see    function post_type_supports
		 * @since  2.1.0
		 * @access public
		 */
		public function build_subtitles_column_head( $posts_columns, $post_type = 'page' ) {
			if ( ! is_admin() ) {
				return;
			}

			$post_type_support = post_type_supports( $post_type, self::SUBTITLE_FEATURE_SUPPORT );
			if ( $post_type_support ) {
				$posts_columns['subtitle'] = esc_html__( 'Subtitle', 'subtitles' );
			}

			return $posts_columns;
		} // end function build_subtitles_column_head

		/**
		 * Build Subtitle column content for post, pages, and custom post types.
		 *
		 * @see    function is_admin
		 * @see    function get_the_subtitle
		 * @since  2.1.0
		 * @access public
		 */
		public function build_subtitles_column_content( $column_name, $post_id ) {
			if ( ! is_admin() || 'subtitle' !== $column_name ) {
				return;
			}

			$subtitle = get_the_subtitle( $post_id );

			if ( ! empty( $subtitle ) ) {
				echo $subtitle; // WPCS: XSS OK
			}
		} // end function build_subtitles_column_content
	} // end class Subtitles_Admin
} // End if().
