<?php

namespace GS_BOOKS;

defined( 'ABSPATH' ) || exit;

class Autoloader {

	/**
	 * Instance of Autoloader
	 *
	 * @var Autoloader
	 */
	private static $instance = null;

	/**
	 * Classes map.
	 * Maps classes to file names.
	 *
	 * @access private
	 * @static
	 * @var    array Classes array use by GS Bookshowcase.
	 */
	private static $classesMap;

	/**
	 * Classes directory.
	 * Maps classes to file names.
	 *
	 * @access private
	 * @static
	 *
	 * Classes folder used for @package GS Bookshowcase.
	 */
	private static $SOURCE_DIRECTORY = GS_BOOKS_PLUGIN_DIR;

	/**
	 * Classmap file for Autoloader
	 *
	 * @access private
	 * @static
	 *
	 * Classes array used for @package GS Bookshowcase.
	 */
	private static $CLASS_MAPS_FILE = __DIR__ . '/classmaps.php';

	/**
	 * Get a single instace of Autoloader
	 *
	 * @return Autoloader
	 */
	public static function init() {
		if ( is_null( self::$instance ) ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Automatically get invoked when initialize the Autoloader.
	 */
	public function __construct() {
		spl_autoload_register( array( &$this, 'autoload' ) );
	}

	/**
	 * Autoload a class.
	 *
	 * @access private
	 *
	 * @param string $class Class name.
	 */
	private function autoload( $class ) {
		if ( 0 !== strpos( $class, __NAMESPACE__ . '\\' ) ) {
			return;
		}

		$relative_class_name = preg_match( '/.*\\\\([\\w]+)/', $class, $matches );

		if ( count( $matches ) > 1 ) {
			$relative_class_name = $matches[1];
		}

		if ( ! class_exists( $class ) ) {
			self::load_class( $relative_class_name );
		}
	}

	/**
	 * Load class.
	 * For a given class name, require the class file.
	 *
	 * @access private
	 * @static
	 *
	 * @param string $relative_class_name Class name.
	 */
	private static function load_class( $relative_class_name ) {
		$classesMap = self::get_classes_map();

		if ( isset( $classesMap[ $relative_class_name ] ) ) {
			$filename = self::$SOURCE_DIRECTORY . $classesMap[ $relative_class_name ];
			if ( is_readable( $filename ) ) {
				require $filename;
			}
		}
	}

	/**
	 * Get the class map, if its not set than load the classmap file.
	 *
	 * @return void
	 */
	private static function get_classes_map() {
		if ( ! self::$classesMap ) {
			self::init_classes_map();
		}
		return self::$classesMap;
	}

	/**
	 * Loader of the classmap file.
	 *
	 * @return array of classes.
	 */
	private static function init_classes_map() {
		self::$classesMap = require_once self::$CLASS_MAPS_FILE;
	}
}

Autoloader::init();
