<?php

namespace IMATHUZH\Qfq\Core\Form\FormElement;

use IMATHUZH\Qfq\Core\Form\Form;
use IMATHUZH\Qfq\Core\Helper\Sanitize;
use IMATHUZH\Qfq\Core\Helper\Support;

class DatetimeFormElement extends AbstractFormElement {
    public ?array $format;

    /**
     * @param $attributes
     * @param Form|null $form
     * @throws \CodeException
     * @throws \DbException
     * @throws \DownloadException
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     * @throws \Twig\Error\LoaderError
     * @throws \Twig\Error\RuntimeError
     * @throws \Twig\Error\SyntaxError
     * @throws \UserFormException
     * @throws \UserReportException
     */
    public function __construct($attributes, ?Form $form = null) {
        parent::__construct($attributes, $form);


        $this->handleCssClasses();
        $this->handleCheckType();
        $this->format = $this->getDefaultDateFormat();
        $this->handleFormat();
        $this->handleValue();
        $this->handleDaysOfWeekEnabled();
        $this->handleClearMe();
        $this->handlePlaceholder();
        $this->handlePattern();
        $this->handleMinMax();
        $this->handleHtmlAttributes();
    }


    /**
     * Adds required css classes to $this->cssClasses
     * Classes depend on the type of datepicker and on form multi/non-multi
     *
     * @return void
     */
    private function handleCssClasses(): void {
        array_push($this->cssClasses, 'form-control');
        if ($this->attributes[FE_DATE_TIME_PICKER_TYPE] === DATE_TIME_PICKER_QFQ) {
            array_push($this->cssClasses, 'qfq-datepicker');
        } elseif (isset($this->attributes[F_FE_INPUT_CLEAR_ME]) && $this->attributes[F_FE_INPUT_CLEAR_ME] != '0' && $this->attributes[FE_DATE_TIME_PICKER_TYPE] === DATE_TIME_PICKER_NO) {
            if (($this->form->specFinal[F_MULTI_MODE] ?? '') == F_MULTI_MODE_VERTICAL) {
                array_push($this->cssClasses, 'qfq-clear-me-multiform');
            } else {
                array_push($this->cssClasses, 'qfq-clear-me');
            }
        }
    }


    /**
     * @return array Returns an array that describes the default format for the used type (datetime / date / time)
     */
    private function getDefaultDateFormat(): array {
        $defaultDateFormat = explode(' ', $this->attributes[FE_DATE_FORMAT], 2);
        $defaultFormat = array();
        if (isset($defaultDateFormat[1])) {
            $defaultFormat['time'] = $defaultDateFormat[1];
            $defaultFormat['date'] = $defaultDateFormat[0];
            $defaultFormat['timeParts'] = explode(':', $defaultFormat['time'], 3);
        } else {
            $defaultFormat['time'] = '';
            $defaultFormat['date'] = $this->attributes[FE_DATE_FORMAT];
            $defaultFormat['timeParts'] = explode(':', $this->attributes[FE_DATE_FORMAT], 3);
        }

        if ($defaultFormat['timeParts'][2] ?? '' === 'ss') {
            $this->attributes[FE_SHOW_SECONDS] = 1;
        }
        return $defaultFormat;
    }


    /**
     * Modifies and returns the default format for a QFQ timepicker
     *
     * @return void
     */
    private function useDateTimeFormatQfq(): void {
        switch ($this->format['date']) {
            case FORMAT_DATE_INTERNATIONAL:
            case FORMAT_DATE_INTERNATIONAL_QFQ:
            case FORMAT_DATE_GERMAN:
            case FORMAT_DATE_GERMAN_QFQ:
                if ($this->attributes[FE_TYPE] == FE_TYPE_DATETIME) {
                    $this->format['date'] = strtoupper($this->format['date']);
                    if (empty($this->format['time'])) {
                        $this->format['time'] = 'HH:mm';
                    }
                    $this->format['date'] .= ' ' . $this->format['time'];
                } else {
                    $this->format['date'] = strtoupper($this->format['date']);
                }
                break;
        }
    }


