<?php
namespace WPDRMS\ASP;

class Autoloader {
	protected static $_instance;

	protected $aliases = array(
		// Legacy non-namespaced aliases
		'asp_indexTable' => 'WPDRMS\\ASP\\Index\\IndexProcessor',
		'ASP_Query'      => 'WPDRMS\\ASP\\Query\\SearchQuery',

		// WPDRMS\ASP\Models -> WPDRMS\ASP\Query (moved in 4.29+)
		'WPDRMS\\ASP\\Models\\SearchQueryArgs' => 'WPDRMS\\ASP\\Query\\SearchQueryArgs',

		// WPDRMS\ASP\Utils -> WPDRMS\Utils (moved to shared/utils in 4.29+)
		'WPDRMS\\ASP\\Utils\\Archive'      => 'WPDRMS\\Utils\\Archive',
		'WPDRMS\\ASP\\Utils\\ArrayUtils'   => 'WPDRMS\\Utils\\ArrayUtils',
		'WPDRMS\\ASP\\Utils\\Css'          => 'WPDRMS\\Utils\\Css',
		'WPDRMS\\ASP\\Utils\\Database'     => 'WPDRMS\\Utils\\Database',
		'WPDRMS\\ASP\\Utils\\FileManager'  => 'WPDRMS\\Utils\\FileManager',
		'WPDRMS\\ASP\\Utils\\Html'         => 'WPDRMS\\Utils\\Html',
		'WPDRMS\\ASP\\Utils\\MB'           => 'WPDRMS\\Utils\\MB',
		'WPDRMS\\ASP\\Utils\\MobileDetect' => 'WPDRMS\\Utils\\MobileDetect',
		'WPDRMS\\ASP\\Utils\\ParseStr'     => 'WPDRMS\\Utils\\ParseStr',
		'WPDRMS\\ASP\\Utils\\Post'         => 'WPDRMS\\Utils\\Post',
		'WPDRMS\\ASP\\Utils\\PostMeta'     => 'WPDRMS\\Utils\\PostMeta',
		'WPDRMS\\ASP\\Utils\\Script'       => 'WPDRMS\\Utils\\Script',
		'WPDRMS\\ASP\\Utils\\Server'       => 'WPDRMS\\Utils\\Server',
		'WPDRMS\\ASP\\Utils\\Str'          => 'WPDRMS\\Utils\\Str',
		'WPDRMS\\ASP\\Utils\\Suggest'      => 'WPDRMS\\Utils\\Suggest',
		'WPDRMS\\ASP\\Utils\\Taxonomy'     => 'WPDRMS\\Utils\\Taxonomy',
		'WPDRMS\\ASP\\Utils\\User'         => 'WPDRMS\\Utils\\User',
		'WPDRMS\\ASP\\Utils\\WPMU'         => 'WPDRMS\\Utils\\WPMU',
		'WPDRMS\\ASP\\Utils\\WooCommerce'  => 'WPDRMS\\Utils\\WooCommerce',

		// WPDRMS\ASP\Cache -> WPDRMS\Utils (moved to shared/utils in 4.29+)
		'WPDRMS\\ASP\\Cache\\BFI_Thumb_1_3' => 'WPDRMS\\Utils\\BFI_Thumb_1_3',

		// WPDRMS\ASP\ORM, Patterns, Rest -> WPDRMS\PluginCore (moved to shared/plugin-core in 4.29+)
		'WPDRMS\\ASP\\ORM\\Model'                              => 'WPDRMS\\PluginCore\\ORM\\Model',
		'WPDRMS\\ASP\\Patterns\\JsonSerializablePublicProperties' => 'WPDRMS\\PluginCore\\Traits\\JsonSerializablePublicProperties',
		'WPDRMS\\ASP\\Patterns\\ObjectAsArrayTrait'            => 'WPDRMS\\PluginCore\\Traits\\ObjectAsArrayTrait',
		'WPDRMS\\ASP\\Patterns\\SingletonTrait'                => 'WPDRMS\\PluginCore\\Traits\\SingletonTrait',
		'WPDRMS\\ASP\\Rest\\AbstractRest'                      => 'WPDRMS\\PluginCore\\Rest\\AbstractRest',
		'WPDRMS\\ASP\\Rest\\RestInterface'                     => 'WPDRMS\\PluginCore\\Rest\\RestInterface',

		// WPDRMS\ASP\Options -> WPDRMS\AdminUI (moved to shared/admin-ui in 4.29+)
		'WPDRMS\\ASP\\Options\\Data\\AbstractOptionData'           => 'WPDRMS\\AdminUI\\Data\\AbstractOptionData',
		'WPDRMS\\ASP\\Options\\Data\\AbstractOptionDataSiteOption' => 'WPDRMS\\AdminUI\\Data\\AbstractOptionDataSiteOption',
		'WPDRMS\\ASP\\Options\\Data\\OptionData'                   => 'WPDRMS\\AdminUI\\Data\\OptionData',
		'WPDRMS\\ASP\\Options\\Data\\OptionDataORM'                => 'WPDRMS\\AdminUI\\Data\\OptionDataORM',
		'WPDRMS\\ASP\\Options\\Factories\\OptionFactory'           => 'WPDRMS\\AdminUI\\OptionFactory',
		'WPDRMS\\ASP\\Options\\Models\\AbstractOption'             => 'WPDRMS\\AdminUI\\Options\\AbstractOption',
		'WPDRMS\\ASP\\Options\\Models\\BoolOption'                 => 'WPDRMS\\AdminUI\\Options\\BoolOption',
		'WPDRMS\\ASP\\Options\\Models\\BorderOption'               => 'WPDRMS\\AdminUI\\Options\\BorderOption',
		'WPDRMS\\ASP\\Options\\Models\\BoxShadowOption'            => 'WPDRMS\\AdminUI\\Options\\BoxShadowOption',
		'WPDRMS\\ASP\\Options\\Models\\DirectoryListOption'        => 'WPDRMS\\AdminUI\\Options\\DirectoryListOption',
		'WPDRMS\\ASP\\Options\\Models\\IntArrayOption'             => 'WPDRMS\\AdminUI\\Options\\IntArrayOption',
		'WPDRMS\\ASP\\Options\\Models\\IntOption'                  => 'WPDRMS\\AdminUI\\Options\\IntOption',
		'WPDRMS\\ASP\\Options\\Models\\Option'                     => 'WPDRMS\\AdminUI\\Options\\Option',
		'WPDRMS\\ASP\\Options\\Models\\SelectOption'               => 'WPDRMS\\AdminUI\\Options\\SelectOption',
		'WPDRMS\\ASP\\Options\\Models\\StringArrayOption'          => 'WPDRMS\\AdminUI\\Options\\StringArrayOption',
		'WPDRMS\\ASP\\Options\\Models\\StringOption'               => 'WPDRMS\\AdminUI\\Options\\StringOption',
		'WPDRMS\\ASP\\Options\\Routes\\DirectoriesRoute'           => 'WPDRMS\\AdminUI\\Routes\\DirectoriesRoute',
		'WPDRMS\\ASP\\Options\\Routes\\TaxonomyTermsRoute'         => 'WPDRMS\\AdminUI\\Routes\\TaxonomyTermsRoute',
		'WPDRMS\\ASP\\Options\\Routes\\UsersRoute'                 => 'WPDRMS\\AdminUI\\Routes\\UsersRoute',

		// WPDRMS\ASP\Synonyms\Manager → SynonymsService (renamed in 4.x+)
		'WPDRMS\\ASP\\Synonyms\\Manager' => 'WPDRMS\\ASP\\Synonyms\\SynonymsService',

		// WPDRMS\ASP\Index\Database → IndexTable (moved to ORM folder in 4.x+)
		'WPDRMS\\ASP\\Index\\Database' => 'WPDRMS\\ASP\\Index\\ORM\\IndexTable',

		// WPDRMS\ASP\Index\Manager → IndexProcessor (shim removed in 4.x+)
		'WPDRMS\\ASP\\Index\\Manager' => 'WPDRMS\\ASP\\Index\\IndexProcessor',

		// WPDRMS\ASP\Misc\PriorityGroups → PrioritiesService (moved in 4.x+)
		'WPDRMS\\ASP\\Misc\\PriorityGroups' => 'WPDRMS\\ASP\\Priorities\\PrioritiesService',
	);

