<commit_before><?php
namespace Helhum\ClassAliasLoader\Composer;

/*
 * This file is part of the class alias loader package.
 *
 * (c) <NAME> <<EMAIL>>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use Composer\Package\RootPackageInterface;
use Composer\Util\Filesystem;

/**
 * Class ClassAliasLoader
 */
class ClassAliasGenerator {

	/**
	 * @param \Composer\Script\Event $event
	 * @param bool $calledByPlugin
	 * @return bool
	 * @throws \Exception
	 */
	static public function generateAliasMap(\Composer\Script\Event $event, $calledByPlugin = false) {
		if (!$calledByPlugin) {
			$event->getIO()->write('
<warning>Please remove the section "post-autoload-dump": "Helhum\\ClassAliasLoader\\Composer\\ClassAliasGenerator::generateAliasMap" from your composer.json! It is obsolete.</warning>
');
			return false;
		}
		$event->getIO()->write('<info>Generating class alias map files</info>');

		$composer = $event->getComposer();
		$config = $composer->getConfig();

		$filesystem = new Filesystem();
		$filesystem->ensureDirectoryExists($config->get('vendor-dir'));
		$basePath = $filesystem->normalizePath(realpath(getcwd()));
		$vendorPath = $filesystem->normalizePath(realpath($config->get('vendor-dir')));
		$targetDir = $vendorPath . '/composer';
		$filesystem->ensureDirectoryExists($targetDir);

		$mainPackage = $composer->getPackage();
		$autoLoadGenerator = $composer->getAutoloadGenerator();
		$localRepo = $composer->getRepositoryManager()->getLocalRepository();
		$packageMap = $autoLoadGenerator->buildPackageMap($composer->getInstallationManager(), $mainPackage, $localRepo->getCanonicalPackages());

		$caseSensitiveClassLoading = self::caseSensitiveClassLoading($mainPackage, $targetDir) ? 'true' : 'false';

		$aliasToClassNameMapping = array();
		$classNameToAliasMapping = array();
		$mappingFound = false;

		foreach ($packageMap as $item) {
			list($package, $installPath) = $item;
			$extra = $package->getExtra();
			if (!empty($extra['class-alias-maps'])) {
				if (!is_array($extra['class-alias-maps'])) {
					throw new \Exception('"class-alias-maps" must be an array');
				}
				foreach ($extra['class-alias-maps'] as $mapFile) {
					$mapFilePath = ($installPath ?: $basePath) . '/' . $filesystem->normalizePath($mapFile);
					if (is_file($mapFilePath)) {
						$packageAliasMap = require $mapFilePath;
						if (!is_array($packageAliasMap)) {
							throw new \Exception('"class alias maps" must return an array', 1422625075);
						}
						if (!empty($packageAliasMap)) {
							$mappingFound = true;
						}
						foreach ($packageAliasMap as $aliasClassName => $className) {
							$lowerCasedAliasClassName = strtolower($aliasClassName);
							$aliasToClassNameMapping[$lowerCasedAliasClassName] = $className;
							$classNameToAliasMapping[$className][$lowerCasedAliasClassName] = $lowerCasedAliasClassName;
						}
					}
				}
			}
		}

		if (!$mappingFound) {
			return false;
		}

		$exportArray = array(
			'aliasToClassNameMapping' => $aliasToClassNameMapping,
			'classNameToAliasMapping' => $classNameToAliasMapping
		);

		$fileContent = '<?php' . chr(10) . 'return ';
		$fileContent .= var_export($exportArray, true);
		$fileContent .= ';';

		file_put_contents($targetDir . '/autoload_classaliasmap.php', $fileContent);

		$suffix = NULL;
		if (!$config->get('autoloader-suffix') && is_readable($vendorPath . '/autoload.php')) {
			$content = file_get_contents($vendorPath.'/autoload.php');
			if (preg_match('{ComposerAutoloaderInit([^:\s]+)::}', $content, $match)) {
				$suffix = $match[1];
			}
		}

		if (!$suffix) {
			$suffix = $config->get('autoloader-suffix') ?: md5(uniqid('', true));
		}


		$aliasLoaderInitClassContent = <<<EOF
<?php

// alias_loader_real.php @generated by helhum/class-alias-loader

class ClassAliasLoaderInit$suffix {

	private static \$loader;

	static public function getAliasLoader(\$composerClassLoader) {
		if (null !== self::\$loader) {
			return self::\$loader;
		}

		\$aliasClassLoader = new Helhum\ClassAliasLoader\Composer\ClassAliasLoader(\$composerClassLoader);

		\$classAliasMap = require __DIR__ . '/autoload_classaliasmap.php';
		\$aliasClassLoader->setAliasMap(\$classAliasMap);
		\$aliasClassLoader->setCaseSensitiveClassLoading($caseSensitiveClassLoading);
		spl_autoload_register(array(\$aliasClassLoader, 'loadClassWithAlias'), true, true);
		\$composerClassLoader->unregister();

		self::\$loader = \$aliasClassLoader;

		return \$aliasClassLoader;

	}
}

EOF;

		file_put_contents($targetDir . '/alias_loader_real.php', $aliasLoaderInitClassContent);

		static::modifyMainAutoloadFile($vendorPath . '/autoload.php', $suffix);

		return true;
	}

	/**
	 * @param $autoloadFile
	 * @param string $suffix
	 */
	static protected function modifyMainAutoloadFile($autoloadFile, $suffix) {
		$originalAutoloadFileContent = file_get_contents($autoloadFile);
		preg_match('/return ComposerAutoloaderInit[^;]*;/', $originalAutoloadFileContent, $matches);
		$originalAutoloadFileContent = str_replace($matches[0], '', $originalAutoloadFileContent);
		$composerClassLoaderInit = str_replace(array('return ', ';'), '', $matches[0]);
		$autoloadFileContent = <<<EOF
$originalAutoloadFileContent

// autoload.php @generated by helhum/class-alias-loader

require __DIR__ . '/composer/alias_loader_real.php';

return ClassAliasLoaderInit$suffix::getAliasLoader($composerClassLoaderInit);

EOF;

		file_put_contents($autoloadFile, $autoloadFileContent);

	}

	/**
	 * Rewrites the class map to have lowercased keys to be able to load classes with wrong casing
	 * Defaults to case sensitivity (composer loader default)
	 *
	 * @param RootPackageInterface $mainPackage
	 * @param string $targetDir
	 * @return bool
	 */
	static protected function caseSensitiveClassLoading(RootPackageInterface $mainPackage, $targetDir) {
		$extra = $mainPackage->getExtra();
		$caseSensitiveClassLoading = true;
		if (isset($extra['autoload-case-sensitivity'])) {
			$caseSensitiveClassLoading = (bool)$extra['autoload-case-sensitivity'];
		}
		if (!$caseSensitiveClassLoading) {
			$classMapContents = file_get_contents($targetDir . '/autoload_classmap.php');
			$classMapContents = preg_replace_callback(
				'/    \'[^\']*\' => /',
				function($match) {
					return strtolower($match[0]);
				},
				$classMapContents<commit_msg>[BUGFIX] Use require_once to require class file<commit_after><?php
namespace Helhum\ClassAliasLoader\Composer;

/*
 * This file is part of the class alias loader package.
 *
 * (c) <NAME> <<EMAIL>>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

use Composer\Package\RootPackageInterface;
use Composer\Util\Filesystem;

/**
 * Class ClassAliasLoader
 */
class ClassAliasGenerator {

	/**
	 * @param \Composer\Script\Event $event
	 * @param bool $calledByPlugin
	 * @return bool
	 * @throws \Exception
	 */
	static public function generateAliasMap(\Composer\Script\Event $event, $calledByPlugin = false) {
		if (!$calledByPlugin) {
			$event->getIO()->write('
<warning>Please remove the section "post-autoload-dump": "Helhum\\ClassAliasLoader\\Composer\\ClassAliasGenerator::generateAliasMap" from your composer.json! It is obsolete.</warning>
');
			return false;
		}
		$event->getIO()->write('<info>Generating class alias map files</info>');

		$composer = $event->getComposer();
		$config = $composer->getConfig();

		$filesystem = new Filesystem();
		$filesystem->ensureDirectoryExists($config->get('vendor-dir'));
		$basePath = $filesystem->normalizePath(realpath(getcwd()));
		$vendorPath = $filesystem->normalizePath(realpath($config->get('vendor-dir')));
		$targetDir = $vendorPath . '/composer';
		$filesystem->ensureDirectoryExists($targetDir);

		$mainPackage = $composer->getPackage();
		$autoLoadGenerator = $composer->getAutoloadGenerator();
		$localRepo = $composer->getRepositoryManager()->getLocalRepository();
		$packageMap = $autoLoadGenerator->buildPackageMap($composer->getInstallationManager(), $mainPackage, $localRepo->getCanonicalPackages());

		$caseSensitiveClassLoading = self::caseSensitiveClassLoading($mainPackage, $targetDir) ? 'true' : 'false';

		$aliasToClassNameMapping = array();
		$classNameToAliasMapping = array();
		$mappingFound = false;

		foreach ($packageMap as $item) {
			list($package, $installPath) = $item;
			$extra = $package->getExtra();
			if (!empty($extra['class-alias-maps'])) {
				if (!is_array($extra['class-alias-maps'])) {
					throw new \Exception('"class-alias-maps" must be an array');
				}
				foreach ($extra['class-alias-maps'] as $mapFile) {
					$mapFilePath = ($installPath ?: $basePath) . '/' . $filesystem->normalizePath($mapFile);
					if (is_file($mapFilePath)) {
						$packageAliasMap = require $mapFilePath;
						if (!is_array($packageAliasMap)) {
							throw new \Exception('"class alias maps" must return an array', 1422625075);
						}
						if (!empty($packageAliasMap)) {
							$mappingFound = true;
						}
						foreach ($packageAliasMap as $aliasClassName => $className) {
							$lowerCasedAliasClassName = strtolower($aliasClassName);
							$aliasToClassNameMapping[$lowerCasedAliasClassName] = $className;
							$classNameToAliasMapping[$className][$lowerCasedAliasClassName] = $lowerCasedAliasClassName;
						}
					}
				}
			}
		}

		if (!$mappingFound) {
			return false;
		}

		$exportArray = array(
			'aliasToClassNameMapping' => $aliasToClassNameMapping,
			'classNameToAliasMapping' => $classNameToAliasMapping
		);

		$fileContent = '<?php' . chr(10) . 'return ';
		$fileContent .= var_export($exportArray, true);
		$fileContent .= ';';

		file_put_contents($targetDir . '/autoload_classaliasmap.php', $fileContent);

		$suffix = NULL;
		if (!$config->get('autoloader-suffix') && is_readable($vendorPath . '/autoload.php')) {
			$content = file_get_contents($vendorPath.'/autoload.php');
			if (preg_match('{ComposerAutoloaderInit([^:\s]+)::}', $content, $match)) {
				$suffix = $match[1];
			}
		}

		if (!$suffix) {
			$suffix = $config->get('autoloader-suffix') ?: md5(uniqid('', true));
		}


		$aliasLoaderInitClassContent = <<<EOF
<?php

// alias_loader_real.php @generated by helhum/class-alias-loader

class ClassAliasLoaderInit$suffix {

	private static \$loader;

	static public function getAliasLoader(\$composerClassLoader) {
		if (null !== self::\$loader) {
			return self::\$loader;
		}

		\$aliasClassLoader = new Helhum\ClassAliasLoader\Composer\ClassAliasLoader(\$composerClassLoader);

		\$classAliasMap = require __DIR__ . '/autoload_classaliasmap.php';
		\$aliasClassLoader->setAliasMap(\$classAliasMap);
		\$aliasClassLoader->setCaseSensitiveClassLoading($caseSensitiveClassLoading);
		spl_autoload_register(array(\$aliasClassLoader, 'loadClassWithAlias'), true, true);
		\$composerClassLoader->unregister();

		self::\$loader = \$aliasClassLoader;

		return \$aliasClassLoader;

	}
}

EOF;

		file_put_contents($targetDir . '/alias_loader_real.php', $aliasLoaderInitClassContent);

		static::modifyMainAutoloadFile($vendorPath . '/autoload.php', $suffix);

		return true;
	}

	/**
	 * @param $autoloadFile
	 * @param string $suffix
	 */
	static protected function modifyMainAutoloadFile($autoloadFile, $suffix) {
		$originalAutoloadFileContent = file_get_contents($autoloadFile);
		preg_match('/return ComposerAutoloaderInit[^;]*;/', $originalAutoloadFileContent, $matches);
		$originalAutoloadFileContent = str_replace($matches[0], '', $originalAutoloadFileContent);
		$composerClassLoaderInit = str_replace(array('return ', ';'), '', $matches[0]);
		$autoloadFileContent = <<<EOF
$originalAutoloadFileContent

// autoload.php @generated by helhum/class-alias-loader

require_once __DIR__ . '/composer/alias_loader_real.php';

return ClassAliasLoaderInit$suffix::getAliasLoader($composerClassLoaderInit);

EOF;

		file_put_contents($autoloadFile, $autoloadFileContent);

	}

	/**
	 * Rewrites the class map to have lowercased keys to be able to load classes with wrong casing
	 * Defaults to case sensitivity (composer loader default)
	 *
	 * @param RootPackageInterface $mainPackage
	 * @param string $targetDir
	 * @return bool
	 */
	static protected function caseSensitiveClassLoading(RootPackageInterface $mainPackage, $targetDir) {
		$extra = $mainPackage->getExtra();
		$caseSensitiveClassLoading = true;
		if (isset($extra['autoload-case-sensitivity'])) {
			$caseSensitiveClassLoading = (bool)$extra['autoload-case-sensitivity'];
		}
		if (!$caseSensitiveClassLoading) {
			$classMapContents = file_get_contents($targetDir . '/autoload_classmap.php');
			$classMapContents = preg_replace_callback(
				'/    \'[^\']*\' => /',
				function($match) {
					return strtolower($match[0]);
				},
				$classMapContents
{'fraction_non_alphanumeric': 0.14961427569547261, 'fraction_numerical': 0.002649419465440661, 'mean_word_length': 5.0, 'pattern_counts': {'":': 2, '<': 35, '<?xml version=': 0, '>': 79, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2387202', 'n_tokens_mistral': 4474, 'n_tokens_neox': 3913, 'n_words': 729}