    /**
     * Formats the time part of $this->format to work with different configurations
     *
     * @return void
     */
    private function setTimeFormat(): void {
        if ($this->format['timeParts'][0] === 'HH' || $this->format['timeParts'][0] === 'hh') {
            $this->format['date'] = $this->format['timeParts'][0] . ':' . $this->format['timeParts'][1];
        } else if ($this->attributes[FE_DATE_TIME_PICKER_TYPE] === DATE_TIME_PICKER_QFQ) {
            $this->format['date'] = 'HH:mm';
        } else {
            $this->format['date'] = 'hh:mm';
        }

        if ($this->attributes[FE_SHOW_SECONDS] == 1) {
            $this->format['date'] .= ':ss';
        }
    }


    /**
     * @return void
     */
    /**
     * Formatiert $this->value für den Browser-Picker.
     * Rundet bei fehlendem Tag (z.B. nur Monat/Jahr) auf den letzten Tag des Monats.
     */
    private function formatValueForBrowser(): void {
        // 1) Ursprüngliches Datum parsen
        $date = date_create($this->value);
        $fmt = $this->attributes[FE_DATE_FORMAT] ?? '';

        // 2) Wenn im Pattern kein Tag ('dd') vorkommt, zum Monatsletzten springen
        if (strpos($fmt, 'dd') === false) {
            $year = (int)date_format($date, 'Y');
            $month = (int)date_format($date, 'm');
            $lastDay = cal_days_in_month(CAL_GREGORIAN, $month, $year);
            // neues Datum auf den letzten Tag des Monats setzen
            $date = date_create(sprintf('%04d-%02d-%02d', $year, $month, $lastDay));
        }

        // 3) Je nach FE_TYPE das Format setzen
        if ($this->attributes[FE_TYPE] === FE_TYPE_DATE) {
            // Nur Datum
            $this->value = date_format($date, "Y-m-d");
        } elseif ($this->attributes[FE_TYPE] === FE_TYPE_DATETIME) {
            // Datum + Zeit
            $this->value = date_format($date, "Y-m-d H:i");
        }
    }


    /**
     * Returns datetime browser type
     *
     * @return string
     */
    private function getDateTimeBrowserType(): string {
        if ($this->attributes[FE_TYPE] == FE_TYPE_DATE) return 'date';
        if ($this->attributes[FE_TYPE] == FE_TYPE_TIME) return 'time';
        return 'datetime-local';
    }


    /**
     * @return bool|string
     */
    private function getDateTimePickerDisabledDays(): bool|string {
        $enabledDays = $this->attributes[FE_DATE_DAYS_OF_WEEK_ENABLED];
        // convert enabled days from datetimepicker user input daysOfWeekEnabled to disabled days
        $enabledDays = explode(',', $enabledDays);
        $disabledDays = '';

        for ($i = 0; $i <= 6; $i++) {
            $flagDayPoint = false;
            foreach ($enabledDays as $day) {
                if ($day == $i) {
                    $flagDayPoint = true;
                }
            }
            if (!$flagDayPoint) {
                $disabledDays .= $i . ',';
            }
        }

        // if last char ',' exists, remove it
        $lastChar = substr($disabledDays, -1);
        if ($lastChar == ',') {
            $disabledDays = substr($disabledDays, 0, -1);
        }
        return $disabledDays;
    }


