<?PHP
/**
 * Controls automatic translation of times.
 *
 * @author Joshua Ramon Enslin <joshua@museum-digital.de>
 */
declare(strict_types = 1);

/**
 * Autotranslater class for times.
 */
final class NodaTimeAutotranslater {

    // TODO: Move these to NodaTimeAutotranslaterLocales

    public const LANGS_SYLLABLE_CLEANING = [
        "hu" => [
            "10-as évek" => "10-es évek",
            "40-as évek" => "40-es évek",
            "50-as évek" => "50-es évek",
            "70-as évek" => "70-es évek",
            "90-as évek" => "90-es évek",
        ],
    ];

    /** @var MDMysqli */
    private MDMysqli $_mysqli_noda;
    /** @var integer */
    private int $_znum;
    /** @var MDMysqliStmt */
    private MDMysqliStmt $_insertStmt;

    /**
     * Formats a time according to a specified format.
     *
     * @return string
     */

    /**
     * Checks if a time is translatable and returns an appropriate bool for easier
     * interfacing than through self::check_translatability.
     *
     * @param string $zeit_beginn          Beginn year.
     * @param string $zeit_ende            End year.
     * @param string $zeit_zaehlzeit_monat Counting time month.
     *
     * @return boolean
     */
    public static function check_is_translatable(string $zeit_beginn, string $zeit_ende, string $zeit_zaehlzeit_monat):bool {

        if (self::check_translatability($zeit_beginn, $zeit_ende, $zeit_zaehlzeit_monat) === NodaTimeAutotranslaterStatus::NOT) {
            return false;
        }

        return true;

    }

    /**
     * Checks if a time is translatable.
     * Translatable times have either a counting time day and month or at least a month.
     *
     * @param string $zeit_beginn          Beginn year.
     * @param string $zeit_ende            End year.
     * @param string $zeit_zaehlzeit_monat Counting time month.
     *
     * @return NodaTimeAutotranslaterStatus
     */
    public static function check_translatability(string $zeit_beginn, string $zeit_ende, string $zeit_zaehlzeit_monat):NodaTimeAutotranslaterStatus {

        if ($zeit_ende === "?") {
            return NodaTimeAutotranslaterStatus::SINCE_START;
        }
        if ($zeit_beginn === "?") {
            return NodaTimeAutotranslaterStatus::UNTIL_END;
        }

        if (\intval($zeit_ende) >= 0 && \intval($zeit_beginn) < 0) {
            return NodaTimeAutotranslaterStatus::NOT;
        }

        if (($zeit_ende > 0 && \intval($zeit_ende) % 100 === 0 and (\intval($zeit_beginn) - 1) % 100 === 0)
            || (\intval($zeit_beginn) < 0 && \intval($zeit_beginn) % 100 === 0 and (\intval($zeit_ende) + 1) % 100 === 0)
        ) {
            return NodaTimeAutotranslaterStatus::CENTURY;
        }

        if ((\intval($zeit_ende) + 1) % 10 === 0 and \intval($zeit_beginn) % 10 === 0 and \intval($zeit_beginn) > 1000) {
            return NodaTimeAutotranslaterStatus::DECADE;
        }

        if (\intval($zeit_ende) < 0 && \intval($zeit_beginn) < 0
            || (\intval($zeit_ende) < 1000 and \trim($zeit_zaehlzeit_monat, ", .0") === "")
        ) {
            return NodaTimeAutotranslaterStatus::AS_YEAR_WITH_SUFFIX;
        }
        if ($zeit_ende === $zeit_beginn and \trim($zeit_zaehlzeit_monat, ", .0") === "") {
            return NodaTimeAutotranslaterStatus::ONLY_YEAR;
        }
        if ($zeit_ende !== $zeit_beginn and \trim($zeit_zaehlzeit_monat, ", .0") === "") {
            return NodaTimeAutotranslaterStatus::TIMESPAN_YEARS;
        }
        // Conditions speaking against translatability.
        if (\trim($zeit_zaehlzeit_monat, ", .0") === "") {
            return NodaTimeAutotranslaterStatus::NOT;
        }

        return NodaTimeAutotranslaterStatus::AS_MONTH_DAY;

    }

