handleSession method

SessionStatus handleSession(
  1. SessionStatus session,
  2. OcrData ocr
)

Implementation

SessionStatus handleSession(SessionStatus session, OcrData ocr) {
  try {
    final List<String> lines = ocr.lines.map((a) => a.text).toList();
    final List<String> baseLines = List<String>.of(ocr.lines.map((a) => a.text).toList());
    SessionStatus updatedSession = session;

    if (updatedSession.step == 0) {
      updatedSession = updatedSession.copyWith(step: 1, dateTime: DateTime.now(), details: "Looking for BirthGenderExp", ocr: ocr);
    }
    // log("handleSession ${updatedSession.step}");
    if (updatedSession.step == 1) {
      String secondLineGuess = lines.firstWhere((a) => _dateSexRe.hasMatch(a), orElse: () => '');
      if (secondLineGuess.isNotEmpty) {
        final dateSexMatch = _dateSexRe.firstMatch(secondLineGuess);
        String dateSexStr = dateSexMatch!.group(0)!;
        final birthDateStr = dateSexMatch.group(1);
        final birthCheck = dateSexMatch.group(2);
        final sexStr = dateSexMatch.group(3);
        final expiryDateStr = dateSexMatch.group(4);
        final expiryCheck = dateSexMatch.group(5);
        bool birthDateValid = _computeMrzCheckDigit(birthDateStr!) == birthCheck;
        bool expDateValid = _computeMrzCheckDigit(expiryDateStr!) == expiryCheck;
        bool sexValid = ["M", "F", "X", "<"].contains(sexStr);

        var currentVal = updatedSession.validation ?? OcrMrzValidation();
        currentVal.birthDateValid = birthDateValid;
        currentVal.expiryDateValid = expDateValid;
        currentVal.sexValid = sexValid;
        if (birthDateValid && expDateValid) {
          updatedSession = updatedSession.copyWith(
            step: 2,
            details: "Found Dates and Gender",
            validation: currentVal,
            birthDate: birthDateStr,
            expiryDate: expiryDateStr,
            sex: sexStr,
            dateSexStr: dateSexStr,
            line2: secondLineGuess,
            birthCheck: birthCheck,
            expCheck: expiryCheck,
            logDetails: "Found Valid Birth Sex Gender => $dateSexStr",
          );
        } else {
          updatedSession = updatedSession.copyWith(
            step: 1,
            details: "Looking for valid Dates",
            validation: currentVal,
            birthDate: birthDateStr,
            expiryDate: expiryDateStr,
            sex: sexStr,
            dateSexStr: dateSexStr,
            line2: secondLineGuess,
            birthCheck: birthCheck,
            expCheck: expiryCheck,
            logDetails: "Found Invalid Birth Sex Gender => $dateSexStr",
          );
        }
      }
    }
    if (updatedSession.step == 2) {
      String? type;
      final parts = updatedSession.dateSexStr!.split(RegExp(r'[^0-9]+'));
      String? nationalityStr;
      String birth = parts[0];
      String exp = parts[1];
      // log("look before $birth or after $exp  ${updatedSession.line2??''}");
      // final countryBeforeBirthReg = RegExp(r'[A-Za-z]{3}' + birth);
      final countryBeforeBirthReg = RegExp(r'([A-Za-z0-9]{3})(?=' + RegExp.escape(birth) + r')');
      final countryAfterExpReg = RegExp(RegExp.escape(exp) + r'([A-Za-z]{3})');
      String line1 = "";
      String? line3;
      for (var l in lines) {
        int index = lines.indexOf(l);
        l = normalize(l);
        final countryBeforeBirthMatch = countryBeforeBirthReg.firstMatch(normalize(l));
        if (countryBeforeBirthMatch != null) {
          // log("we have before ${countryBeforeBirthMatch.group(0)}");
          type = l.length < 40 ? "td2" : "td3";
          nationalityStr = countryBeforeBirthMatch.group(0)!;
          if (index != 0) {
            line1 = lines[index - 1];
          }
          updatedSession = updatedSession.copyWith(logDetails: "Found Valid Nationality ${nationalityStr} in ${countryBeforeBirthMatch.group(0)}$birth");
        }
        final countryAfterExpMatch = countryAfterExpReg.firstMatch(normalize(l));
        if (countryAfterExpMatch != null && normalize(l).startsWith(birth)) {
          // log("we have match after ${countryAfterExpMatch.group(1)}");
          type = "td1";
          nationalityStr = countryAfterExpMatch.group(1)!;
          if (index != 0) {
            line1 = lines[index - 1];
          }
          if (index != lines.length - 1) {
            line3 = lines[index + 1];
          }
          updatedSession = updatedSession.copyWith(logDetails: "Found Valid Nationality ${nationalityStr} in $exp${countryAfterExpMatch.group(0)}");
        } else {
          // log("not countryAfterExpReg ${normalize(l)}");
        }

        if (nationalityStr != null) {
          final fixedNationalityStr = fixAlphaOnlyField(nationalityStr);
          if (isValidMrzCountry(nationalityStr) || isValidMrzCountry(fixedNationalityStr)) {
            var currentVal = updatedSession.validation ?? OcrMrzValidation();
            currentVal.nationalityValid = isValidMrzCountry(nationalityStr) || isValidMrzCountry(fixedNationalityStr);
            updatedSession = updatedSession.copyWith(step: 3, details: 'Found nationality', nationality: nationalityStr, type: type, line1: line1, line2: normalize(l), line3: line3, validation: currentVal);
          }

          // final fixedNationalityStr = fixAlphaOnlyField(nationalityStr);
          if (isValidMrzCountry(nationalityStr)) {
            var currentVal = updatedSession.validation ?? OcrMrzValidation();
            currentVal.nationalityValid = isValidMrzCountry(nationalityStr);
            updatedSession = updatedSession.copyWith(step: 3, details: 'Found nationality', nationality: nationalityStr, type: type, line1: line1, line2: normalize(l), line3: line3, validation: currentVal);
          }
        } else {
          updatedSession = updatedSession.copyWith(logDetails: "Did not found valid Nationality before $birth or after $exp in\n${lines.where((a) => a.contains(birth) || a.contains(exp)).map((b) => normalize(b)).join("\n")}");
          // log("not valid nat ${nationalityStr} in ${lines.map((a) => normalize(a)).join("\n")}");
        }
      }
    }

    if (updatedSession.step == 3) {
      String? numberStr;
      if (updatedSession.type == "td1") {
        String dateStart = updatedSession.birthDate!;
        for (var l in lines) {
          int index = lines.indexOf(l);
          if (l.startsWith(dateStart)) {
            // log("we have before ${countryBeforeBirthMatch.group(0)}");
            // numberStr = numberBeforeNatMatch.group(1)!.replaceAll("O", '0').replaceAll("<", '');
            // String numberStrCheck = numberBeforeNatMatch.group(2)!;
            // bool docNumberValid = _computeMrzCheckDigit(numberStr!) == numberStrCheck;
            // currentVal.docNumberValid = docNumberValid;

            var currentVal = updatedSession.validation!;

            String firstLineGuess = normalize(lines[index - 1]);
            if (firstLineGuess.length >= 15) {
              String firstFiveChars = firstLineGuess.substring(0, 5);
              String docCode = firstFiveChars.substring(0, 2);
              String countryCode = firstFiveChars.substring(2, 5);
              bool validCode = DocumentCodeHelper.isValid(docCode);
              log("valid code ${validCode} ==> ${docCode}");
              bool validCountry = isValidMrzCountry(countryCode);
              if (validCode && validCountry) {
                numberStr = firstLineGuess.substring(5, 14);
                final numberStrCheck = firstLineGuess[14];
                bool validDocNumber = _computeMrzCheckDigit(numberStr) == numberStrCheck;

                currentVal.countryValid = validCountry;
                currentVal.docCodeValid = validCode;

                updatedSession = updatedSession.copyWith(
                  step: 3,
                  line1: normalizeWithLength(normalize(firstLineGuess), len: 30),
                  line2: normalizeWithLength("${dateStart}${countryCode}", len: 30),
                  details: "Found Number Code Country : $numberStr",
                  countryCode: countryCode,
                  docCode: docCode,
                  validation: currentVal,
                  numberCheck: numberStrCheck,
                  logDetails: "Found valid $countryCode DocCode $docCode",
                );

                currentVal.docNumberValid = validDocNumber;
                currentVal.linesLengthValid = true;
                currentVal.finalCheckValid = true;
                currentVal.personalNumberValid = true;
                if (validDocNumber) {
                  updatedSession = updatedSession.copyWith(
                    step: 4,
                    line1: normalizeWithLength(normalize(firstLineGuess), len: 30),
                    line2: normalizeWithLength("${dateStart}${numberStr}${numberStrCheck}", len: 30),
                    details: "Found Number Code Country : $numberStr",
                    countryCode: countryCode,
                    docCode: docCode,
                    docNumber: numberStr,
                    validation: currentVal,
                    numberCheck: numberStrCheck,
                    logDetails: "Found valid Number: $numberStr Country: $countryCode DocCode $docCode",
                  );
                } else {
                  // log("invalid doc number $numberStr checked $numberStrCheck\n${normalizeWithLength(normalize(firstLineGuess), len: 30)}");
                }
              }
            }

            // log("numberStr $numberStr");
            // log("numberStrCheck $numberStrCheck");
          }

          // if (nationalityStr != null) {
          //   if (isValidMrzCountry(nationalityStr)) {
          //     var currentVal = updatedSession.validation ?? OcrMrzValidation();
          //     currentVal.nationalityValid = isValidMrzCountry(nationalityStr);
          //     updatedSession = updatedSession.copyWith(step: 3, details: 'Found nationality', nationality: nationalityStr, type: type, line1: line1, line2: normalize(l), line3: line3, validation: currentVal);
          //   }
          // }
        }
      } else {
        final parts = updatedSession.dateSexStr!.split(RegExp(r'[^0-9]+'));
        String birth = parts[0];
        String natBirth = "${updatedSession.nationality}$birth";
        String natOnly = "${updatedSession.nationality}";

        // final numberBeforeNatReg = RegExp(r'^(.*?)(?=' + RegExp.escape(natBirth) + r')');
        final numberBeforeNatReg = RegExp(r'([A-Z0-9<]{9,12})(\d)(?=' + RegExp.escape(natOnly) + r')');
        for (var l in lines) {
          int index = lines.indexOf(l);
          final numberBeforeNatMatch = numberBeforeNatReg.firstMatch(normalize(l));
          if (numberBeforeNatMatch != null && index != 0) {
            // log("we have before ${countryBeforeBirthMatch.group(0)}");
            numberStr = numberBeforeNatMatch.group(1)!.replaceAll("O", '0').replaceAll("<", '');
            String numberStrCheck = numberBeforeNatMatch.group(2)!;
            bool docNumberValid = _computeMrzCheckDigit(numberStr!) == numberStrCheck;
            var currentVal = updatedSession.validation!;
            currentVal.docNumberValid = docNumberValid;

            String firstLineGuess = lines[index - 1];
            if (firstLineGuess.length > 5) {
              String firstFiveChars = firstLineGuess.substring(0, 5);
              String docCode = firstFiveChars.substring(0, 2);
              String countryCode = firstFiveChars.substring(2, 5);
              bool validCode = DocumentCodeHelper.isValid(docCode);
              bool validCountry = isValidMrzCountry(countryCode);

              if (validCode && validCountry) {
                currentVal.countryValid = validCountry;
                currentVal.docCodeValid = validCode;
                currentVal.finalCheckValid = true;
                currentVal.personalNumberValid = true;
                currentVal.linesLengthValid = true;
                updatedSession = updatedSession.copyWith(
                  step: 4,
                  details: "Found Number Code Country : $numberStr",
                  line2: normalizeWithLength('${updatedSession.docNumber}${numberStrCheck}${updatedSession.dateSexStr}${updatedSession.optional ?? ''}', len: 44),
                  countryCode: countryCode,
                  docCode: docCode,
                  docNumber: numberStr,
                  validation: currentVal,
                  nationality: fixAlphaOnlyField(natOnly),
                  numberCheck: numberStrCheck,
                  logDetails: "Found valid Number: $numberStr Country: $countryCode DocCode $docCode",
                );
              }
            }

            // log("numberStr $numberStr");
            // log("numberStrCheck $numberStrCheck");
          }

          // if (nationalityStr != null) {
          //   if (isValidMrzCountry(nationalityStr)) {
          //     var currentVal = updatedSession.validation ?? OcrMrzValidation();
          //     currentVal.nationalityValid = isValidMrzCountry(nationalityStr);
          //     updatedSession = updatedSession.copyWith(step: 3, details: 'Found nationality', nationality: nationalityStr, type: type, line1: line1, line2: normalize(l), line3: line3, validation: currentVal);
          //   }
          // }
        }
      }
    }

    // if (updatedSession.step == 4) {
    //   String? numberStr;
    //   if (updatedSession.type == DocumentStandardType.td1) {
    //   } else {
    //     for (var l in lines) {
    //       int index = lines.indexOf(l);
    //       if (l.startsWith(updatedSession.docNumber!) && index > 0) {
    //         String line1 = fixAlphaOnlyField(lines[index - 1]);
    //         if (line1.length > 13) {
    //           String firstFiveChars = line1.substring(0, 5);
    //           String docCode = firstFiveChars.substring(0, 2);
    //           String countryCode = firstFiveChars.substring(2, 5);
    //           bool validCode = DocumentCodeHelper.isValid(docCode);
    //           bool validCountry = isValidMrzCountry(countryCode);
    //           var currentVal = updatedSession.validation!;
    //           currentVal.countryValid = validCountry;
    //           currentVal.docCodeValid = validCode;
    //
    //           if (validCountry && validCode) {
    //             updatedSession = updatedSession.copyWith(step: 5, details: 'Found nationality', line1: normalize(line1), line2: l, countryCode: countryCode, docCode: docCode);
    //           }
    //         }
    //       }
    //     }
    //   }
    // }

    if (updatedSession.step == 4) {
      if (updatedSession.type == "td1") {
        if(lines.length>2){
          String line3 = lines[2];
          MrzName? name = parseNamesTd1(line3);
          String firstName = name.givenNames.join(" ");
          String lastName = name.surname;
          List<String> otherLines = [...lines.where((a) => a != line3).map((a) => normalize(a))];
          var currentVal = updatedSession.validation ?? OcrMrzValidation();
          var(a,_,__) = name.validateNames(otherLines,OcrMrzSetting(nameValidationMode: NameValidationMode.exact),[]);
          currentVal.nameValid = a;
          updatedSession = updatedSession.copyWith(step: 5, details: 'Found names', line3: normalize(line3), firstName: firstName, lastName: lastName, validation: currentVal, logDetails: "Found Name: $firstName  $lastName");
        }
      } else {
        String line1Start = updatedSession.docCode! + updatedSession.countryCode!;

        for (var l in lines) {
          if (l.startsWith(line1Start)) {
            MrzName? name = parseNamesTd3OrTd2(l);
            String firstName = name.givenNames.join(" ");
            String lastName = name.surname;
            List<String> otherLines = [...lines.where((a) => a != l).map((a) => normalize(a))];
            var currentVal = updatedSession.validation ?? OcrMrzValidation();
            var(a,_,__)= name.validateNames(otherLines,OcrMrzSetting(nameValidationMode: NameValidationMode.exact),[]);
            currentVal.nameValid = a;
            updatedSession = updatedSession.copyWith(step: 5, details: 'Found names', line1: normalize(l), firstName: firstName, lastName: lastName, validation: currentVal, logDetails: "Found Name: $firstName  $lastName");
          }
        }
      }
    }

    // if (updatedSession.step == 6) {
    //   if (updatedSession.type == DocumentStandardType.td1) {
    //   } else {
    //     final optionalAndFinalCheckReg = RegExp(r'^(.*?<+)(\d{0,2})$');
    //     // String datesSex = updatedSession.dateSexStr!;
    //     String expWithCheck = updatedSession.expiryDate! + updatedSession.expCheck!;
    //     for (var l in baseLines) {
    //       l = normalize(l);
    //       if (l.length > 20) {
    //         List<String> parts = l.split(expWithCheck);
    //         if (parts.length > 1) {
    //           String optionalAndFinalGuess = parts[1];
    //           final optionalAndFinalCheckMatch = optionalAndFinalCheckReg.firstMatch(optionalAndFinalGuess);
    //           if (optionalAndFinalCheckMatch != null) {
    //             String optionalStr = optionalAndFinalCheckMatch.group(1)!;
    //             String finalCheckStr = optionalAndFinalCheckMatch.group(2)!;
    //
    //             bool finalCheckValid = (updatedSession.getFinalCheckValue)==_computeMrzCheckDigit(finalCheckStr);
    //             var currentVal = updatedSession.validation!;
    //             currentVal.finalCheckValid = finalCheckValid;
    //             if(finalCheckValid) {
    //               updatedSession = updatedSession.copyWith(step: 7, details: 'Found Final Check', optional: optionalStr, finalCheck: finalCheckStr);
    //             }else{
    //               log("final check not valid ==> ${updatedSession.getFinalCheckValue} ${finalCheckStr}");
    //             }
    //
    //           }
    //         }
    //       }
    //     }
    //   }
    // }

    // log("${updatedSession.step} ${updatedSession.logDetails??''}");
    return updatedSession;
  } catch (e) {
    if (e is Error) {
      log("$e\n${e.stackTrace}");
    }
    rethrow;
  }
}