	private function __construct() {
		defined('ABSPATH') or die();

		spl_autoload_register( array( $this, 'loader' ) );

		// Proactively register namespace-based aliases so type hints in customer code
		// (e.g. eval'd snippets) resolve correctly regardless of when they are evaluated.
		// Only alias when the target class is already loaded — triggering autoload here
		// would eagerly load classes that other code (e.g. Mockery alias mocks) expects
		// to find unloaded until first real use.
		foreach ( $this->aliases as $old => $new ) {
			if ( strpos($old, '\\') !== false && !class_exists($old, false) && class_exists($new, false) ) {
				class_alias($new, $old);
			}
		}
	}

	function loader( $class ) {

		// project-specific namespace prefix
		$prefix = 'WPDRMS\\ASP\\';

		// base directory for the namespace prefix
		$base_dir = ASP_CLASSES_PATH;

		// does the class use the namespace prefix?
		$len = strlen($prefix);

		if ( strncmp($prefix, $class, $len) !== 0 ) {
			// is this an alias?
			if ( isset($this->aliases[ $class ]) ) {
				if ( !class_exists($this->aliases[ $class ]) ) {
					$this->loader($this->aliases[ $class ]);
				}

				if ( class_exists($this->aliases[ $class ]) ) {
					/**
					 * Create class alias for old class names
					 */
					class_alias($this->aliases[ $class ], $class);
				}
			}
		} else {
			// get the relative class name
			$relative_class = substr($class, $len);

			// replace the namespace prefix with the base directory, replace namespace
			// separators with directory separators in the relative class name, append
			// with .php
			$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';

			// if the file exists, require it
			if ( file_exists($file) ) {
				require $file;
			} elseif ( isset($this->aliases[ $class ]) ) {
				if ( !class_exists($this->aliases[ $class ]) ) {
					$this->loader($this->aliases[ $class ]);
				}
				if ( class_exists($this->aliases[ $class ]) ) {
					class_alias($this->aliases[ $class ], $class);
				}
			}
		}
	}

	// ------------------------------------------------------------
	// ---------------- SINGLETON SPECIFIC --------------------
	// ------------------------------------------------------------
	public static function getInstance() {
		if ( ! ( self::$_instance instanceof self ) ) {
			self::$_instance = new self();
		}

		return self::$_instance;
	}
}
Autoloader::getInstance();