    /**
     * Gets suffix mode for years with suffix.
     *
     * @param integer $start Start year.
     * @param integer $end   End year.
     *
     * @return NodaTimeAutotranslaterSuffixMode
     */
    public static function getSuffixModeForYearsWSuffix(int $start, int $end):NodaTimeAutotranslaterSuffixMode {

        if ($start < 0 && $end < 0) {
            return NodaTimeAutotranslaterSuffixMode::BCE; // 2; // " v. Chr.";
        }
        else if ($end < 1000) {
            return NodaTimeAutotranslaterSuffixMode::CE; // " n. Chr.";
        }
        else {
            return NodaTimeAutotranslaterSuffixMode::ANY; // Times larger than 1000 n. Chr.
        }

    }

    /**
     * Applies suffix format to a time string.
     *
     * @param NodaTimeAutotranslaterLocales    $tLang      Two digit ANSI language code.
     * @param string                           $timeName   Time name.
     * @param NodaTimeAutotranslaterSuffixMode $suffixMode Suffix mode.
     *
     * @return string
     */
    private static function _applyBcBceFormat(NodaTimeAutotranslaterLocales $tLang, string $timeName, NodaTimeAutotranslaterSuffixMode $suffixMode):string {

        switch ($suffixMode) {
        case NodaTimeAutotranslaterSuffixMode::ANY:
            return $timeName;
        case NodaTimeAutotranslaterSuffixMode::CE:
            return \sprintf($tLang->eraFormatCeForSprintf(), $timeName);
        case NodaTimeAutotranslaterSuffixMode::BCE:
            return \sprintf($tLang->eraFormatBceForSprintf(), $timeName);
        default:
            throw new Exception("Unknown case encountered for time translations.");
        }

    }

    /**
     * Translated years or timespans below 1000 CE.
     *
     * @param array<integer|string> $timeInfo Time information.
     *
     * @return array<string, string>
     */
    public static function translateYearsWithSuffix(array $timeInfo):array {

        $start = \intval($timeInfo['zeit_beginn']);
        $end = \intval($timeInfo['zeit_ende']);

        $suffixMode = self::getSuffixModeForYearsWSuffix($start, $end);

        // Time info to pass
        if ($suffixMode === NodaTimeAutotranslaterSuffixMode::BCE) {
            $timeInfoToCopy = $timeInfo;
            $timeInfoToCopy["zeit_beginn"] = \abs($start);
            $timeInfoToCopy["zeit_ende"] = \abs($end);
        }

        $output = [];
        $cases = NodaTimeAutotranslaterLocales::cases();

        // TODO: Run gettranslations first, then loop
        foreach ($cases as $tLang) {

            if ($suffixMode === NodaTimeAutotranslaterSuffixMode::BCE) {

                if (empty($timeInfoToCopy)) {
                    throw new Exception("No time information to copy existent");
                }
                $ceIndicatorsToRemove = explode("%s", $tLang->eraFormatCeForSprintf());
                $year = self::getTranslations($timeInfoToCopy)[$tLang->name];
                foreach ($ceIndicatorsToRemove as $ceIndicatorToRemove) {
                    $year = str_replace($ceIndicatorToRemove, "", $year);
                }
            }
            else {
                if ($start === $end) {
                    $year = \sprintf($tLang->formatSingleYearForSprintf(), (string)\abs($start));
                }
                else $year = \sprintf($tLang->formatYearspanForSprintf(), (string)\abs($start), (string)\abs($end));
            }

            $output[$tLang->name] = self::_applyBcBceFormat($tLang, $year, $suffixMode);

        }
        return $output;

    }

    /**
     * Translated only years: 1994.
     *
     * @param array<integer|string> $timeInfo Time information.
     *
     * @return array<string, string>
     */
    public static function translateYearOnly(array $timeInfo):array {

        $start = \intval($timeInfo['zeit_beginn']);
        $output = [];

        $cases = NodaTimeAutotranslaterLocales::cases();
        foreach ($cases as $tLang) {
            $format = $tLang->formatSingleYearForSprintf();
            $output[$tLang->name] = \sprintf($format, (string)\abs($start));
        }
        return $output;

    }

    /**
     * Translated only years: 1994.
     *
     * @param array<integer|string> $timeInfo Time information.
     *
     * @return array<string, string>
     */
    public static function translateTimespanYears(array $timeInfo):array {

        $start = \intval($timeInfo['zeit_beginn']);
        $end = \intval($timeInfo['zeit_ende']);
        $output = [];

        $cases = NodaTimeAutotranslaterLocales::cases();
        foreach ($cases as $tLang) {
            $output[$tLang->name] = \sprintf($tLang->formatYearspanForSprintf(), (string)\abs($start), (string)\abs($end));
        }
        return $output;

    }