    /**
     * Fill $this->htmlAttributes
     *
     * @return void
     */
    private function handleHtmlAttributes(): void {
        Support::setIfNotSet($this->attributes, F_FE_DATA_MATCH_ERROR);
        Support::setIfNotSet($this->attributes, F_FE_DATA_ERROR);

        // Set some normal htmlAttributes
        $this->htmlAttributes[ATTRIBUTE_DATA_REFERENCE] = $this->attributes[FE_DATA_REFERENCE];
        $this->htmlAttributes[FE_SIZE] = $this->attributes[FE_SIZE];
        $this->htmlAttributes[FE_MAX_LENGTH] = $this->attributes[FE_MAX_LENGTH];
        $this->htmlAttributes[FE_VALUE] = htmlentities($this->value);
        $this->htmlAttributes[F_FE_DATA_PATTERN_ERROR] = $this->attributes[F_FE_DATA_PATTERN_ERROR];
        $this->htmlAttributes[F_FE_DATA_REQUIRED_ERROR] = $this->attributes[F_FE_DATA_REQUIRED_ERROR];
        $this->htmlAttributes[F_FE_DATA_MATCH_ERROR] = $this->attributes[F_FE_DATA_MATCH_ERROR];
        $this->htmlAttributes[F_FE_DATA_ERROR] = $this->attributes[F_FE_DATA_ERROR];
        $this->htmlAttributes[FE_INPUT_AUTOCOMPLETE] = $this->attributes[FE_INPUT_AUTOCOMPLETE] ?? '';
        $this->htmlAttributes[FE_AUTOFOCUS] = $this->attributes[FE_AUTOFOCUS] ?? '';
        $this->htmlAttributes[FE_PLACEHOLDER] = $this->attributes[FE_PLACEHOLDER];
        if ($this->attributes[FE_DYNAMIC_UPDATE] === 'yes') $this->htmlAttributes[FE_DATA_LOAD] = FE_DATA_LOAD;
        $this->htmlAttributes['title'] = $this->attributes[FE_TOOLTIP];
        $this->htmlAttributes[FE_MIN] = $this->attributes[FE_MIN];
        $this->htmlAttributes[FE_MAX] = $this->attributes[FE_MAX];
        $this->htmlAttributes[FE_CHECK_PATTERN] = $this->attributes[FE_CHECK_PATTERN];


        // Set input type
        if ($this->attributes[FE_DATE_TIME_PICKER_TYPE] === DATE_TIME_PICKER_BROWSER) {
            $type = $this->getDateTimeBrowserType();
        } else {
            // date|time|datetime|datetime-local are not appropriate - only I18n representation possible.
            $type = 'text';
        }
        $this->htmlAttributes['type'] = $type;


        // Set 'data-..' htmlAttributes
        $dateTimeKeys = array(
            FE_DATE_LOCALE,
            FE_DATE_DAYS_OF_WEEK_ENABLED,
            FE_DATE_FORMAT,
            FE_DATE_VIEWMODE_DEFAULT,
            F_FE_INPUT_CLEAR_ME,
            FE_DATE_SHOW_CALENDAR_WEEKS,
            FE_DATE_CURRENT_DATETIME,
            FE_DATE_DATETIME_SIDE_SIDE_BY_SIDE,
            FE_MIN,
            FE_MAX
        );

        $dateTimeAttributes = array(
            "locale",
            "days-of-week-disabled",
            "format",
            "view-mode-default",
            "show-clear-button",
            "show-calendar-weeks",
            "use-current-datetime",
            "datetime-side-by-side",
            "minDate",
            "maxDate"
        );

        $keyCount = 0;
        foreach ($dateTimeKeys as $key) {
            if (isset($this->attributes[$key]) && $this->attributes[$key] != "" && $key != FE_DATE_FORMAT) {
                $this->htmlAttributes['data-' . $dateTimeAttributes[$keyCount]] = $this->attributes[$key];
            } elseif ($key == FE_DATE_FORMAT) {
                $this->htmlAttributes['data-' . $dateTimeAttributes[$keyCount]] = $this->format['date'];
            }
            $keyCount++;
        }
    }


    /**
     * Set FE_MIN and FE_MAX for a date/time FE that is not of type QFQ
     *
     * @return void
     */
    private function handleMinMax(): void {
        // For other dateTimePicker than qfq, min/max values need to be converted
        if ($this->attributes[FE_DATE_TIME_PICKER_TYPE] === DATE_TIME_PICKER_QFQ) return;

        if ($this->attributes[FE_TYPE] == FE_TYPE_DATE) {
            $dateMinMaxFormat = "Y-m-d";
        } else {
            $dateMinMaxFormat = "Y-m-d H:i";
        }

        if (isset($this->attributes[FE_MIN]) && $this->attributes[FE_MIN] !== '') {
            $dateMin = date_create($this->attributes[FE_MIN]);
            $this->attributes[FE_MIN] = date_format($dateMin, $dateMinMaxFormat);
        }

        if (isset($this->attributes[FE_MAX]) && $this->attributes[FE_MAX] !== '') {
            $dateMax = date_create($this->attributes[FE_MAX]);
            $this->attributes[FE_MAX] = date_format($dateMax, $dateMinMaxFormat);
        }
    }


