/// <summary>
        ///     Maps <paramref name="identityNumber" /> to a
        ///     <see cref="StatementBruteForce.Core.SouthAfricanIdentityNumberModel" /> object.
        /// </summary>
        /// <param name="identityNumber">13 digit South African identity number, defined as YYMMDDSSSSCAZ.</param>
        /// <returns>
        ///     A <see cref="StatementBruteForce.Core.SouthAfricanIdentityNumberModel" /> object.
        /// </returns>
        public static SouthAfricanIdentityNumberModel ParseIdentityNumberStringToModel(string identityNumber)
        {
            var chars = identityNumber.ToCharArray();

            #region local functions

            int yy()
            {
                if (char.IsDigit(c: chars[0]) && char.IsDigit(c: chars[1]))
                {
                    return(1900 + 10 * CharUnicodeInfo.GetDigitValue(ch: chars[0]) +
                           CharUnicodeInfo.GetDigitValue(ch: chars[1]));
                }

                return(-1);
            }

            int mm()
            {
                if (char.IsDigit(c: chars[2]) && char.IsDigit(c: chars[3]))
                {
                    return(10 * CharUnicodeInfo.GetDigitValue(ch: chars[2]) +
                           CharUnicodeInfo.GetDigitValue(ch: chars[3]));
                }

                return(-1);
            }

            int dd()
            {
                if (char.IsDigit(c: chars[4]) && char.IsDigit(c: chars[5]))
                {
                    return(10 * CharUnicodeInfo.GetDigitValue(ch: chars[4]) +
                           CharUnicodeInfo.GetDigitValue(ch: chars[5]));
                }

                return(-1);
            }

            #endregion


            var model = new SouthAfricanIdentityNumberModel(yearOfBirth: yy(), monthOfBirth: mm(), dayOfBirth: dd(),
                                                            gender: char.IsDigit(c: chars[6]) ? CharUnicodeInfo.GetDigitValue(ch: chars[6]) : -1,
                                                            genderSequence1: char.IsDigit(c: chars[7]) ? CharUnicodeInfo.GetDigitValue(ch: chars[7]) : -1,
                                                            genderSequence2: char.IsDigit(c: chars[8]) ? CharUnicodeInfo.GetDigitValue(ch: chars[8]) : -1,
                                                            genderSequence3: char.IsDigit(c: chars[9]) ? CharUnicodeInfo.GetDigitValue(ch: chars[9]) : -1,
                                                            citizenship: char.IsDigit(c: chars[10]) ? CharUnicodeInfo.GetDigitValue(ch: chars[10]) : -1,
                                                            obsolete: char.IsDigit(c: chars[11]) ? CharUnicodeInfo.GetDigitValue(ch: chars[11]) : -1,
                                                            checksum: char.IsDigit(c: chars[12]) ? CharUnicodeInfo.GetDigitValue(ch: chars[12]) : -1);
            return(model);
        }
        /// <summary>
        ///     Generates valid identity numbers.
        /// </summary>
        /// <param name="seedModel">
        ///     A <see cref="StatementBruteForce.Core.SouthAfricanIdentityNumberModel" /> object used as seed value for generating
        ///     permutations.
        /// </param>
        /// <param name="genderType">
        ///     An enum option to specify the male or female identity numbers if desired.
        /// </param>
        /// <returns>
        ///     List of valid identity numbers.
        /// </returns>
        public static List <string> GenerateValidIdentityNumbers(SouthAfricanIdentityNumberModel seedModel,
                                                                 GenderType?genderType = null)
        {
            var list = new List <string>();

            // If no values are provided, loop through possible values in a nested manner.
            var startMonth = 1;
            var endMonth   = 12;

            if (!string.IsNullOrEmpty(value: seedModel.MonthOfBirth))
            {
                var month = Convert.ToInt32(value: seedModel.MonthOfBirth);
                startMonth = month;
                endMonth   = month;
            }

            for (var m = startMonth; m <= endMonth; m++)
            {
                var startDay = 1;
                var endDay   = DateTime.DaysInMonth(year: seedModel.Year, month: m);
                if (!string.IsNullOrEmpty(value: seedModel.DayOfBirth))
                {
                    var day = Convert.ToInt32(value: seedModel.DayOfBirth);
                    startDay = day;
                    endDay   = day;
                }

                for (var d = startDay; d <= endDay; d++)
                {
                    var startGender = 0;
                    var endGender   = 9;
                    if (genderType.HasValue)
                    {
                        if (genderType == GenderType.Male)
                        {
                            startGender = 5;
                        }
                        else
                        {
                            endGender = 4;
                        }
                    }

                    if (!string.IsNullOrEmpty(value: seedModel.GenderDigit))
                    {
                        var gender = Convert.ToInt32(value: seedModel.GenderDigit);
                        startGender = gender;
                        endGender   = gender;
                    }

                    for (var g = startGender; g <= endGender; g++)
                    {
                        var startSequence     = 0;
                        var endSequence       = 999;
                        var incrementSequence = 1;

                        if (!string.IsNullOrEmpty(value: seedModel.GenderSequenceDigit1))
                        {
                            startSequence += Convert.ToInt32(value: seedModel.GenderSequenceDigit1) * 100;
                            endSequence    = startSequence + 99;
                        }

                        if (!string.IsNullOrEmpty(value: seedModel.GenderSequenceDigit2))
                        {
                            startSequence    += Convert.ToInt32(value: seedModel.GenderSequenceDigit2) * 10;
                            incrementSequence = 100;
                        }

                        if (!string.IsNullOrEmpty(value: seedModel.GenderSequenceDigit3))
                        {
                            startSequence    += Convert.ToInt32(value: seedModel.GenderSequenceDigit3);
                            incrementSequence = 10;
                        }

                        for (var s = startSequence; s <= endSequence; s += incrementSequence)
                        {
                            var startCitizenship = 0;
                            var endCitizenship   = 1;
                            if (seedModel.Citizenship.HasValue)
                            {
                                var citizenship = seedModel.Citizenship.Value;
                                if (citizenship == CitizenshipType.SA)
                                {
                                    endCitizenship = (int)CitizenshipType.SA;
                                }
                                else
                                {
                                    startCitizenship = (int)CitizenshipType.Other;
                                }
                            }

                            for (var c = startCitizenship; c <= endCitizenship; c++)
                            {
                                var startObsolete = 8;
                                var endObsolete   = 9;
                                if (!string.IsNullOrEmpty(value: seedModel.ObsoleteDigit))
                                {
                                    var obsolete = Convert.ToInt32(value: seedModel.ObsoleteDigit);
                                    startObsolete = obsolete;
                                    endObsolete   = obsolete;
                                }

                                for (var o = startObsolete; o <= endObsolete; o++)
                                {
                                    var numberSection = $"{seedModel.YearOfBirth:D2}{m:D2}{d:D2}{g}{s:D3}{c}{o}";
                                    if (!string.IsNullOrEmpty(value: seedModel.ChecksumDigit))
                                    {
                                        numberSection += seedModel.ChecksumDigit;
                                    }
                                    else
                                    {
                                        numberSection +=
                                            CalculateLuhnChecksumDigit(identityNumberSection: numberSection).ToString();
                                    }

                                    if (numberSection.IsValidSouthAfricanIdentityNumber())
                                    {
                                        list.Add(item: numberSection);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(list);
        }