    /**
     * Translates century names: 19. Jahrhundert.
     *
     * @param array<integer|string> $timeInfo Time information.
     *
     * @return array<string, string>
     */
    public static function translateYearsAsCentury(array $timeInfo):array {

        if (\intval($timeInfo['zeit_beginn']) > 0) {
            // Beginn: 1500. (1501 - 1) / 100 + 1 = 16. 16th century is the time.
            $start_cen = ((\intval($timeInfo['zeit_beginn']) - 1) / 100) + 1;
            // End: 1600. 16th century is the time.
            $end_cen = \intval($timeInfo['zeit_ende']) / 100;
        }
        else {
            // End: -1600. 16th century is the time.
            $start_cen = \intval($timeInfo['zeit_beginn']) / 100;
            // End: -1500. (1501 - 1) / 100 + 1 = 16. 16th century is the time.
            $end_cen = ((\intval($timeInfo['zeit_ende']) + 1) / 100) - 1;
        }

        $suffixMode = self::getSuffixModeForYearsWSuffix(\intval($timeInfo['zeit_beginn']) - 1, \intval($timeInfo['zeit_ende']));

        $output = [];

        $cases = NodaTimeAutotranslaterLocales::cases();
        foreach ($cases as $tLang) {

            if ($start_cen === $end_cen) {
                $tLangValue = \sprintf($tLang->formatCenturyForSprintf(), (string)\abs($start_cen));
            }
            else {
                $tLangValue = \sprintf($tLang->formatCenturiesForSprintf(), (string)\abs($start_cen), (string)\abs($end_cen));
            }
            $output[$tLang->name] = self::_applyBcBceFormat($tLang, $tLangValue, $suffixMode);

        }
        return $output;

    }

    /**
     * Translates decade names: 1920er Jahre.
     *
     * @param array<integer|string> $timeInfo Time information.
     *
     * @return array<string, string>
     */
    public static function translateYearsAsDecade(array $timeInfo):array {

        // Beginn: 1500. (1501 - 1) / 100 + 1 = 16. 16th century is the time.
        $start_cen = (\intval($timeInfo['zeit_beginn']));
        // End: 1600. 16th century is the time.
        $end_cen = (\intval($timeInfo['zeit_ende']));

        $suffixMode = self::getSuffixModeForYearsWSuffix(\intval($timeInfo['zeit_beginn']) - 1, \intval($timeInfo['zeit_ende']));

        $output = [];

        $cases = NodaTimeAutotranslaterLocales::cases();
        foreach ($cases as $tLang) {

            if ($start_cen === $end_cen - 9) {
                $tLangValue = \sprintf($tLang->formatDecadeForSprintf(), (string)$start_cen, (string)$end_cen);
                if (!empty(self::LANGS_SYLLABLE_CLEANING[$tLang->name])) $tLangValue = \strtr($tLangValue, self::LANGS_SYLLABLE_CLEANING[$tLang->name]);
            }
            else {
                $tLangValue = \sprintf($tLang->formatDecadesForSprintf(), (string)$start_cen, (string)($end_cen - 9));
                if (!empty(self::LANGS_SYLLABLE_CLEANING[$tLang->name])) $tLangValue = \strtr($tLangValue, self::LANGS_SYLLABLE_CLEANING[$tLang->name]);
            }
            $output[$tLang->name] = self::_applyBcBceFormat($tLang, $tLangValue, $suffixMode);

        }

        return $output;

    }

    /**
     * Translated years or timespans below 1000 CE.
     *
     * @param array<integer|string> $timeInfo Time information.
     *
     * @return array<string, string>
     */
    public static function translateYearsAfterStart(array $timeInfo):array {

        if (empty(\trim((string)$timeInfo['zeit_zaehlzeit_monat'], " ,.;0"))) {
            $timeInfo['zeit_beginn'] = \strval(\intval($timeInfo['zeit_beginn']) - 1);
        }
        # else throw new Exception("Unhandled split case. Counting time is: " . var_export($timeInfo, true));
        $innerTimeInfo = $timeInfo;
        $innerTimeInfo['zeit_ende'] = $timeInfo['zeit_beginn'];
        $output = [];

        $innerTls = self::getTranslations($innerTimeInfo);

        $cases = NodaTimeAutotranslaterLocales::cases();
        foreach ($cases as $tLang) {

            $dateAlone = $innerTls[$tLang->name];

            $timeName = \sprintf($tLang->formatYearsAfterStartForSprintf(), $dateAlone);
            $output[$tLang->name] = $timeName;

        }
        return $output;

    }