    /**
     * Sets / Sanitizes $this->attributes[FE_CHECK_TYPE] and $this->attributes[FE_CHECK_PATTERN]
     *
     * @return void
     * @throws \UserFormException
     */
    private function handleCheckType(): void {
        $tmpPattern = $this->attributes[FE_CHECK_PATTERN];
        //  If bootstrap datetimepicker (date and datetime FE Type) is used, check pattern is not needed. Keep pattern for FE Type time.
        // pgroeb: This does not make sense: type should be datetime, date or time, but these are all excluded in the following IF
        if ($this->attributes[FE_TYPE] != FE_TYPE_DATETIME && $this->attributes[FE_TYPE] != FE_TYPE_DATE && $this->attributes[FE_TYPE] != FE_TYPE_TIME) {
            $this->attributes[FE_CHECK_PATTERN] = Support::dateTimeRegexp($this->attributes[FE_TYPE], $this->attributes[FE_DATE_FORMAT], $this->attributes[FE_TIME_IS_OPTIONAL]);
        }

        switch ($this->attributes[FE_CHECK_TYPE]) {
            case  SANITIZE_ALLOW_PATTERN:
                $this->attributes[FE_CHECK_PATTERN] = $tmpPattern;
                break;
            case SANITIZE_ALLOW_ALL:
            case SANITIZE_ALLOW_ALNUMX:
            case SANITIZE_ALLOW_ALLBUT:
                $this->attributes[FE_CHECK_TYPE] = SANITIZE_ALLOW_PATTERN;
                break;
            default:
                throw new \UserFormException("Checktype not applicable for date/time: '" . $this->attributes[FE_CHECK_TYPE] . "'", ERROR_NOT_APPLICABLE);
        }
    }


    /**
     * Sets $this->value to work with the current configuration of the FE
     *
     * @return void
     * @throws \CodeException
     * @throws \UserFormException
     */
    private function handleValue(): void {
        $showTime = ($this->attributes[FE_TYPE] == FE_TYPE_TIME || $this->attributes[FE_TYPE] == FE_TYPE_DATETIME) ? 1 : 0;
        if ($this->value == 'CURRENT_TIMESTAMP' || $this->value == 'current_timestamp()') {
            $this->value = date('Y-m-d H:i:s');
        }

        $this->convertQfqLowerToStdDateFmtUpper($this->attributes, $this->format);
        $this->value = Support::convertDateTime($this->value, $this->attributes[FE_DATE_FORMAT], $this->attributes[FE_SHOW_ZERO], $showTime, $this->attributes[FE_SHOW_SECONDS]);
        if ($this->attributes[FE_TYPE] !== FE_TYPE_TIME) {
            $this->value = $this->formatValueByTypeDate($this->value, $this->format[FE_TYPE_DATE]);
        }

        // Browser needs own formatted value to show date
        if ($this->attributes[FE_DATE_TIME_PICKER_TYPE] === DATE_TIME_PICKER_BROWSER && $this->value !== '') {
            $this->formatValueForBrowser();
        }

        $tableColumnTypes = $this->store->getStore(STORE_TABLE_COLUMN_TYPES);
        // truncate if necessary
        if ($this->value != '' && $this->attributes[FE_MAX_LENGTH] > 0) {
            if (!is_array($this->value) && $this->attributes[FE_TYPE] === FE_TYPE_TIME && ($tableColumnTypes[$this->attributes[FE_NAME]] ?? '') === DB_COLUMN_TYPE_DATETIME) {
                $valueArr = explode(' ', $this->value);
                if (count($valueArr) > 1) {
                    $this->value = $valueArr[1];
                } else {
                    $this->value = $valueArr[0];
                }
            } else {
                $this->value = substr($this->value, 0, $this->attributes[FE_MAX_LENGTH]);
            }
        }
    }

    /**
     * Normalizes a QFQ-style date format by uppercasing only the date part (e.g. 'mm.yyyy' → 'MM.YYYY'),
     * while leaving the time part (e.g. 'HH:mm') unchanged.
     *
     *  Logic:
     *   1. Split FE_DATE_FORMAT into datePart and timePart by space
     *   2. Uppercase the datePart only
     *   3. Combine both parts to a final format
     *   4. Store result in format[FE_TYPE_DATE]
     *   5. Reset FE_DATE_FORMAT to backend default (FE_DATEPICKER_DATE_STANDARD_UPPER)
     *
     * Example:
     *   - Input:  'mm.yyyy HH:mm'
     *   - Result: format[FE_TYPE_DATE] = 'MM.YYYY HH:mm'
     *             attributes[FE_DATE_FORMAT] = 'DD.MM.YYYY'
     * */

