<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit; // security check, don't load file outside WP
}

class Sensei_Autoloader_Bundle {
	/**
	 * @var path to the includes directory within Sensei.
	 */
	private $include_path      = 'includes';
	private $bundle_identifier = 'sensei';

	/**
	 * Sensei_Autoloader_Bundle constructor.
	 *
	 * @param string $bundle_identifier
	 * @param string $namespace_path path relative to includes
	 */
	public function __construct( $bundle_identifier = 'sensei', $bundle_identifier_path = '' ) {
		$this->bundle_identifier = $bundle_identifier;
		// setup a relative path for the current autoload instance
		$this->include_path = trailingslashit( trailingslashit( untrailingslashit( dirname( __FILE__ ) ) ) . $bundle_identifier_path );
	}

	private function format_namespace() {
		return strtolower( $this->bundle_identifier );
	}

	/**
	 * @param $class string
	 * @return bool
	 */
	public function load_class( $class ) {

		if ( ! is_numeric( strpos( strtolower( $class ), $this->format_namespace() ) ) ) {
			return false;
		}

		// check for file in the main includes directory
		$class_file_path = $this->include_path . 'class-' . str_replace( '_', '-', strtolower( $class ) ) . '.php';
		if ( file_exists( $class_file_path ) ) {

			require_once $class_file_path;
			return true;
		}

		// lastly check legacy types
		$stripped_woothemes_from_class = str_replace( 'woothemes_', '', strtolower( $class ) ); // remove woothemes
		$legacy_class_file_path        = $this->include_path . 'class-' . str_replace( '_', '-', strtolower( $stripped_woothemes_from_class ) ) . '.php';
		if ( file_exists( $legacy_class_file_path ) ) {

			require_once $legacy_class_file_path;
			return true;
		}

		return false;

	}//end load_class()
}

/**
 * Loading all class files within the Sensei/includes directory
 *
 * The auto loader class listens for calls to classes within Sensei and loads
 * the file containing the class.
 *
 * @package Core
 * @since 1.9.0
 */
class Sensei_Autoloader {

	/**
	 * @var path to the includes directory within Sensei.
	 */
	private $include_path = 'includes';

	/**
	 * @var array $class_file_map. List of classes mapped to their files
	 */
	private $class_file_map = array();

	private $autoloader_bundles = array();

	/**
	 * Constructor
	 *
	 * @since 1.9.0
	 */
	public function __construct() {

		// make sure we do not override an existing autoload function
		if ( function_exists( '__autoload' ) ) {
			spl_autoload_register( '__autoload' );
		}

		// setup a relative path for the current autoload instance
		$this->include_path = trailingslashit( untrailingslashit( dirname( __FILE__ ) ) );

		// setup the class file map
		$this->initialize_class_file_map();

		$this->autoloader_bundles = array(
			new Sensei_Autoloader_Bundle( 'Sensei_REST_API', 'rest-api' ),
			new Sensei_Autoloader_Bundle( 'Sensei_Domain_Models', 'domain-models' ),
			new Sensei_Autoloader_Bundle( 'Sensei', '' ),
		);

		// add Sensei custom auto loader
		spl_autoload_register( array( $this, 'autoload' ) );

	}