    /**
     * Translated years or timespans below 1000 CE.
     *
     * @param array<integer|string> $timeInfo Time information.
     *
     * @return array<string, string>
     */
    public static function translateYearsSinceStart(array $timeInfo):array {

        // $start = \intval($timeInfo['zeit_beginn']);

        if (substr((string)$timeInfo['zeit_name'], 0, 5) === "Nach ") {
            return self::translateYearsAfterStart($timeInfo);
        }

        $innerTimeInfo = $timeInfo;
        $innerTimeInfo['zeit_ende'] = $timeInfo['zeit_beginn'];
        $output = [];

        $innerTls = self::getTranslations($innerTimeInfo);

        $cases = NodaTimeAutotranslaterLocales::cases();
        foreach ($cases as $tLang) {

            $dateAlone = $innerTls[$tLang->name];

            $timeName = \sprintf($tLang->formatYearsSinceStartForSprintf(), $dateAlone);
            $output[$tLang->name] = $timeName;

        }
        return $output;

    }

    /**
     * Translated years or timespans below 1000 CE.
     *
     * @param array<integer|string> $timeInfo Time information.
     *
     * @return array<string, string>
     */
    public static function translateYearsBeforeEnd(array $timeInfo):array {

        if (empty(\trim((string)$timeInfo['zeit_zaehlzeit_monat'], " ,.;0"))) {
            $timeInfo['zeit_ende'] = \strval(\intval($timeInfo['zeit_ende']) + 1);
        }
        // $end = \intval($timeInfo['zeit_ende']);

        $innerTimeInfo = $timeInfo;
        $innerTimeInfo['zeit_beginn'] = $timeInfo['zeit_ende'];

        $output = [];

        $innerTls = self::getTranslations($innerTimeInfo);

        $cases = NodaTimeAutotranslaterLocales::cases();
        foreach ($cases as $tLang) {

            $dateAlone = $innerTls[$tLang->name];

            $timeName = \sprintf($tLang->formatYearsBeforeStartForSprintf(), $dateAlone);
            $output[$tLang->name] = $timeName;

        }
        return $output;

    }

    /**
     * Translated years or timespans below 1000 CE.
     *
     * @param array<integer|string> $timeInfo Time information.
     *
     * @return array<string, string>
     */
    public static function translateYearsUntilEnd(array $timeInfo):array {

        // $end = \intval($timeInfo['zeit_ende']);

        if (substr((string)$timeInfo['zeit_name'], 0, 4) === "Vor ") {
            return self::translateYearsBeforeEnd($timeInfo);
        }

        $innerTimeInfo = $timeInfo;
        $innerTimeInfo['zeit_beginn'] = $timeInfo['zeit_ende'];

        $output = [];

        $innerTls = self::getTranslations($innerTimeInfo);

        $cases = NodaTimeAutotranslaterLocales::cases();
        foreach ($cases as $tLang) {

            $dateAlone = $innerTls[$tLang->name];

            $timeName = \sprintf($tLang->formatYearsUntilStartForSprintf(), $dateAlone);
            $output[$tLang->name] = $timeName;
        }
        return $output;

    }

