<?php
/**
 * CPTGenerator
 *
 * @package CommonFrameworkPlugin
 */

namespace CommonFrameworkPlugin;

/**
 * Class CPTGenerator
 *
 * Responsible for generating custom post types and taxonomies for the CommonFrameworkPlugin.
 */
class CPTGenerator extends \CommonFrameworkPlugin\Module {

	/**
	 * Used to alter the order in which classes are initialized.
	 *
	 * Lower number will be initialized first.
	 *
	 * @note This has no correlation to the `init` priority. It's just a way to allow certain classes to be initialized before others.
	 *
	 * @var int The priority of the module.
	 */
	public $load_order = 1;

	/**
	 * Determines if registration can happen.
	 *
	 * @return bool True if registration is allowed.
	 */
	public function can_register() {
		return true;
	}

	/**
	 * Registers hooks related to custom post types and taxonomies.
	 *
	 * @return void
	 */
	public function register() {}

	/**
	 * Registers a custom post type.
	 *
	 * @param array $fields The array of fields required to register the post type.
	 *
	 * @link https://codex.wordpress.org/Function_Reference/register_post_type
	 */
	public function register_single_post_type( $fields ) {

		/**
		 * Labels used when displaying the posts in the admin and sometimes on the front end.
		 */
		$labels = array(
			'name'                  => $fields['plural'],
			'singular_name'         => $fields['singular'],
			'menu_name'             => $fields['menu_name'],
			'new_item'              => sprintf( __( 'New %s', 'common-framework' ), $fields['singular'] ),
			'add_new'               => sprintf( __( 'Add New %s', 'common-framework' ), $fields['singular'] ),
			'add_new_item'          => sprintf( __( 'Add New %s', 'common-framework' ), $fields['singular'] ),
			'edit_item'             => sprintf( __( 'Edit %s', 'common-framework' ), $fields['singular'] ),
			'view_item'             => sprintf( __( 'View %s', 'common-framework' ), $fields['singular'] ),
			'view_items'            => sprintf( __( 'View %s', 'common-framework' ), $fields['plural'] ),
			'search_items'          => sprintf( __( 'Search %s', 'common-framework' ), $fields['plural'] ),
			'not_found'             => sprintf( __( 'No %s found', 'common-framework' ), strtolower( $fields['plural'] ) ),
			'not_found_in_trash'    => sprintf( __( 'No %s found in trash', 'common-framework' ), strtolower( $fields['plural'] ) ),
			'all_items'             => sprintf( __( 'All %s', 'common-framework' ), $fields['plural'] ),
			'archives'              => sprintf( __( '%s Archives', 'common-framework' ), $fields['singular'] ),
			'attributes'            => sprintf( __( '%s Attributes', 'common-framework' ), $fields['singular'] ),
			'insert_into_item'      => sprintf( __( 'Insert into %s', 'common-framework' ), strtolower( $fields['singular'] ) ),
			'uploaded_to_this_item' => sprintf( __( 'Uploaded to this %s', 'common-framework' ), strtolower( $fields['singular'] ) ),

			/* Labels for hierarchical post types only. */
			'parent_item'           => sprintf( __( 'Parent %s', 'common-framework' ), $fields['singular'] ),
			'parent_item_colon'     => sprintf( __( 'Parent %s:', 'common-framework' ), $fields['singular'] ),

			/* Custom archive label. Must filter 'post_type_archive_title' to use. */
			'archive_title'        => $fields['plural'],
		);

		$args = array(
			'labels'             => $labels,
			'description'        => ( isset( $fields['description'] ) ) ? $fields['description'] : '',
			'public'             => ( isset( $fields['public'] ) ) ? $fields['public'] : true,
			'publicly_queryable' => ( isset( $fields['publicly_queryable'] ) ) ? $fields['publicly_queryable'] : true,
			'exclude_from_search' => ( isset( $fields['exclude_from_search'] ) ) ? $fields['exclude_from_search'] : false,
			'show_ui'            => ( isset( $fields['show_ui'] ) ) ? $fields['show_ui'] : true,
			'show_in_menu'       => ( isset( $fields['show_in_menu'] ) ) ? $fields['show_in_menu'] : true,
			'query_var'          => ( isset( $fields['query_var'] ) ) ? $fields['query_var'] : true,
			'show_in_admin_bar'  => ( isset( $fields['show_in_admin_bar'] ) ) ? $fields['show_in_admin_bar'] : true,
			'capability_type'    => ( isset( $fields['capability_type'] ) ) ? $fields['capability_type'] : 'post',
			'has_archive'        => ( isset( $fields['has_archive'] ) ) ? $fields['has_archive'] : true,
			'hierarchical'       => ( isset( $fields['hierarchical'] ) ) ? $fields['hierarchical'] : true,
			'supports'           => ( isset( $fields['supports'] ) ) ? $fields['supports'] : array(
				'title',
				'editor',
				'excerpt',
				'author',
				'thumbnail',
				'comments',
				'trackbacks',
				'custom-fields',
				'revisions',
				'page-attributes',
				'post-formats',
			),
			'menu_position'      => ( isset( $fields['menu_position'] ) ) ? $fields['menu_position'] : 21,
			'menu_icon'          => ( isset( $fields['menu_icon'] ) ) ? $fields['menu_icon'] : 'dashicons-admin-generic',
			'show_in_nav_menus'  => ( isset( $fields['show_in_nav_menus'] ) ) ? $fields['show_in_nav_menus'] : true,
			'show_in_rest'       => ( isset( $fields['show_in_rest'] ) ) ? $fields['show_in_rest'] : true,
		);

		if ( isset( $fields['rewrite'] ) ) {
			$args['rewrite'] = $fields['rewrite'];
		}

		if ( $fields['custom_caps'] ) {
			$args['capabilities'] = array(
				'edit_post'                 => 'edit_' . strtolower( $fields['singular'] ),
				'read_post'                 => 'read_' . strtolower( $fields['singular'] ),
				'delete_post'               => 'delete_' . strtolower( $fields['singular'] ),
				'edit_posts'                => 'edit_' . strtolower( $fields['plural'] ),
				'edit_others_posts'         => 'edit_others_' . strtolower( $fields['plural'] ),
				'publish_posts'             => 'publish_' . strtolower( $fields['plural'] ),
				'read_private_posts'        => 'read_private_' . strtolower( $fields['plural'] ),
				'delete_posts'              => 'delete_' . strtolower( $fields['plural'] ),
				'delete_private_posts'      => 'delete_private_' . strtolower( $fields['plural'] ),
				'delete_published_posts'    => 'delete_published_' . strtolower( $fields['plural'] ),
				'delete_others_posts'       => 'delete_others_' . strtolower( $fields['plural'] ),
				'edit_private_posts'        => 'edit_private_' . strtolower( $fields['plural'] ),
				'edit_published_posts'      => 'edit_published_' . strtolower( $fields['plural'] ),
				'create_posts'              => 'edit_' . strtolower( $fields['plural'] ),
			);

			$args['map_meta_cap'] = true;

			$this->assign_capabilities( $args['capabilities'], $fields['custom_caps_users'] );
		}

		register_post_type( $fields['slug'], $args );

		if ( isset( $fields['taxonomies'] ) && is_array( $fields['taxonomies'] ) ) {
			foreach ( $fields['taxonomies'] as $taxonomy ) {
				$this->register_single_post_type_taxnonomy( $taxonomy );
			}
		}
	}

