<?php
/**
 * Community Events Autoloader
 *
 * @package Calendarize_it
 * @since 4.7.0
 */

namespace Calendarize_it;

use Exception;
use WP_ERROR;

defined( 'ABSPATH' ) || exit;

/**
 * Autoloader class.
 *
 * @since 4.7.0
 */
class Autoloader {

	/**
	 * The plugin file.
	 *
	 * @since 4.7.0
	 * @var string
	 */
	private static $plugin_file;

	/**
	 * The subpackage name.
	 *
	 * @since 4.7.0
	 * @var string
	 */
	private static $subpackage = '';

	/**
	 * The source directory name.
	 *
	 * @since 4.7.0
	 * @var string
	 */
	private static $src_dir_name = '';

	/**
	 * Formats the string to the autoload standard.
	 *
	 * @since 4.7.0
	 *
	 * @param string $search  The value being searched for.
	 * @param string $replace The replacement value that replaces found search values.
	 * @param string $string  The input string.
	 *
	 * @return string
	 */
	private static function format( $search, $replace, $string ) {
		return strtolower( str_replace( $search, $replace, $string ) );
	}

	/**
	 * Registers the autoload function.
	 *
	 * @since 4.7.0
	 *
	 * @param string $plugin_file  The plugin file.
	 * @param string $subpackge    The subpackage.
	 * @param string $src_dir_name The source directory name.
	 *
	 * @return WP_Error Returns on failure.
	 */
	public static function register( $plugin_file, $subpackage = '', $src_dir_name = 'includes' ) {
		static::$plugin_file  = $plugin_file;
		static::$subpackage   = $subpackage;
		static::$src_dir_name = trailingslashit( $src_dir_name );

		try {
			spl_autoload_register( array( __CLASS__, 'autoload' ) );
		} catch ( Exception $e ) {
			$prefix = statis::format( '-', '_', basename( dirname( static::$plugin_file ) ) );

			return new WP_Error( $prefix . '_autoload_failed', $e->getMessage() );
		}
	}

	/**
	 * Gets the file name from the class.
	 *
	 * @since 4.7.0
	 *
	 * @param string $class The class name.
	 *
	 * @return string
	 */
	private static function get_file_name( $class ) {
		return sprintf( 'class-%s.php', static::format( '_', '-', static::get_class_name( $class ) ) );
	}

	/**
	 * Gets the class name from the fully qualified class name.
	 *
	 * @since 4.7.0
	 *
	 * @param string $class The class name.
	 *
	 * @return string
	 */
	private static function get_class_name( $class ) {
		return substr( $class, strrpos( $class, '\\' ) + 1 );
	}

	/**
	 * Gets the includes directory path.
	 *
	 * @since 4.7.0
	 *
	 * @param string $class The class name.
	 *
	 * @return string
	 */
	private static function get_src_dir_path( $class ) {
		return plugin_dir_path( static::$plugin_file ) . static::$src_dir_name . static::get_path_in_src_dir( $class );
	}

	/**
	 * Gets the namespace.
	 *
	 * @since 4.7.0
	 *
	 * @return string
	 */

	private static function get_namespace() {
		return static::$subpackage ? __NAMESPACE__ . '\\'  . static::$subpackage : __NAMESPACE__;
	}

	/**
	 * Gets the inner path in the soruce directory from the class.
	 *
	 * @since 4.7.0
	 *
	 * @param string $class The class name.
	 *
	 * @return string
	 */
	private static function get_path_in_src_dir( $class ) {
		$namespace_length  = strlen( static::get_namespace() );
		$before_class_name = strrpos( $class, '\\' );
		$path              = '';

		if ( $namespace_length !== $before_class_name ) {
			$folders = substr( $class, $namespace_length + 1, $before_class_name - $namespace_length );
			$path   .= static::format( '\\', '/', $folders );
		}

		return $path;
	}

	/**
	 * Auto-loads classes.
	 *
	 * @since 4.7.0
	 *
	 * @param string $class The class name.
	 */
	public static function autoload( $class ) {
		if ( 0 !== strpos( $class, static::get_namespace() ) ) {
			return;
		}

		$src_dir_path = static::get_src_dir_path( $class );
		$file_name = static::get_file_name( $class );

		require_once $src_dir_path . $file_name;
	}

}