    /**
     * Prepares translations for each available language.
     *
     * @param array<integer|string> $timeInfo Time information.
     *
     * @return array<string>
     */
    public static function prepareTranslations(array $timeInfo):array {

        if (!empty($timeInfo['zeit_name']) and strlen((string)$timeInfo['zeit_name']) > 10 and !empty($timespanDates = NodaTimeSplitter::attempt_splitting_from_till((string)$timeInfo['zeit_name']))) {

            $output = [];

            if (empty($start = NodaTimeSplitter::attempt_splitting($timespanDates['start_name']))) {
                return [];
            }
            $startTimeInfo = [
                "zeit_name" => $timespanDates['start_name'],
                "zeit_beginn" => $start->start_year,
                "zeit_ende" => $start->end_year,
                "zeit_zaehlzeit_jahr" => NodaTimeSplitter::timePartsToCountingYear($start),
                "zeit_zaehlzeit_monat" => $start->counting_time_month,
                "zeit_zaehlzeit_tag" => $start->counting_time_day,
                "zeit_zaehlzeit_vorzeichen" => $start->counting_time_indicator->toString(),
            ];

            if (empty($end = NodaTimeSplitter::attempt_splitting($timespanDates['end_name']))) {
                return [];
            }
            $endTimeInfo = [
                "zeit_name" => $timespanDates['end_name'],
                "zeit_beginn" => $end->start_year,
                "zeit_ende" => $end->end_year,
                "zeit_zaehlzeit_jahr" => NodaTimeSplitter::timePartsToCountingYear($end),
                "zeit_zaehlzeit_monat" => $end->counting_time_month,
                "zeit_zaehlzeit_tag" => $end->counting_time_day,
                "zeit_zaehlzeit_vorzeichen" => $end->counting_time_indicator->toString(),
            ];

            $output = [];
            $cases = NodaTimeAutotranslaterLocales::cases();
            foreach ($cases as $tLang) {
                $startTls = self::getTranslations($startTimeInfo);
                $endTls = self::getTranslations($endTimeInfo);
                if (empty($startTls) || empty($endTls)) return [];
                $start_term = $startTls[$tLang->name];
                $end_term = $endTls[$tLang->name];

                $output[$tLang->name] = \sprintf($tLang->formatYearspanForSprintf(), $start_term, $end_term);
            }
            return $output;
        }

        if (($translation_type = self::check_translatability((string)$timeInfo['zeit_beginn'], (string)$timeInfo['zeit_ende'], (string)$timeInfo['zeit_zaehlzeit_monat'])) === NodaTimeAutotranslaterStatus::NOT) {
            throw new MDgenericInvalidInputsException("Non-translatable date: {$timeInfo['zeit_beginn']} - {$timeInfo['zeit_ende']}");
        }

        if ($translation_type === NodaTimeAutotranslaterStatus::ONLY_YEAR) {
            return self::translateYearOnly($timeInfo);
        }

        if ($translation_type === NodaTimeAutotranslaterStatus::SINCE_START) {
            return self::translateYearsSinceStart($timeInfo);
        }

        if ($translation_type === NodaTimeAutotranslaterStatus::UNTIL_END) {
            return self::translateYearsUntilEnd($timeInfo);
        }

        if ($translation_type === NodaTimeAutotranslaterStatus::CENTURY) {
            return self::translateYearsAsCentury($timeInfo);
        }

        if ($translation_type === NodaTimeAutotranslaterStatus::DECADE) {
            return self::translateYearsAsDecade($timeInfo);
        }

        if ($translation_type === NodaTimeAutotranslaterStatus::TIMESPAN_YEARS) {
            return self::translateTimespanYears($timeInfo);
        }

        if ($translation_type === NodaTimeAutotranslaterStatus::AS_YEAR_WITH_SUFFIX) {
            return self::translateYearsWithSuffix($timeInfo);
        }

        $suffixMode = self::getSuffixModeForYearsWSuffix(\intval($timeInfo['zeit_beginn']) - 1, \intval($timeInfo['zeit_ende']));

        if (\trim((string)$timeInfo['zeit_zaehlzeit_tag'], ", .0") === "") {
            $dateStr = "{$timeInfo['zeit_zaehlzeit_jahr']}-{$timeInfo['zeit_zaehlzeit_monat']}-05 12:00:01";
            $usecase = NodaTimeAutotranslaterUseCase::MONTH;
        }
        else {
            $dateStr = "{$timeInfo['zeit_zaehlzeit_jahr']}-{$timeInfo['zeit_zaehlzeit_monat']}-{$timeInfo['zeit_zaehlzeit_tag']} 12:00:01";
            $usecase = NodaTimeAutotranslaterUseCase::DAY;
        }

        $dateGeneral = new DateTimeImmutable($dateStr);

        $output = [];
        $cases = NodaTimeAutotranslaterLocales::cases();
        foreach ($cases as $tLang) {

            $locale = $tLang->localeIntlDateFormatter();

            $dateGeneral = IntlCalendar::createInstance(locale: $locale);
            $dateGeneral->set(IntlCalendar::FIELD_YEAR, (int)$timeInfo['zeit_zaehlzeit_jahr']);
            $dateGeneral->set(IntlCalendar::FIELD_MONTH, (int)$timeInfo['zeit_zaehlzeit_monat'] - 1);
            if ($usecase === NodaTimeAutotranslaterUseCase::DAY) {
                $dateGeneral->set(IntlCalendar::FIELD_DAY_OF_MONTH, (int)$timeInfo['zeit_zaehlzeit_tag']);
            }

            // Set time to noon, so that time zones or DST will not make a difference
            $dateGeneral->set(IntlCalendar::FIELD_AM_PM, 0); // 0: AM, 1: PM
            $dateGeneral->set(IntlCalendar::FIELD_HOUR, 11);

            $format = match($usecase) {
                NodaTimeAutotranslaterUseCase::MONTH => $tLang->formatYearMonthForIntlDateFormatter(),
                default => $tLang->formatFullDateForIntlDateFormatter(),
            };

            /*
            \setlocale(LC_TIME, $locale);
            $tLangValue = self::_formatTimeName($locale, $tLangValue, $dateGeneral);
            if ($locale !== \setlocale(LC_TIME, "0")) continue;
             */

            # \setlocale(LC_TIME, $locale);
            # if ($locale !== \setlocale(LC_TIME, "0")) continue;
            # $tLangValue = \strftime($format, $dateGeneral ?: 0);

            $fmt = new IntlDateFormatter(
                $locale,
                timezone: new DateTimeZone("GMT"),
                pattern: $format,
            );
            if (($tLangValue = $fmt->format($dateGeneral)) === false) continue;

            $output[$tLang->name] = self::_applyBcBceFormat($tLang, $tLangValue, $suffixMode);

        }

        return $output;

    }