    private function convertQfqLowerToStdDateFmtUpper(array &$attributes, array &$format): void {

        if (isset($attributes[FE_DATE_FORMAT], $attributes[FE_DATE_FORMAT_SAVE])) {
            $rawFormat = $attributes[FE_DATE_FORMAT];

            // Aufteilen in [Datumsteil, Zeitteil]
            $parts = preg_split('/\s+/', $rawFormat, 2);
            $datePart = strtoupper($parts[0] ?? '');
            $timePart = $parts[1] ?? '';

            $finalFormat = trim($datePart . ' ' . $timePart);

            $format[FE_TYPE_DATE] = $finalFormat;

            // Setze das Backend-kompatible Standardformat (z.B. DD.MM.YYYY HH:mm)
            $attributes[FE_DATE_FORMAT] = FE_DATEPICKER_DATE_STANDARD_UPPER;
        }
    }

    /**
     * Formats a given datetime string according to a QFQ-style format like 'MM.YYYY HH:mm'.
     *
     * This function takes a complete datetime string (e.g. '2025-10-22 10:30:00') and shortens it based on
     * which date components are present in the format string. Only the parts explicitly included in the
     * format (DD, MM, YYYY) will be returned — in their proper order. Any time components (e.g. HH, mm, ss)
     * are preserved and appended after the date part.
     *
     * Internally, the method:
     *  1. Parses the format string into date and time parts.
     *  2. Checks if the format is missing any of the 3 core date components (day, month, year).
     *     If all 3 are present, the original value is returned unchanged.
     *  3. If any are missing, a new format string is built using only the included parts:
     *     - The date is shortened accordingly (e.g. 'MM.YYYY' or just 'YYYY').
     *     - The time part is preserved and appended with spacing.
     *  4. The final format is applied to the DateTime object using `date_format()` and returned.
     *
     * Examples:
     *   - Format: 'MM.YYYY HH:mm'  → Output: '04.2025 10:30'
     *   - Format: 'MM HH:mm'       → Output: '04 10:30'
     *   - Format: 'YYYY'           → Output: '2025'
     *   - Format: 'DD.MM.YYYY'     → Output: original unchanged
     *
     *
     * @param string $value The full datetime string (e.g. '2025-10-22 10:30:00')
     * @param string $typeDateFormat A QFQ-style format string (e.g. 'MM.YYYY HH:mm', 'YYYY')
     * @return string                 The shortened and formatted datetime string
     */

    private function formatValueByTypeDate(string $value, string $typeDateFormat): string {
        $dt = date_create($value);
        if (!$dt) {
            return $value;
        }

        $format = strtoupper($typeDateFormat);

        // Zeit trennen
        $parts = preg_split('/\s+/', $format, 2);
        $dateFormat = $parts[0] ?? '';
        $timeFormat = $parts[1] ?? '';

        // Prüfen: Ist vollständiges Datum enthalten? Wenn ja, nicht kürzen
        if (strpos($dateFormat, FE_DATEPICKER_DAY) !== false &&
            strpos($dateFormat, FE_DATEPICKER_MONTH) !== false &&
            strpos($dateFormat, FE_DATEPICKER_YEAR) !== false) {
            return $value; // Keine Kürzung nötig
        }

        // Format-Mapping
        $dateKeys = [FE_DATEPICKER_DAY, FE_DATEPICKER_MONTH, FE_DATEPICKER_YEAR];
        $phpMap = [FE_DATEPICKER_DAY => 'd', FE_DATEPICKER_MONTH => 'm', FE_DATEPICKER_YEAR => 'Y'];
        $phpFormat = '';

        // Datumsteil aufbauen (nur enthaltene Teile, korrekt mit Punkt getrennt)
        foreach ($dateKeys as $index => $key) {
            if (strpos($dateFormat, $key) !== false) {
                if ($phpFormat !== '') {
                    $phpFormat .= '.';
                }
                $phpFormat .= $phpMap[$key];
            }
        }

        // Zeit anhängen
        if ($timeFormat !== '') {
            $phpFormat .= ' ';
            $timeParts = preg_split('/(\W+)/', $timeFormat, -1, PREG_SPLIT_DELIM_CAPTURE);
            $timeMap = [
                'HH' => 'H', 'H' => 'G',
                'MM' => 'i', 'mm' => 'i', 'm' => 'i',
                'SS' => 's', 'ss' => 's', 's' => 's',
            ];
            foreach ($timeParts as $part) {
                $upper = strtoupper($part);
                $phpFormat .= $timeMap[$upper] ?? $part;
            }
        }

        return date_format($dt, trim($phpFormat));
    }

