<?php
/**
 * LifterLMS Navigation Menus
 *
 * @package LifterLMS/Classes
 *
 * @since 3.14.7
 * @version 4.12.0
 */

defined( 'ABSPATH' ) || exit;

/**
 * LifterLMS Navigation Menus class.
 *
 * @since 3.14.7
 * @since 3.24.0 Unknown.
 * @since 3.37.12 Fixed possible access to undefined index.
 *                Excluded endpoints with an empty url.
 *                Made sure to use strict comparisons.
 */
class LLMS_Nav_Menus {

	/**
	 * Constructor.
	 *
	 * @since 3.14.7
	 * @since 3.22.0 Unknown.
	 *
	 * @return void
	 */
	public function __construct() {

		// Filter menu items on frontend to add real URLs to menu items.
		add_filter( 'wp_nav_menu_objects', array( $this, 'filter_nav_items' ) );

		// Add meta box to the Appearance -> Menus screen on admin panel.
		add_action( 'load-nav-menus.php', array( $this, 'add_metabox' ) );

		// Add LifterLMS menu item type section to customizer.
		add_filter( 'customize_nav_menu_available_item_types', array( $this, 'customize_add_type' ) );

		// Add LifterLMS menu items links to the customizer.
		add_filter( 'customize_nav_menu_available_items', array( $this, 'customize_add_items' ), 10, 4 );

		// Add active classes for nav items for catalog pages.
		add_filter( 'wp_nav_menu_objects', array( $this, 'menu_item_classes' ) );

	}

	/**
	 * Add nav menu metabox.
	 *
	 * @since 3.14.7
	 *
	 * @return void
	 */
	public function add_metabox() {

		add_meta_box( 'llms-nav-menu', __( 'LifterLMS', 'lifterlms' ), array( $this, 'output' ), 'nav-menus', 'side', 'default' );
		add_action( 'admin_print_footer_scripts', array( $this, 'output_scripts' ) );

	}

	/**
	 * Adds LifterLMS menu items to the customizer.
	 *
	 * @since 3.14.7
	 *
	 * @param array   $items  Optional. Menu items. Default empty array.
	 * @param string  $type   Optional. Requested menu item type. Default empty string.
	 * @param string  $object Optional. Requested menu item object. Default empty string.
	 * @param integer $page   Optional. Requested page number. Default `0`.
	 * @return array
	 */
	public function customize_add_items( $items = array(), $type = '', $object = '', $page = 0 ) {

		if ( 'llms_nav' !== $object ) {
			return $items;
		}

		foreach ( $this->get_nav_items() as $id => $data ) {

			$items[] = array(
				'classes'    => 'llms-nav-item-' . $id,
				'id'         => $id,
				'title'      => $data['title'],
				'type_label' => __( 'Custom Link', 'lifterlms' ),
				'url'        => esc_url_raw( $data['url'] ),
			);

		}

		return array_slice( $items, 10 * $page, 10 );
	}

	/**
	 * Add the LifterLMS menu item section to the customizer.
	 *
	 * @since 3.14.7
	 *
	 * @param array $types Existing menu item types.
	 * @return array
	 */
	public function customize_add_type( $types ) {

		$types['llms_nav_menu_items'] = array(
			'title'  => _x( 'LifterLMS', 'customizer menu section title', 'lifterlms' ),
			'type'   => 'llms_nav',
			'object' => 'llms_nav',
		);

		return $types;
	}

	/**
	 * Filters Nav Menu Items to convert #llms- urls into actual URLs.
	 *
	 * Also hides URLs that should only be available to logged in users.
	 *
	 * @since 3.14.7
	 * @since 3.37.12 Use `in_array` with strict types comparison.
	 *
	 * @param array $items Nav menu items.
	 * @return array
	 */
	public function filter_nav_items( $items ) {

		$urls = array(
			'#llms-signout',
			'#llms-signin',
		);

		foreach ( $items as $i => &$data ) {

			if ( in_array( $data->url, $urls, true ) ) {

				if ( '#llms-signin' === $data->url ) {
					if ( is_user_logged_in() ) {
						unset( $items[ $i ] );
					} else {
						$data->url = llms_get_page_url( 'myaccount' );
					}
				} elseif ( '#llms-signout' === $data->url ) {
					if ( is_user_logged_in() ) {
						$data->url = wp_logout_url( llms_get_page_url( 'myaccount' ) );
					} else {
						unset( $items[ $i ] );
					}
				}
			}
		}

		return $items;
	}

	/**
	 * Retrieve a filtered array of custom LifterLMS nav menu items.
	 *
	 * @since 3.14.7
	 * @since 3.37.12 Fixed possible access to undefined index.
	 *                Excluded endpoints with an empty url.
	 *
	 * @return array
	 */
	private function get_nav_items() {

		$items = array();

		foreach ( LLMS_Student_Dashboard::get_tabs() as $id => $data ) {

			if ( ! empty( $data['nav_item'] ) ) {

				$url = ! empty( $data['endpoint'] ) ? llms_get_endpoint_url( $data['endpoint'], '', llms_get_page_url( 'myaccount' ) ) : '';

				// No URL no nav item.
				if ( empty( $url ) ) {
					if ( empty( $data['url'] ) ) {
						continue;
					} else {
						$url = $data['url'];
					}
				}

				$title = empty( $data['title'] ) ? '' : $data['title'];

				$items[ $id ] = array(
					'url'   => $url,
					'label' => $title,
					'title' => $title,
				);

			}
		}

		$items['signin']  = array(
			'url'   => '#llms-signin',
			'label' => __( 'Sign In', 'lifterlms' ),
			'title' => __( 'Sign In', 'lifterlms' ),
		);
		$items['signout'] = array(
			'url'   => '#llms-signout',
			'label' => __( 'Sign Out', 'lifterlms' ),
			'title' => __( 'Sign Out', 'lifterlms' ),
		);

		/**
		 * Filters array of custom LifterLMS nav menu items
		 *
		 * @since 3.14.7
		 *
		 * @param array $items Array of custom LifterLMS nav menu items.
		 */
		return apply_filters( 'llms_nav_menu_items', $items );

	}

