static async Task ComposePatientBlock(TextWriter writer, Func<int> lineNumberGetter, Action<int> lineNumberSetter, Patient patient, bool lab) { var lineNumber = lineNumberGetter(); //Lijn 1: aanduiding begin van een aanvraag formaat: #A (eventueel gevolgd het rijksregisternummer van de patient of bij gebrek hieraan het Medidoc dossiernummer van de patiënt zie appendix A voor de vorming van het Medidoc dossiernummer) lineNumber++; await writer.WriteLineAsync(string.Concat("#A", patient.Id)); //Lijn 2: naam en voornaam van de patiënt lineNumber++; await writer.WriteLineAsync(string.Concat(patient.LastName?.TrimToMaxSize(24).PadRight(24) ?? string.Empty, patient.FirstName).TrimToMaxSize(40)); //Lijn 3: geboortedatum patiënt //formaat: JJJJMMDD lineNumber++; await writer.WriteLineAsync(patient.BirthDate?.ToString("yyyyMMdd")); //Lijn 4: geslacht patiënt //formaat: X, of Y, of Z lineNumber++; switch (patient.Sex) { case Sex.male: await writer.WriteLineAsync("Y"); break; case Sex.female: await writer.WriteLineAsync("X"); break; default: await writer.WriteLineAsync("Z"); break; } //Lijn 5: datum van de aanvraag //formaat: JJJJMMDD lineNumber++; await writer.WriteLineAsync(patient.RequestDate?.ToString("yyyyMMdd")); //(Lijn 6: referentienummer aanvraag //formaat: max 14 karakters. lineNumber++; await writer.WriteLineAsync(patient.ReferenceNumber?.TrimToMaxSize(14)); if (lab) { //Lijn 7: protocol code //formaat: 1 karakter, zijnde: P indien partieel protocol; C indien volledig protocol; S indien aanvulling van een partieel; L indien het de laatste aanvulling is lineNumber++; switch (patient.ProtocolCode) { case ProtocolCode.Partial: await writer.WriteLineAsync("P"); break; case ProtocolCode.Full: await writer.WriteLineAsync("C"); break; case ProtocolCode.Adition: await writer.WriteLineAsync("S"); break; case ProtocolCode.LastAdition: await writer.WriteLineAsync("L"); break; default: await writer.WriteLineAsync(); break; } } else { //(lijn 7:)Episodenummer (positie 1-14); legt verband tussen meerdere onderzoeken //mag blanco gelaten worden lineNumber++; await writer.WriteLineAsync(patient.EpisodeNumber?.TrimToMaxSize(14)); } //(lijn 1-7 zijn obligaat, de volgende lijnen mogen weggelaten worden) //(lijn 8:)Straat (positie 1-24) + nr (positie 25-31) if (!string.IsNullOrEmpty(patient.Address?.Street)) { lineNumber++; await writer.WriteLineAsync(string.Concat(patient.Address?.Street?.TrimToMaxSize(24).PadRight(24) ?? string.Empty, patient.Address?.HouseNr).TrimToMaxSize(31)); } //(lijn 9:)Postcode (positie 1-7) if (!string.IsNullOrEmpty(patient.Address?.PostalCode)) { lineNumber++; await writer.WriteLineAsync(patient.Address?.PostalCode?.TrimToMaxSize(7)); } //(lijn 10:)Gemeente (positie 1-24) if (!string.IsNullOrEmpty(patient.Address?.Town)) { lineNumber++; await writer.WriteLineAsync(patient.Address?.Town?.TrimToMaxSize(24)); } foreach (var result in patient.Results) await ComposeResultBlock(writer, () => lineNumber, (ln) => lineNumber = ln, result); lineNumber++; await writer.WriteLineAsync("#A/"); lineNumberSetter(lineNumber); }
static async Task<Patient> ParsePatientBlock(TextReader reader, Func<int> lineNumberGetter, Action<int> lineNumberSetter, IDictionary<int, IList<string>> parserErrors, string firstLine, bool lab) { var patient = new Patient(); var lineNumber = lineNumberGetter(); //Lijn 1: aanduiding begin van een aanvraag formaat: #A (eventueel gevolgd het rijksregisternummer van de patient of bij gebrek hieraan het Medidoc dossiernummer van de patiënt zie appendix A voor de vorming van het Medidoc dossiernummer) if (firstLine.Length > 2) { var id = firstLine.Substring(2); if (id.Length == 11) { if (!id.IsValidSocialSecurityNumber()) parserErrors.AddItem(lineNumber, $"Not a valid SSN: '{id}'"); } else if (id.Length == 13) { if (id == null || !Regex.Match(id.Trim(), @"\d{6}[XYZ][A-Z.]{6}", RegexOptions.IgnoreCase).Success) parserErrors.AddItem(lineNumber, $"Not a valid Medidoc dossiernummer: '{id}'"); } else { parserErrors.AddItem(lineNumber, $"Invalid patient id '{firstLine}'"); } patient.Id = id?.Trim(); } //Lijn 2: naam en voornaam van de patiënt lineNumber++; var name = (await reader.ReadLineAsync())?.CheckMaxSize(40, parserErrors, lineNumber); patient.LastName = name?.Substring(0, name.Length > 24 ? 24 : name.Length).Trim(); if (name?.Length > 24) patient.FirstName = name?.Substring(24).Trim(); //Lijn 3: geboortedatum patiënt //formaat: JJJJMMDD lineNumber++; patient.BirthDate = (await reader.ReadLineAsync())?.CheckMaxSize(8, parserErrors, lineNumber).ToNullableDatetime("yyyyMMdd", "yyMMdd"); //Lijn 4: geslacht patiënt //formaat: X, of Y, of Z lineNumber++; switch ((await reader.ReadLineAsync())?.CheckMaxSize(1, parserErrors, lineNumber)) { case "X": patient.Sex = Sex.female; break; case "Y": patient.Sex = Sex.male; break; default: patient.Sex = Sex.unknown; break; } //Lijn 5: datum van de aanvraag //formaat: JJJJMMDD lineNumber++; patient.RequestDate = (await reader.ReadLineAsync())?.CheckMaxSize(8, parserErrors, lineNumber).ToNullableDatetime("yyyyMMdd", "yyMMdd"); //(Lijn 6: referentienummer aanvraag //formaat: max 14 karakters. lineNumber++; patient.ReferenceNumber = (await reader.ReadLineAsync())?.CheckMaxSize(14, parserErrors, lineNumber).Trim(); if (lab) { //Lijn 7: protocol code //formaat: 1 karakter, zijnde: P indien partieel protocol; C indien volledig protocol; S indien aanvulling van een partieel; L indien het de laatste aanvulling is lineNumber++; var protocolCode = (await reader.ReadLineAsync())?.CheckMaxSize(1, parserErrors, lineNumber); switch (protocolCode) { case "P": patient.ProtocolCode = ProtocolCode.Partial; break; case "C": patient.ProtocolCode = ProtocolCode.Full; break; case "S": patient.ProtocolCode = ProtocolCode.Adition; break; case "L": patient.ProtocolCode = ProtocolCode.LastAdition; break; default: parserErrors.AddItem(lineNumber, string.Format($"'{protocolCode}' is not a valid protocol code (only P,C,S and L) are allowed.")); break; } } else { //(lijn 7:)Episodenummer (positie 1-14); legt verband tussen meerdere onderzoeken //mag blanco gelaten worden lineNumber++; patient.EpisodeNumber = (await reader.ReadLineAsync())?.CheckMaxSize(14, parserErrors, lineNumber).Trim(); } //(lijn 1-7 zijn obligaat, de volgende lijnen mogen weggelaten worden) lineNumber++; var line = await reader.ReadLineAsync(); if (line != null && !line.StartsWith(@"#R")) { //(lijn 8:)Straat (positie 1-24) + nr (positie 25-31) var address = line?.CheckMaxSize(31, parserErrors, lineNumber); patient.Address.Street = address?.Substring(0, address.Length > 24 ? 24 : address.Length).Trim(); if (address?.Length > 24) patient.Address.HouseNr = address?.Substring(24).Trim(); lineNumber++; line = await reader.ReadLineAsync(); if (line != null && !line.StartsWith(@"#R")) { //(lijn 9:)Postcode (positie 1-7) patient.Address.PostalCode = line?.CheckMaxSize(7, parserErrors, lineNumber).Trim(); lineNumber++; line = await reader.ReadLineAsync(); if (line != null && !line.StartsWith(@"#R")) { //(lijn 10:)Gemeente (positie 1-24) patient.Address.Town = line?.CheckMaxSize(24, parserErrors, lineNumber).Trim(); } } } if (line != null && !line.StartsWith(@"#R")) { //(lijn 11 en volgende: in voorbereiding voor mut-gegevens, enz) lineNumber++; while ((line = (await reader.ReadLineAsync())) != null && !line.StartsWith(@"#R")) { lineNumber++; } } do { if (line == null || !line.StartsWith("#R")) parserErrors.AddItem(lineNumber, $"Not valid start of result block expected '#R' but got '{line}'"); if (line != null) patient.Results.Add(await ParseResultBlock(reader, () => lineNumber, (ln) => lineNumber = ln, parserErrors, line)); lineNumber++; } while ((line = (await reader.ReadLineAsync())) != null && !line.StartsWith(@"#A/")); lineNumberSetter(lineNumber); return patient; }