    /**
     * Set $this->format according to FE type and configuration
     *
     * @return void
     */
    private function handleFormat(): void {
        //Examples of accepted dateFormats: YYYY-MM-DD , DD.MM.YYYY, HH:mm(24h), hh:mm(12h AM PM)
        // Get dateformat default from T3 config and adjust it for datetimepicker because config default (dd.mm.yyyy) is not the default of bootstrap datetimepicker.
        if ($this->attributes[FE_DATE_TIME_PICKER_TYPE] === DATE_TIME_PICKER_QFQ) {
            $this->useDateTimeFormatQfq();
        } else if ($this->attributes[FE_TYPE] == FE_TYPE_DATETIME) {
            if ($this->format['time'] === '') {
                $this->format['time'] = 'hh:mm';
            }
            $this->format['date'] .= ' ' . $this->format['time'];
        }

        // if FE type datetime and showSeconds is set, corrected format is needed
        if ($this->attributes[FE_TYPE] === FE_TYPE_DATETIME && $this->attributes[FE_SHOW_SECONDS] == 1 && !isset($this->format['timeParts'][2])) {
            $this->format['date'] .= ':ss';
        }

        // if FE type 'time' is used, overwrite $this->format['date']
        if ($this->attributes[FE_TYPE] === FE_TYPE_TIME) {
            $this->setTimeFormat();
        }
    }

    /**
     * Sets / Sanitizes $this->attributes[FE_DATE_DAYS_OF_WEEK_ENABLED]
     *
     * @return void
     */
    private function handleDaysOfWeekEnabled(): void {
        $this->attributes[FE_DATE_DAYS_OF_WEEK_ENABLED] = $this->attributes[FE_DATE_DAYS_OF_WEEK_ENABLED] ?? '';

        // Set correct parameter value for daysOfWeekDisabled attribute in FE
        if ($this->attributes[FE_DATE_DAYS_OF_WEEK_ENABLED] != '' && isset($this->attributes[FE_DATE_DAYS_OF_WEEK_ENABLED])) {
            $disabledDays = $this->getDateTimePickerDisabledDays();
            $this->attributes[FE_DATE_DAYS_OF_WEEK_ENABLED] = '[' . $disabledDays . ']';
        }
    }

    /**
     * Sets / Sanitizes $this->attributes[FE_INPUT_CLEAR_ME]
     *
     * @return void
     */
    private function handleClearMe(): void {
        if ($this->attributes[FE_DATE_TIME_PICKER_TYPE] === DATE_TIME_PICKER_QFQ) {
            $this->attributes[F_FE_INPUT_CLEAR_ME] = empty($this->attributes[F_FE_INPUT_CLEAR_ME]) ? 'false' : 'true';
        }
    }

    /**
     * Sets / Sanitizes $this->attributes[FE_PLACEHOLDER]
     *
     * @return void
     */
    private function handlePlaceholder(): void {
        if ($this->attributes[FE_PLACEHOLDER] == '') {
            $placeholder = $this->format['date'];
            $this->attributes[FE_PLACEHOLDER] = $placeholder;
        }
    }

    /**
     * Sets / Sanitizes $this->attributes[FE_CHECK_PATTERN] and $this->attributes[F_FE_DATA_PATTERN_ERROR]
     *
     * @return void
     * @throws \CodeException
     */
    private function handlePattern(): void {
        // HANDLE SANITIZE PATTERN
        if ($this->attributes[F_FE_DATA_PATTERN_ERROR] == '') {
            $this->attributes[F_FE_DATA_PATTERN_ERROR] = "Please match the format: " . $this->attributes[FE_PLACEHOLDER];
        }

        $this->attributes[FE_CHECK_PATTERN] = Sanitize::getInputCheckPattern($this->attributes[FE_CHECK_TYPE], $this->attributes[FE_CHECK_PATTERN], '', $sanitizeMessage);

        // Use system message only,if no custom one is set.
        if ($this->attributes[F_FE_DATA_PATTERN_ERROR] == $this->attributes[F_FE_DATA_PATTERN_ERROR_SYSTEM]) {
            $this->attributes[F_FE_DATA_PATTERN_ERROR] = $sanitizeMessage;
        }
    }
}