	/**
	 * Generate a list of Sensei class and map them the their respective
	 * files within the includes directory
	 *
	 * @since 1.9.0
	 */
	public function initialize_class_file_map() {

		$this->class_file_map = array(

			/**
			 * Main Sensei class
			 */
			'Sensei_Main'                                => 'class-sensei.php',

			/**
			 * Admin
			 */
			'Sensei_Learner_Management'                  => 'admin/class-sensei-learner-management.php',

			/**
			 * Shortcodes
			 */
			'Sensei_Shortcode_Loader'                    => 'shortcodes/class-sensei-shortcode-loader.php',
			'Sensei_Shortcode_Interface'                 => 'shortcodes/interface-sensei-shortcode.php',
			'Sensei_Shortcode_Featured_Courses'          => 'shortcodes/class-sensei-shortcode-featured-courses.php',
			'Sensei_Shortcode_User_Courses'              => 'shortcodes/class-sensei-shortcode-user-courses.php',
			'Sensei_Shortcode_Courses'                   => 'shortcodes/class-sensei-shortcode-courses.php',
			'Sensei_Shortcode_Teachers'                  => 'shortcodes/class-sensei-shortcode-teachers.php',
			'Sensei_Shortcode_User_Messages'             => 'shortcodes/class-sensei-shortcode-user-messages.php',
			'Sensei_Shortcode_Course_Page'               => 'shortcodes/class-sensei-shortcode-course-page.php',
			'Sensei_Shortcode_Lesson_Page'               => 'shortcodes/class-sensei-shortcode-lesson-page.php',
			'Sensei_Shortcode_Course_Categories'         => 'shortcodes/class-sensei-shortcode-course-categories.php',
			'Sensei_Shortcode_Unpurchased_Courses'       => 'shortcodes/class-sensei-shortcode-unpurchased-courses.php',
			'Sensei_Legacy_Shortcodes'                   => 'shortcodes/class-sensei-legacy-shortcodes.php',

			/**
			 * Renderers
			 */
			'Sensei_Renderer_Interface'                  => 'renderers/interface-sensei-renderer.php',
			'Sensei_Renderer_Single_Post'                => 'renderers/class-sensei-renderer-single-post.php',

			/**
			 * Unsupported theme handlers.
			 */
			'Sensei_Unsupported_Theme_Handler_Interface' => 'unsupported-theme-handlers/interface-sensei-unsupported-theme-handler.php',
			'Sensei_Unsupported_Theme_Handler_Page_Imitator' => 'unsupported-theme-handlers/class-sensei-unsupported-theme-handler-page-imitator.php',
			'Sensei_Unsupported_Theme_Handler_Utils'     => 'unsupported-theme-handlers/class-sensei-unsupported-theme-handler-utils.php',
			'Sensei_Unsupported_Theme_Handler_CPT'       => 'unsupported-theme-handlers/class-sensei-unsupported-theme-handler-cpt.php',
			'Sensei_Unsupported_Theme_Handler_Module'    => 'unsupported-theme-handlers/class-sensei-unsupported-theme-handler-module.php',
			'Sensei_Unsupported_Theme_Handler_Course_Results' => 'unsupported-theme-handlers/class-sensei-unsupported-theme-handler-course-results.php',
			'Sensei_Unsupported_Theme_Handler_Lesson_Tag_Archive' => 'unsupported-theme-handlers/class-sensei-unsupported-theme-handler-lesson-tag-archive.php',
			'Sensei_Unsupported_Theme_Handler_Teacher_Archive' => 'unsupported-theme-handlers/class-sensei-unsupported-theme-handler-teacher-archive.php',
			'Sensei_Unsupported_Theme_Handler_Message_Archive' => 'unsupported-theme-handlers/class-sensei-unsupported-theme-handler-message-archive.php',
			'Sensei_Unsupported_Theme_Handler_Learner_Profile' => 'unsupported-theme-handlers/class-sensei-unsupported-theme-handler-learner-profile.php',
			'Sensei_Unsupported_Theme_Handler_Course_Archive' => 'unsupported-theme-handlers/class-sensei-unsupported-theme-handler-course-archive.php',

			/**
			 * Built in theme integration support
			 */
			'Sensei_Theme_Integration_Loader'            => 'theme-integrations/theme-integration-loader.php',
			'Sensei__S'                                  => 'theme-integrations/underscores.php',
			'Sensei_Twentyeleven'                        => 'theme-integrations/twentyeleven.php',
			'Sensei_Twentytwelve'                        => 'theme-integrations/twentytwelve.php',
			'Sensei_Twentythirteen'                      => 'theme-integrations/Twentythirteen.php',
			'Sensei_Twentyfourteen'                      => 'theme-integrations/Twentyfourteen.php',
			'Sensei_Twentyfifteen'                       => 'theme-integrations/Twentyfifteen.php',
			'Sensei_Twentysixteen'                       => 'theme-integrations/Twentysixteen.php',
			'Sensei_Storefront'                          => 'theme-integrations/Storefront.php',

			/**
			 * WooCommerce
			 */
			'Sensei_WC'                                  => 'class-sensei-wc.php',

			/**
			 * WooCommerce Memberships
			 */
			'Sensei_WC_Memberships'                      => 'class-sensei-wc-memberships.php',

			/**
			* WPML
			*/
			'Sensei_WPML'                                => 'wpml/class-sensei-wpml.php',

		);
	}

	/**
	 * Autoload all sensei files as the class names are used.
	 */
	public function autoload( $class ) {

		// only handle classes with the word `sensei` in it
		if ( ! is_numeric( strpos( strtolower( $class ), 'sensei' ) ) ) {

			return;

		}

		// exit if we didn't provide mapping for this class
		if ( isset( $this->class_file_map[ $class ] ) ) {

			$file_location = $this->include_path . $this->class_file_map[ $class ];
			require_once $file_location;
			return;

		}

		foreach ( $this->autoloader_bundles as $bundle ) {
			if ( true === $bundle->load_class( $class ) ) {
				return;
			}
		}

		return;

	}//end autoload()

}