	/**
	 * Add "active" classes to menu items for LLMS catalog pages.
	 *
	 * @since 3.22.0
	 * @since 3.37.12 Use strict comparisons.
	 *                Cast `page_for_posts` option to int in order to use strict comparisons.
	 * @since 4.12.0 Make sure `is_lifterlms()` exists before calling it.
	 *
	 * @param array $menu_items Menu items.
	 * @return array
	 */
	public function menu_item_classes( $menu_items ) {

		if ( ! function_exists( 'is_lifterlms' ) || ! is_lifterlms() ) {
			return $menu_items;
		}

		$courses_id     = llms_get_page_id( 'courses' );
		$memberships_id = llms_get_page_id( 'memberships' );
		$blog_id        = absint( get_option( 'page_for_posts', 0 ) );

		foreach ( $menu_items as $key => $item ) {

			$classes   = $item->classes;
			$object_id = absint( $item->object_id );

			// Remove active class from blog archive.
			if ( $blog_id === $object_id ) {

				$menu_items[ $key ]->current = false;
				foreach ( array( 'current_page_parent', 'current-menu-item' ) as $class ) {
					if ( in_array( $class, $classes, true ) ) {
						unset( $classes[ array_search( $class, $classes, true ) ] );
					}
				}
			} elseif ( 'page' === $item->object && ( ( is_courses() && $courses_id === $object_id ) || ( is_memberships() && $memberships_id === $object_id ) ) ) {

				$menu_items[ $key ]->current = true;
				$classes[]                   = 'current-menu-item';
				$classes[]                   = 'current_page_item';

				// Set parent links for courses & memberships.
			} elseif ( ( $courses_id === $object_id && ( is_singular( 'course' ) || is_course_taxonomy() ) ) || ( $memberships_id === $object_id && ( is_singular( 'llms_membership' ) || is_membership_taxonomy() ) ) ) {

				$classes[] = 'current_page_parent';

			}

			$menu_items[ $key ]->classes = array_unique( $classes );

		}

		return $menu_items;
	}

	/**
	 * Output the metabox.
	 *
	 * @since 3.14.7
	 * @since 3.24.0 Unknown.
	 *
	 * @return void
	 */
	public function output() {

		?>
		<div id="posttype-llms-nav-items" class="posttypediv">
			<div id="tabs-panel-llms-nav-items" class="tabs-panel tabs-panel-active">
				<ul id="llms-nav-items-checklist" class="categorychecklist form-no-clear">
					<?php
					$i = -1;
					foreach ( $this->get_nav_items() as $key => $data ) :
						?>
						<li>
							<label class="menu-item-title">
								<input type="checkbox" class="menu-item-checkbox" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-object-id]" value="<?php echo esc_attr( $i ); ?>" /> <?php echo esc_html( $data['label'] ); ?>
							</label>
							<input type="hidden" class="menu-item-type" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-type]" value="custom" />
							<input type="hidden" class="menu-item-title" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-title]" value="<?php echo esc_html( $data['title'] ); ?>" />
							<input type="hidden" class="menu-item-url" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-url]" value="<?php echo esc_url( $data['url'] ); ?>" />
							<input type="hidden" class="menu-item-classes" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-classes]" value="<?php echo esc_attr( 'llms-nav-item-' . $key ); ?>" />
						</li>
						<?php
						$i--;
					endforeach;
					?>
				</ul>
			</div>
			<p class="button-controls">
				<span class="list-controls">
					<a href="<?php echo admin_url( 'nav-menus.php?page-tab=all&selectall=1#posttype-llms-nav-items' ); ?>" class="select-all"><?php _e( 'Select all', 'lifterlms' ); ?></a>
				</span>
				<span class="add-to-menu">
					<input type="submit" class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( 'Add to menu', 'lifterlms' ); ?>" name="add-post-type-menu-item" id="submit-posttype-llms-nav-items">
					<span class="spinner"></span>
				</span>
			</p>
		</div>
		<?php
	}

	/**
	 * Output JS to ensure that users don't edit the #llms-signout URL that's replaced dynamically with an actual signout link.
	 *
	 * @since 3.14.7
	 *
	 * @return void
	 */
	public function output_scripts() {
		?>
		<script type="text/javascript">
		jQuery( '#menu-to-edit' ).on( 'click', 'a.item-edit', function() {
			var $settings = jQuery(this).closest( '.menu-item-bar' ).next( '.menu-item-settings' ),
				$url = $settings.find( '.edit-menu-item-url' );

			if ( 0 === $url.val().indexOf( '#llms-sign' ) ) {
				$url.closest( 'p.field-url' ).css( 'display', 'none' );
			}
		} );
		</script>
		<?php
	}

}

return new LLMS_Nav_Menus();
