	/**
	 * Compiler Component Joomla Version Settings
	 *
	 * @var    Settings
	 * @since 3.2.0
	 */
	protected Settings $settings;

	/**
	 * Compiler Utilities Paths
	 *
	 * @var    Paths
	 * @since 3.2.0
	 */
	protected Paths $paths;

	/**
	 * Compiler Counter
	 *
	 * @var    Counter
	 * @since 3.2.0
	 */
	protected Counter $counter;

	/**
	 * Compiler Utilities File
	 *
	 * @var    File
	 * @since 3.2.0
	 */
	protected File $file;

	/**
	 * Compiler Utilities Files
	 *
	 * @var    Files
	 * @since 3.2.0
	 */
	protected Files $files;

	/**
	 * Database object to query local DB
	 *
	 * @var    CMSApplication
	 * @since 3.2.0
	 **/
	protected CMSApplication $app;

	/**
	 * Constructor.
	 *
	 * @param Settings|null         $settings    The compiler component joomla version settings object.
	 * @param Paths|null            $paths       The compiler paths object.
	 * @param Counter|null          $counter     The compiler counter object.
	 * @param File|null             $file        The compiler file object.
	 * @param Files|null            $files       The compiler files object.
	 * @param CMSApplication|null   $app         The CMS Application object.
	 *
	 * @since 3.2.0
	 * @throws \Exception
	 */
	public function __construct(?Settings $settings = null, ?Paths $paths = null,
		?Counter $counter = null, ?File $file = null, ?Files $files = null,
		?CMSApplication $app = null)
	{
		$this->settings = $settings ?: Compiler::_('Component.Settings');
		$this->paths = $paths ?: Compiler::_('Utilities.Paths');
		$this->counter = $counter ?: Compiler::_('Utilities.Counter');
		$this->file = $file ?: Compiler::_('Utilities.File');
		$this->files = $files ?: Compiler::_('Utilities.Files');
		$this->app = $app ?: Factory::getApplication();
	}

	/**
	 * Build Structural Needed Files & Folders
	 *
	 * @param   array        $target    The main target and name
	 * @param   string       $type      The type in the target
	 * @param   string|null  $fileName  The custom file name
	 * @param   array|null   $config    To add more data to the files info
	 *
	 * @return  bool  true on success
	 * @since 3.2.0
	 */
	public function build(array $target, string $type,
		?string $fileName = null, ?array $config = null): bool
	{
		// did we build the files (any number)
		$build_status = false;

		// check that we have the target values
		if (ArrayHelper::check($target))
		{
			// search the target
			foreach ($target as $main => $name)
			{
				// make sure it is lower case
				$name = StringHelper::safe($name);

				// setup the files
				foreach ($this->settings->multiple()->{$main} as $item => $details)
				{
					if ($details->type === $type)
					{
						$file_details = $this->getFileDetails(
							$details,
							(string) $item,
							$name,
							$fileName,
							$config
						);

						if (is_array($file_details))
						{
							// store the new files
							$this->files->appendArray('dynamic.' . $file_details['view'],
								$file_details);

							// we have build at least one
							$build_status = true;
						}
					}
				}
			}
		}

		return $build_status;
	}

	/**
	 * Get the details
	 *
	 * @param   object       $details   The item details
	 * @param   string       $item      The item name
	 * @param   string       $name      The given name
	 * @param   string|null  $fileName  The custom file name
	 * @param   array|null   $config    To add more data to the files info
	 *
	 * @return  array|null  The details
	 * @since 3.2.0
	 */
	private function getFileDetails(object $details, string $item,
		string $name, ?string $fileName = null, ?array $config = null): ?array
	{
		$zip_path = '';
		if (($path = $this->getPath($details, $zip_path, $name)) === null)
		{
			return null;
		}

		// setup the folder
		if (!Folder::exists($path))
		{
			Folder::create($path);
			$this->file->html($zip_path);

			// count the folder created
			$this->counter->folder++;
		}

		$new_name = $this->getNewName($details, $item, $name, $fileName);

		if (!JoomlaFile::exists($path . '/' . $new_name))
		{
			// move the file to its place
			JoomlaFile::copy(
				$this->paths->template_path . '/' . $item,
				$path . '/' . $new_name
			);

			// count the file created
			$this->counter->file++;
		}

		// we can't have dots in a view name
		if (strpos($name, '.') !== false)
		{
			$name = preg_replace('/[\.]+/', '_', (string) $name);
		}

		// setup array for new file
		$file = [
			'path' => $path . '/' . $new_name,
			'name' => $new_name,
			'view' => $name,
			'zip'  => $zip_path . '/' . $new_name
		];

		if (ArrayHelper::check($config))
		{
			$file['config'] = $config;
		}

		return $file;
	}

	/**
	 * Get the path
	 *
	 * @param   object     $details   The item details
	 * @param   string     $zipPath   The zip path
	 * @param   string     $name      The name
	 *
	 * @return  string|null  The path
	 * @since 3.2.0
	 */
	private function getPath(object $details, string &$zipPath, string $name): ?string
	{
		// set destination path
		if (strpos((string) $details->path, 'VIEW') !== false)
		{
			$path = str_replace('VIEW', $name, (string) $details->path);
		}
		else
		{
			$path = $details->path;
		}

		// make sure we have component to replace
		if (strpos((string) $path, 'c0mp0n3nt') !== false)
		{
			$zipPath = str_replace('c0mp0n3nt/', '', (string) $path);

			return str_replace(
				'c0mp0n3nt/', $this->paths->component_path . '/', (string) $path
			);
		}

		$this->app->enqueueMessage(
			Text::sprintf('<hr /><h3>c0mp0n3nt issue found</h3><p>The path (%s) could not be used.</p>',
				$path
			), 'Error'
		);

		return null;
	}

	/**
	 * Get the new name
	 *
	 * @param   object       $details   The item details
	 * @param   string       $item      The item name
	 * @param   string       $name      The name
	 * @param   string|null  $fileName  The custom file name
	 *
	 * @return  string      The new name
	 * @since 3.2.0
	 */
	private function getNewName(object $details, string $item,
		string &$name, ?string $fileName = null): string
	{
		// do the file need renaming
		if ($details->rename)
		{
			if (!empty($fileName))
			{
				$name = $name . '_' . $fileName;

				return str_replace(
					$details->rename, $fileName, $item
				);
			}
			elseif ($details->rename === 'new')
			{
				return $details->newName;
			}

			return str_replace(
				$details->rename, $name, $item
			);
		}

		return $item;
	}
