	/**
	 * The Config Class.
	 *
	 * @var   Config
	 * @since 3.2.0
	 */
	protected Config $config;

	/**
	 * The Registry Class.
	 *
	 * @var   Registry
	 * @since 3.2.0
	 */
	protected Registry $registry;

	/**
	 * The ListFieldClass Class.
	 *
	 * @var   ListFieldClass
	 * @since 3.2.0
	 */
	protected ListFieldClass $listfieldclass;

	/**
	 * The DoNotEscape Class.
	 *
	 * @var   DoNotEscape
	 * @since 3.2.0
	 */
	protected DoNotEscape $donotescape;

	/**
	 * The Placeholder Class.
	 *
	 * @var   Placeholder
	 * @since 3.2.0
	 */
	protected Placeholder $placeholder;

	/**
	 * The Customcode Class.
	 *
	 * @var   Customcode
	 * @since 3.2.0
	 */
	protected Customcode $customcode;

	/**
	 * The Language Class.
	 *
	 * @var   Language
	 * @since 3.2.0
	 */
	protected Language $language;

	/**
	 * The Groups Class.
	 *
	 * @var   FieldGroups
	 * @since 3.2.0
	 */
	protected FieldGroups $fieldgroups;

	/**
	 * Title Switch
	 *
	 * @var int
	 * @since 3.2.0
	 */
	private int $title;

	/**
	 * Alias Switch
	 *
	 * @var int
	 * @since 3.2.0
	 */
	private int $alias;

	/**
	 * Field Properties
	 *
	 * @var array
	 * @since 3.2.0
	 */
	private array $properties;

	/**
	 * PHP Tracking
	 *
	 * @var array
	 * @since 3.2.0
	 */
	private array $php;

	/**
	 * Field attributes
	 *
	 * @var array
	 * @since 3.2.0
	 */
	private array $attributes;

	/**
	 * Field custom switch
	 *
	 * @var bool
	 * @since 3.2.0
	 */
	private bool $custom;

	/**
	 * Field Custom Label
	 *
	 * @var string
	 * @since 3.2.0
	 */
	private string $customLabel;

	/**
	 * Field readonly switch
	 *
	 * @var bool
	 * @since 3.2.0
	 */
	private bool $readonly;

	/**
	 * Field View Type
	 *
	 * @var int
	 * @since 3.2.0
	 */
	private int $viewType;

	/**
	 * Field Name
	 *
	 * @var string
	 * @since 3.2.0
	 */
	private string $name;

	/**
	 * Field Type Name
	 *
	 * @var string
	 * @since 3.2.0
	 */
	private string $typeName;

	/**
	 * Field Multiple Switch
	 *
	 * @var bool
	 * @since 3.2.0
	 */
	private bool $multiple;

	/**
	 * Field Name Language Label
	 *
	 * @var string
	 * @since 3.2.0
	 */
	private string $langLabel;

	/**
	 * View Language String
	 *
	 * @var string
	 * @since 3.2.0
	 */
	private string $langView;

	/**
	 * View List Code
	 *
	 * @var string
	 * @since 3.2.0
	 */
	private string $nameListCode;

	/**
	 * View Single Code
	 *
	 * @var string
	 * @since 3.2.0
	 */
	private string $nameSingleCode;

	/**
	 * Field Placeholders
	 *
	 * @var array
	 * @since 3.2.0
	 */
	private array $placeholders;

	/**
	 * Repeatable Switch
	 *
	 * @var bool
	 * @since 3.2.0
	 */
	private bool $repeatable;

	/**
	 * Constructor.
	 *
	 * @param Config           $config           The Config Class.
	 * @param Registry         $registry         The Registry Class.
	 * @param ListFieldClass   $listfieldclass   The ListFieldClass Class.
	 * @param DoNotEscape      $donotescape      The DoNotEscape Class.
	 * @param Placeholder      $placeholder      The Placeholder Class.
	 * @param Customcode       $customcode       The Customcode Class.
	 * @param Language         $language         The Language Class.
	 * @param FieldGroups      $fieldgroups      The Groups Class.
	 *
	 * @since 3.2.0
	 */
	public function __construct(Config $config, Registry $registry, ListFieldClass $listfieldclass, DoNotEscape $donotescape, Placeholder $placeholder,
		Customcode $customcode, Language $language, FieldGroups $fieldgroups)
	{
		$this->config = $config;
		$this->registry = $registry;
		$this->listfieldclass = $listfieldclass;
		$this->donotescape = $donotescape;
		$this->placeholder = $placeholder;
		$this->customcode = $customcode;
		$this->language = $language;
		$this->fieldgroups = $fieldgroups;
	}

	/**
	 * set field attributes
	 *
	 * @param   array    $field           The field data
	 * @param   int      $viewType        The view type
	 * @param   string   $name            The field name
	 * @param   string   $typeName        The field type
	 * @param   bool     $multiple        The switch to set multiple selection option
	 * @param   string   $langLabel       The language string for field label
	 * @param   string   $langView        The language string of the view
	 * @param   string   $nameListCode    The list view name
	 * @param   string   $nameSingleCode  The single view name
	 * @param   array    $placeholders    The place holder and replace values
	 * @param   bool     $repeatable      The repeatable field switch
	 *
	 * @return  array The field attributes
	 * @since 3.2.0
	 */
	public function set(
		array $field, int $viewType, string $name, string $typeName,
		bool &$multiple, string &$langLabel, string $langView, string $nameListCode,
		string $nameSingleCode, array $placeholders, bool $repeatable = false
	): array
	{
		if (!$this->setSettings($field))
		{
			return [];
		}

		// initialise the empty attributes and other global values
		$this->initialise($viewType, $name, $typeName, $multiple, $langLabel,
			$langView, $nameListCode, $nameSingleCode, $placeholders, $repeatable);

		if (!$this->setProperties())
		{
			return $this->attributes;
		}

		// set the attributes
		$this->setAttributes();

		// update global ref passed value
		$multiple = $this->multiple;
		$langLabel = $this->langLabel;

		return $this->attributes;
	}

	/**
	 * set field settings
	 *
	 * @param   array    $field     The field data
	 *
	 * @return  bool true if settings was set
	 * @since 3.2.0
	 */
	private function setSettings(array $field): bool
	{
		if (isset($field['settings']))
		{
			$this->settings = $field['settings'];
			$this->alias = $field['alias'] ?? 0;
			$this->title = $field['title'] ?? 0;

			return true;
		}

		return false;
	}

	/**
	 * set field properties
	 *
	 * @return  bool true if settings was set
	 * @since 3.2.0
	 */
	private function setProperties(): bool
	{
		if (isset($this->settings->properties) && ArrayHelper::check($this->settings->properties))
		{
			$this->properties = $this->settings->properties;

			return true;
		}

		return false;
	}

	/**
	 * Set the attributes with properties
	 *
	 * @return  void
	 * @since 3.2.0
	 */
	private function setAttributes(): void
	{
		foreach ($this->properties as $property)
		{
			$name = $property['name'] ?? 'error';
			$example = $property['example'] ?? 'error';
			$translatable = $property['translatable'] ?? 0;
			$mandatory = $property['mandatory'] ?? 0;

			$this->setValue(
				$this->modelValue(
					$this->getValue($name),
					$name,
					(int) $translatable
				),
				$name,
				$example,
				(int) $mandatory
			);
		}

		$this->setPHP();

		$this->extraAttributes();
	}

	/**
	 * Set the extra attributes
	 *
	 * @return  void
	 * @since 3.2.0
	 */
	private function extraAttributes(): void
	{
		// do some nice twigs beyond the default
		if (isset($this->attributes['name']))
		{
			// check if we have class value for the list view of this field
			$listclass = GetHelper::between(
				$this->settings->xml, 'listclass="', '"'
			);
			if (StringHelper::check($listclass))
			{
				$this->listfieldclass->set($this->nameListCode . '.' . $this->attributes['name'], $listclass);
			}

			// check if we find reason to remove this field from being escaped
			$escaped = GetHelper::between(
				$this->settings->xml, 'escape="', '"'
			);
			if (StringHelper::check($escaped))
			{
				$this->donotescape->set($this->nameListCode . '.' .
					$this->attributes['name'], true);
			}

			// check if we have display switch for dynamic placement
			$display = GetHelper::between(
				$this->settings->xml, 'display="', '"'
			);
			if (StringHelper::check($display))
			{
				$this->attributes['display'] = $display;
			}

			// make sure validation is set if found (even it not part of field properties)
			if (!isset($this->attributes['validate']))
			{
				// check if we have validate (validation rule set)
				$validationRule = GetHelper::between(
					$this->settings->xml, 'validate="', '"'
				);
				if (StringHelper::check($validationRule))
				{
					$this->attributes['validate']
						= StringHelper::safe(
						$validationRule
					);
				}
			}

			// make sure ID is always readonly
			if ($this->attributes['name'] === 'id' && !$this->readonly)
			{
				$this->attributes['readonly'] = 'true';
			}
		}
	}

	/**
	 * Get XML value
	 *
	 * @param   string   $name   The property name
	 *
	 * @return  string|null   The property value
	 * @since 3.2.0
	 */
	private function getValue(string $name): ?string
	{
		if ($name === 'type')
		{
			return $this->getType();
		}

		if ($name === 'name')
		{
			return $this->getName();
		}

		if ($name === 'validate')
		{
			return $this->getValidation();
		}

		if (in_array($name, ['extension', 'directory', 'formsource']))
		{
			return $this->getXmlValue($name);
		}

		if (strpos((string) $name, 'type_php') !== false && $this->custom)
		{
			return $this->getTypePHP($name);
		}

		if ($name === 'prime_php' && $this->custom)
		{
			return $this->getPrimePHP($name);
		}

		if ($name === 'extends' && $this->custom)
		{
			return $this->getExtends();
		}

		if ($name === 'view' && $this->custom)
		{
			return $this->getView();
		}

		if ($name === 'views' && $this->custom)
		{
			return $this->getViews();
		}

		if ($name === 'component' && $this->custom)
		{
			return $this->getComponent();
		}

		if ($name === 'table' && $this->custom)
		{
			return $this->getTable();
		}

		if ($name === 'value_field' && $this->custom)
		{
			return $this->getValueField();
		}

		if ($name === 'key_field' && $this->custom)
		{
			return $this->getKeyField();
		}

		if ($name === 'button' && $this->repeatable && $this->custom)
		{
			return $this->removeButtonRepeatable();
		}

		if ($name === 'button' && $this->custom)
		{
			return $this->getButton();
		}

		if ($name === 'required' && 'repeatable' === $this->typeName)
		{
			return $this->removeRequired();
		}

		if ($this->viewType == 2 && in_array($name, ['readonly', 'disabled']))
		{
			return $this->setReadonly($name);
		}

		if ($name === 'multiple')
		{
			return $this->getMultiple($name);
		}

		if ($name === 'class' && in_array($this->typeName, ['note', 'spacer']))
		{
			return $this->getClass();
		}

		// Default action if no condition is met
		return $this->getXmlValue($name);
	}

	/**
	 * Model the found value
	 *
	 * @param   string|null   $value          The property value
	 * @param   string        $name           The property name
	 * @param   int           $translatable   Switch to set translation
	 *
	 * @return  string|null   The property value
	 * @since 3.2.0
	 */
	private function modelValue(?string $value, string $name, int $translatable): ?string
	{
		// check if translatable
		if ($value !== null && StringHelper::check($value)
			&& $translatable == 1)
		{
			// update label if field use multiple times
			if ($name === 'label')
			{
				if (isset($this->attributes['name'])
					&& $this->registry->get("unique.names." . $this->nameListCode . ".names." . $this->attributes['name']) !== null)
				{
					$value .= ' ('
						. StringHelper::safe(
							$this->registry->get("unique.names." . $this->nameListCode . ".names." . $this->attributes['name'])
						) . ')';
				}
			}

			// replace placeholders
			$value = $this->placeholder->update(
				$value, $this->placeholders
			);

			// insure custom labels don't get messed up
			if ($this->custom)
			{
				$this->customLabel = $value;
			}

			// set lang key
			$lang_value = $this->langView . '_'
				. FieldHelper::safe(
					$this->name . ' ' . $name, true
				);

			// add to lang array
			$this->language->set($this->config->lang_target, $lang_value, $value);

			// use lang value
			$value = $lang_value;
		}
		elseif ($this->alias && $translatable == 1)
		{
			if ($name === 'label')
			{
				$value = 'JFIELD_ALIAS_LABEL';
			}
			elseif ($name === 'description')
			{
				$value = 'JFIELD_ALIAS_DESC';
			}
			elseif ($name === 'hint')
			{
				$value = 'JFIELD_ALIAS_PLACEHOLDER';
			}
		}
		elseif ($this->title && $translatable == 1)
		{
			if ($name === 'label')
			{
				$value = 'JGLOBAL_TITLE';
			}
		}

		return $value;
	}

	/**
	 * set the found value
	 *
	 * @param   string|null   $value          The property value
	 * @param   string        $name           The property name
	 * @param   string        $example        The example value
	 * @param   int           $mandatory      The mandatory switch
	 *
	 * @return  void
	 * @since 3.2.0
	 */
	private function setValue(?string $value, string $name, string $example, int $mandatory): void
	{
		// only load value if found or is mandatory
		if (($value !== null && StringHelper::check($value))
			|| ($mandatory == 1 && !$this->custom))
		{
			// make sure mandatory fields are added
			if ($value === null || !StringHelper::check($value))
			{
				$value = $example;
			}

			// load to langBuilder down the line
			if ($name === 'label')
			{
				if ($this->custom)
				{
					$this->attributes['custom']['label'] = $this->customLabel ?? 'error';
				}

				$this->langLabel = $value;
			}

			// now set the value
			$this->attributes[$name] = $value;
		}
		// validate that the default field is set
		elseif ($name === 'default'
			&& ($xmlValidateValue = GetHelper::between(
				$this->settings->xml, 'default="', '"', 'none-set'
			)) !== 'none-set')
		{
			// we must allow empty defaults
			$this->attributes['default'] = $value;
		}
	}

	/**
	 * Set PHP if needed
	 *
	 * @return  void
	 * @since 3.2.0
	 */
	private function setPHP(): void
	{
		// check if all php is loaded using the tracker
		if (ArrayHelper::check($this->php))
		{
			// little search validation
			$confirmation = '8qvZHoyuFYQqpj0YQbc6F3o5DhBlmS-_-a8pmCZfOVSfANjkmV5LG8pCdAY2JNYu6cB';
			foreach ($this->php as $search_key => $php_key)
			{
				// we must search for more code in the xml just encase
				foreach (range(2, 30) as $php_line)
				{
					$get_ = $search_key . '_' . $php_line;
					if (!isset($this->attributes['custom'][$php_key][$php_line])
						&& ($value = UtilitiesFieldHelper::getValue(
							$this->settings->xml, $get_, $confirmation
						)) !== $confirmation)
					{
						$this->attributes['custom'][$php_key][$php_line]
							= $this->customcode->update(
							Base64Helper::open($value)
						);
					}
				}
			}
		}
	}

	/**
	 * get an xml value (default)
	 *
	 * @param   string   $name   The property name
	 *
	 * @return  string|null
	 * @since 3.2.0
	 */
	private function getXmlValue(string $name): ?string
	{
		// get value & replace the placeholders
		return $this->placeholder->update(
			GetHelper::between(
				$this->settings->xml, $name . '="', '"'
			), $this->placeholders
		);
	}

	/**
	 * get type value
	 *
	 * @return  string
	 * @since 3.2.0
	 */
	private function getType(): string
	{
		// add to custom if it is custom
		if ($this->custom)
		{
			// set the type just to make sure.
			$this->attributes['custom']['type'] = $this->typeName;
		}

		return $this->typeName;
	}

	/**
	 * get name value
	 *
	 * @return  string
	 * @since 3.2.0
	 */
	private function getName(): string
	{
		// get the actual field name
		return $this->placeholder->update($this->name, $this->placeholders);
	}

	/**
	 * get validation value
	 *
	 * @return  string|null
	 * @since 3.2.0
	 */
	private function getValidation(): ?string
	{
		// check if we have validate (validation rule set)
		$value = GetHelper::between(
			$this->settings->xml, 'validate="', '"'
		);

		if (StringHelper::check($value))
		{
			$value = StringHelper::safe(
				$value
			);
		}

		return $value;
	}

	/**
	 * get type PHP code
	 *
	 * @param   string   $name   The property name
	 *
	 * @return  string|null
	 * @since 3.2.0
	 */
	private function getTypePHP(string $name): ?string
	{
		// set the line number
		$line = (int) preg_replace(
			'/[^0-9]/', '', (string) $name
		);

		// set the type key
		$key = (string) trim(
			str_replace(
				'type_', '',
				preg_replace('/[0-9]+/', '', (string) $name)
			), '_'
		);

		// load the php for the custom field file
		$this->attributes['custom'][$key][$line]
			=  $this->customcode->update(
			Base64Helper::open(
				GetHelper::between(
					$this->settings->xml,
					$name . '="', '"'
				)
			)
		);

		// load tracker
		$this->php['type_' . $key] = $key;

		return null;
	}

	/**
	 * get prime PHP code
	 *
	 * @param   string   $name   The property name
	 *
	 * @return  string|null
	 * @since 3.2.0
	 */
	private function getPrimePHP(string $name): ?string
	{
		// load the php for the custom field file
		$this->attributes['custom']['prime_php']
			= (int) GetHelper::between(
			$this->settings->xml, $name . '="', '"'
		);

		return null;
	}

	/**
	 * get extends value
	 *
	 * @return  string|null
	 * @since 3.2.0
	 */
	private function getExtends(): ?string
	{
		// load the class that is being extended
		$this->attributes['custom']['extends']
			= GetHelper::between(
			$this->settings->xml, 'extends="', '"'
		);

		return null;
	}

	/**
	 * get view value
	 *
	 * @return  string|null
	 * @since 3.2.0
	 */
	private function getView(): ?string
	{
		// load the view name & replace the placeholders
		$this->attributes['custom']['view']
			= StringHelper::safe(
			$this->placeholder->update(
				GetHelper::between(
					$this->settings->xml, 'view="', '"'
				), $this->placeholders
			)
		);

		return null;
	}

	/**
	 * get views value
	 *
	 * @return  string|null
	 * @since 3.2.0
	 */
	private function getViews(): ?string
	{
		// load the views name & replace the placeholders
		$this->attributes['custom']['views']
			= StringHelper::safe(
			$this->placeholder->update(
				GetHelper::between(
					$this->settings->xml, 'views="', '"'
				), $this->placeholders
			)
		);

		return null;
	}

	/**
	 * get component value
	 *
	 * @return  string|null
	 * @since 3.2.0
	 */
	private function getComponent(): ?string
	{
		// load the component name & replace the placeholders
		$this->attributes['custom']['component']
			= $this->placeholder->update(
			GetHelper::between(
				$this->settings->xml, 'component="', '"'
			), $this->placeholders
		);

		return null;
	}

	/**
	 * get table value
	 *
	 * @return  string|null
	 * @since 3.2.0
	 */
	private function getTable(): ?string
	{
		// load the main table that is queried & replace the placeholders
		$this->attributes['custom']['table']
			= $this->placeholder->update(
			GetHelper::between(
				$this->settings->xml, 'table="', '"'
			), $this->placeholders
		);

		return null;
	}

	/**
	 * get value field
	 *
	 * @return  string|null
	 * @since 3.2.0
	 */
	private function getValueField(): ?string
	{
		// load the text key
		$this->attributes['custom']['text']
			= StringHelper::safe(
			GetHelper::between(
				$this->settings->xml, 'value_field="', '"'
			)
		);

		return null;
	}

	/**
	 * get key field value
	 *
	 * @return  string|null
	 * @since 3.2.0
	 */
	private function getKeyField(): ?string
	{
		// load the id key
		$this->attributes['custom']['id']
			= StringHelper::safe(
			GetHelper::between(
				$this->settings->xml, 'key_field="', '"'
			)
		);

		return null;
	}

	/**
	 * remove the button on repeatable
	 *
	 * @return  string
	 * @since 3.2.0
	 */
	private function removeButtonRepeatable(): string
	{
		// do not add button
		$this->attributes['custom']['add_button'] = 'false';

		// don't load the button to repeatable
		return 'false';
	}

	/**
	 * get button value
	 *
	 * @return  string|null
	 * @since 3.2.0
	 */
	private function getButton(): ?string
	{
		// load the button string value if found
		$value = (string) StringHelper::safe(
			GetHelper::between(
				$this->settings->xml, 'button="', '"'
			)
		);

		// add to custom values
		$this->attributes['custom']['add_button']
			= (StringHelper::check($value)
			|| 1 == $value) ? $value : 'false';

		return $value;
	}

	/**
	 * remove the required value
	 *
	 * @return  string
	 * @since 3.2.0
	 */
	private function removeRequired(): string
	{
		// don't load the required to repeatable field type
		return 'false';
	}

	/**
	 * set the readonly switch
	 *
	 * @param   string   $name   The property name
	 *
	 * @return  string
	 * @since 3.2.0
	 */
	private function setReadonly(string $name): string
	{
		// trip the switch for readonly
		if ($name === 'readonly')
		{
			$this->readonly = true;
		}

		// set read only
		return 'true';
	}

	/**
	 * set the multiple switch
	 *
	 * @param   string   $name   The property name
	 *
	 * @return  string
	 * @since 3.2.0
	 */
	private function getMultiple(string $name): string
	{
		$value = (string) GetHelper::between(
			$this->settings->xml, $name . '="', '"'
		);

		// add the multiple
		if ('true' === $value)
		{
			$this->multiple = true;
		}

		return $value;
	}

	/**
	 * get class value
	 *
	 * @return  string
	 * @since 3.2.0
	 */
	private function getClass(): string
	{
		$value = GetHelper::between(
			$this->settings->xml, 'class="', '"'
		);

		// add the type class
		if (StringHelper::check($value))
		{
			if (strpos($value, $this->name) === false)
			{
				$value = $value . ' ' . $this->name;
			}

			return $value;
		}

		return $this->name;
	}

	/**
	 * Initialise the attributes and other global values
	 *
	 * @param   int      $viewType        The view type
	 * @param   string   $name            The field name
	 * @param   string   $typeName        The field type
	 * @param   bool     $multiple        The switch to set multiple selection option
	 * @param   string   $langLabel       The language string for field label
	 * @param   string   $langView        The language string of the view
	 * @param   string   $nameListCode    The list view name
	 * @param   string   $nameSingleCode  The single view name
	 * @param   array    $placeholders    The place holder and replace values
	 * @param   bool     $repeatable      The repeatable field switch
	 *
	 * @return  void
	 * @since 3.2.0
	 */
	private function initialise(int $viewType, string $name, string $typeName,
		bool $multiple, string $langLabel, string $langView, string $nameListCode,
		string $nameSingleCode, array $placeholders, bool $repeatable): void
	{
		$this->attributes     = [];
		$this->php            = [];
		$this->custom         = false;
		$this->readonly       = false;
		$this->viewType       = $viewType;
		$this->name           = $name;
		$this->typeName       = $typeName;
		$this->multiple       = $multiple;
		$this->langLabel      = $langLabel;
		$this->langView       = $langView;
		$this->nameListCode   = $nameListCode;
		$this->nameSingleCode = $nameSingleCode;
		$this->placeholders   = $placeholders;
		$this->repeatable     = $repeatable;

		// setup Joomla default fields
		if (!$this->fieldgroups->check($typeName))
		{
			$this->attributes['custom'] = [];

			// is this an own custom field
			if (isset($this->settings->own_custom))
			{
				$this->attributes['custom']['own_custom'] 
					= $this->settings->own_custom;
			}
			$this->custom = true;
		}
	}