    /**
     * Validates correctness of years in translation strings.
     *
     * @param string|integer        $start        Start year.
     * @param string|integer        $end          End year.
     * @param array<string, string> $translations Translations.
     *
     * @return boolean
     */
    public static function validateTranslations(string|int $start, string|int $end, array $translations):bool {

        $start = ltrim((string)$start, ' 0-');
        $end = ltrim((string)$end, ' 0-');

        // Edge cases: Centuries and decades have special translations
        // and can thus not be validated properly
        // Century BCE
        if (substr($start, -1) === "0" && substr($end, -1) === '1' && $start > $end) {
            return true;
        }
        // Century CE
        if (substr($start, -1) === "1" && substr($end, -1) === '0' && $start < $end) {
            return true;
        }
        // Decade
        if (substr($start, -1) === "0" && substr($end, -1) === '9' && $start < $end) {
            return true;
        }

        // 1920 + ? can be both Since 1920 and After 1919, so validation
        // is impossible there, too
        if ($start === '?' || $end === '?') return true;

        // Unset unvalidatable languages
        unset($translations['ar'], $translations['fa']);

        if ($start !== '?') {
            foreach ($translations as $t) {
                if (!str_contains($t, $start)) {
                    return false;
                }
            }
        }
        if ($end !== '?' && $start !== $end) {
            foreach ($translations as $t) {
                if (!str_contains($t, $end)) {
                    return false;
                }
            }
        }

        return true;

    }

    /**
     * Gets translations for a given entry type.
     *
     * @param array<integer|string> $timeInfo Time information.
     *
     * @return array<string>
     */
    public static function getTranslations(array $timeInfo):array {

        $output = self::prepareTranslations($timeInfo);

        if (self::validateTranslations($timeInfo['zeit_beginn'], $timeInfo['zeit_ende'], $output) === false) return [];

        return $output;

    }

    /**
     * Runs autotranslater.
     *
     * @param array<integer|string> $timeInfo Time information.
     *
     * @return void
     */
    public function translate(array $timeInfo):void {

        if (empty($translations = self::getTranslations($timeInfo))) {
            return;
        }

        $this->_mysqli_noda->autocommit(false);

        foreach ($translations as $tLang => $tLangValue) {
            $this->_insertStmt->bind_param("iss", $this->_znum, $tLang, $tLangValue);
            $this->_insertStmt->execute();
        }

        $this->_mysqli_noda->commit();
        $this->_mysqli_noda->autocommit(true);

    }

    /**
     * Constructor.
     *
     * @param MDMysqli $mysqli_noda Database connection.
     * @param integer  $znum        Time ID.
     *
     * @return void
     */
    public function __construct(MDMysqli $mysqli_noda, int $znum) {

        $this->_mysqli_noda = $mysqli_noda;
        $this->_znum = $znum;

        $this->_insertStmt = $this->_mysqli_noda->do_prepare("INSERT INTO `zeit_translation`
            (`zeit_id`, `trans_language`, `trans_name`)
            VALUES
            (?, ?, ?)");

    }

    /**
     * Destructor.
     *
     * @return void
     */
    public function __destruct() {

        $this->_insertStmt->close();

    }
}