	/**
	 * Registers a single taxonomy for a custom post type.
	 *
	 * @param array $tax_fields The array of taxonomy fields.
	 *
	 * @return void
	 */
	private function register_single_post_type_taxnonomy( $tax_fields ) {
		$labels = array(
			'name'                       => $tax_fields['plural'],
			'singular_name'              => $tax_fields['single'],
			'menu_name'                  => $tax_fields['plural'],
			'all_items'                  => sprintf( __( 'All %s', 'common-framework' ), $tax_fields['plural'] ),
			'edit_item'                  => sprintf( __( 'Edit %s', 'common-framework' ), $tax_fields['single'] ),
			'view_item'                  => sprintf( __( 'View %s', 'common-framework' ), $tax_fields['single'] ),
			'update_item'                => sprintf( __( 'Update %s', 'common-framework' ), $tax_fields['single'] ),
			'add_new_item'               => sprintf( __( 'Add New %s', 'common-framework' ), $tax_fields['single'] ),
			'new_item_name'              => sprintf( __( 'New %s Name', 'common-framework' ), $tax_fields['single'] ),
			'parent_item'                => sprintf( __( 'Parent %s', 'common-framework' ), $tax_fields['single'] ),
			'parent_item_colon'          => sprintf( __( 'Parent %s:', 'common-framework' ), $tax_fields['single'] ),
			'search_items'               => sprintf( __( 'Search %s', 'common-framework' ), $tax_fields['plural'] ),
			'popular_items'              => sprintf( __( 'Popular %s', 'common-framework' ), $tax_fields['plural'] ),
			'separate_items_with_commas' => sprintf( __( 'Separate %s with commas', 'common-framework' ), $tax_fields['plural'] ),
			'add_or_remove_items'        => sprintf( __( 'Add or remove %s', 'common-framework' ), $tax_fields['plural'] ),
			'choose_from_most_used'      => sprintf( __( 'Choose from the most used %s', 'common-framework' ), $tax_fields['plural'] ),
			'not_found'                  => sprintf( __( 'No %s found', 'common-framework' ), $tax_fields['plural'] ),
		);

		$args = array(
			'label'                 => $tax_fields['plural'],
			'labels'                => $labels,
			'hierarchical'          => ( isset( $tax_fields['hierarchical'] ) ) ? $tax_fields['hierarchical'] : true,
			'public'                => ( isset( $tax_fields['public'] ) ) ? $tax_fields['public'] : true,
			'show_ui'               => ( isset( $tax_fields['show_ui'] ) ) ? $tax_fields['show_ui'] : true,
			'show_in_nav_menus'     => ( isset( $tax_fields['show_in_nav_menus'] ) ) ? $tax_fields['show_in_nav_menus'] : true,
			'show_tagcloud'         => ( isset( $tax_fields['show_tagcloud'] ) ) ? $tax_fields['show_tagcloud'] : true,
			'meta_box_cb'           => ( isset( $tax_fields['meta_box_cb'] ) ) ? $tax_fields['meta_box_cb'] : null,
			'show_admin_column'     => ( isset( $tax_fields['show_admin_column'] ) ) ? $tax_fields['show_admin_column'] : true,
			'show_in_quick_edit'    => ( isset( $tax_fields['show_in_quick_edit'] ) ) ? $tax_fields['show_in_quick_edit'] : true,
			'update_count_callback' => ( isset( $tax_fields['update_count_callback'] ) ) ? $tax_fields['update_count_callback'] : '',
			'show_in_rest'          => ( isset( $tax_fields['show_in_rest'] ) ) ? $tax_fields['show_in_rest'] : true,
			'rest_base'             => $tax_fields['taxonomy'],
			'rest_controller_class' => ( isset( $tax_fields['rest_controller_class'] ) ) ? $tax_fields['rest_controller_class'] : 'WP_REST_Terms_Controller',
			'query_var'             => $tax_fields['taxonomy'],
			'rewrite'               => ( isset( $tax_fields['rewrite'] ) ) ? $tax_fields['rewrite'] : true,
			'sort'                  => ( isset( $tax_fields['sort'] ) ) ? $tax_fields['sort'] : '',
		);

		$args = apply_filters( $tax_fields['taxonomy'] . '_args', $args );

		register_taxonomy( $tax_fields['taxonomy'], $tax_fields['post_types'], $args );
	}

	/**
	 * Assigns capabilities to users for a custom post type.
	 *
	 * @param array $caps_map The array of capabilities to map.
	 * @param array $users The array of user roles to assign capabilities to.
	 *
	 * @return void
	 */
	private function assign_capabilities( $caps_map, $users ) {
		foreach ( $users as $user ) {
			$user_role = get_role( $user );
			foreach ( $caps_map as $cap_map_key => $capability ) {
				$user_role->add_cap( $capability );
			}
		}
	}
}
