import { GenericDocument, Field } from './GenericDocument';

/// All possible root document types.
export type BarcodeDocumentModelRootType =
  | typeof BoardingPassDocumentType
  | typeof SwissQRDocumentType
  | typeof DEMedicalPlanDocumentType
  | typeof IDCardPDF417DocumentType
  | typeof GS1DocumentType
  | typeof SEPADocumentType
  | typeof MedicalCertificateDocumentType
  | typeof VCardDocumentType
  | typeof AAMVADocumentType;

export const BoardingPassDocumentType = 'BoardingPass';
export const BoardingPassLegDocumentType = 'Leg';
export const SwissQRDocumentType = 'SwissQR';
export const DEMedicalPlanDocumentType = 'DEMedicalPlan';
export const DEMedicalPlanPatientDocumentType = 'Patient';
export const DEMedicalPlanDoctorDocumentType = 'Doctor';
export const DEMedicalPlanSubheadingDocumentType = 'Subheading';
export const DEMedicalPlanSubheadingMedicineDocumentType = 'Medicine';
export const DEMedicalPlanSubheadingMedicineSubstanceDocumentType = 'Substance';
export const DEMedicalPlanSubheadingPrescriptionDocumentType = 'Prescription';
export const IDCardPDF417DocumentType = 'IDCardPDF417';
export const GS1DocumentType = 'GS1';
export const GS1ElementDocumentType = 'Element';
export const GS1ElementValidationErrorDocumentType = 'ValidationError';
export const SEPADocumentType = 'SEPA';
export const MedicalCertificateDocumentType = 'MedicalCertificate';
export const VCardDocumentType = 'VCard';
export const VCardEntryDocumentType = 'Entry';
export const VCardVersionDocumentType = 'Version';
export const VCardSourceDocumentType = 'Source';
export const VCardKindDocumentType = 'Kind';
export const VCardXMLDocumentType = 'XML';
export const VCardNameDocumentType = 'Name';
export const VCardFirstNameDocumentType = 'FirstName';
export const VCardNicknameDocumentType = 'Nickname';
export const VCardBirthdayDocumentType = 'Birthday';
export const VCardAnniversaryDocumentType = 'Anniversary';
export const VCardGenderDocumentType = 'Gender';
export const VCardDeliveryAddressDocumentType = 'DeliveryAddress';
export const VCardPhotoDocumentType = 'Photo';
export const VCardTelephoneNumberDocumentType = 'TelephoneNumber';
export const VCardEmailDocumentType = 'Email';
export const VCardIMPPDocumentType = 'IMPP';
export const VCardLanguagesDocumentType = 'Languages';
export const VCardTimeZoneDocumentType = 'TimeZone';
export const VCardGeoLocationDocumentType = 'GeoLocation';
export const VCardTitleDocumentType = 'Title';
export const VCardRoleDocumentType = 'Role';
export const VCardLogoDocumentType = 'Logo';
export const VCardOrganisationDocumentType = 'Organisation';
export const VCardMemberDocumentType = 'Member';
export const VCardRelatedDocumentType = 'Related';
export const VCardCategoriesDocumentType = 'Categories';
export const VCardNoteDocumentType = 'Note';
export const VCardProductIdDocumentType = 'ProductId';
export const VCardRevisionDocumentType = 'Revision';
export const VCardSoundDocumentType = 'Sound';
export const VCardUIDDocumentType = 'UID';
export const VCardClientPIDMapDocumentType = 'ClientPIDMap';
export const VCardURLDocumentType = 'URL';
export const VCardPublicKeyDocumentType = 'PublicKey';
export const VCardBusyTimeURLDocumentType = 'BusyTimeURL';
export const VCardCalendarURIForRequestsDocumentType = 'CalendarURIForRequests';
export const VCardCalendarURIDocumentType = 'CalendarURI';
export const VCardCustomDocumentType = 'Custom';
export const AAMVADocumentType = 'AAMVA';
export const AAMVATitleDataDocumentType = 'TitleData';
export const AAMVARegistrationDataDocumentType = 'RegistrationData';
export const AAMVAMotorCarrierDataDocumentType = 'MotorCarrierData';
export const AAMVARegistrantAndVehicleDataDocumentType = 'RegistrantAndVehicleData';
export const AAMVAVehicleOwnerDataDocumentType = 'VehicleOwnerData';
export const AAMVAVehicleDataDocumentType = 'VehicleData';
export const AAMVAVehicleSafetyInspectionDataDocumentType = 'VehicleSafetyInspectionData';
export const AAMVADLIDDocumentType = 'DLID';
export const AAMVADriverLicenseDocumentType = 'DriverLicense';
export const AAMVAIDCardDocumentType = 'IDCard';
export const AAMVAEnhancedDriverLicenseDocumentType = 'EnhancedDriverLicense';
export const AAMVARawDocumentDocumentType = 'RawDocument';

/** Boarding Pass */
export class BoardingPass {
  private _document: GenericDocument;

  get document(): GenericDocument {
    return this._document;
  }

  constructor(document: GenericDocument) {
    if (document.type.name !== this.requiredDocumentType()) {
      throw new Error(
        `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
      );
    }

    this._document = document;
  }

  requiredDocumentType(): string {
    return BoardingPassDocumentType;
  }

  /** Electronic Ticket */
  get electronicTicket(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'ElectronicTicket') as Field;
  }

  /** Name */
  get name(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'Name') as Field;
  }

  /** Number Of Legs */
  get numberOfLegs(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'NumberOfLegs') as Field;
  }

  /** Security Data */
  get securityData(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'SecurityData') as Field;
  }

  /** An array of all children of type "Leg". */
  get legs(): BoardingPass.Leg[] {
    return this.document.children
      .filter((c: GenericDocument) => c.type.name === 'Leg')
      .map((c: GenericDocument) => new BoardingPass.Leg(c));
  }
}

export namespace BoardingPass {
  /** Leg of the journey */
  export class Leg {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return BoardingPassLegDocumentType;
    }

    /** Airline Designator Of Boarding Pass Issuer */
    get airlineDesignatorOfBoardingPassIssuer(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'AirlineDesignatorOfBoardingPassIssuer'
      );
    }

    /** Airline Numeric Code */
    get airlineNumericCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AirlineNumericCode');
    }

    /** Baggage Tag License Plate Numbers */
    get baggageTagLicensePlateNumbers(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'BaggageTagLicensePlateNumbers'
      );
    }

    /** Check In Sequence Number */
    get checkInSequenceNumber(): Field {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'CheckInSequenceNumber'
      ) as Field;
    }

    /** Compartment Code */
    get compartmentCode(): Field {
      return this.document.fields.find((f: Field) => f.type.name === 'CompartmentCode') as Field;
    }

    /** Date Of Boarding Pass Issuance Julian */
    get dateOfBoardingPassIssuanceJulian(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'DateOfBoardingPassIssuanceJulian'
      );
    }

    /** Date Of Flight Julian */
    get dateOfFlightJulian(): Field {
      return this.document.fields.find((f: Field) => f.type.name === 'DateOfFlightJulian') as Field;
    }

    /** Departure Airport Code */
    get departureAirportCode(): Field {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'DepartureAirportCode'
      ) as Field;
    }

    /** Destination Airport Code */
    get destinationAirportCode(): Field {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'DestinationAirportCode'
      ) as Field;
    }

    /** Document Form Serial Number */
    get documentFormSerialNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DocumentFormSerialNumber');
    }

    /** Document Type */
    get documentType(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DocumentType');
    }

    /** Fast Track */
    get fastTrack(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FastTrack');
    }

    /** First Non Consecutive Baggage Tag License Plate Number */
    get firstNonConsecutiveBaggageTagLicensePlateNumber(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'FirstNonConsecutiveBaggageTagLicensePlateNumber'
      );
    }

    /** Flight Number */
    get flightNumber(): Field {
      return this.document.fields.find((f: Field) => f.type.name === 'FlightNumber') as Field;
    }

    /** For Individual Airline Use */
    get forIndividualAirlineUse(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'ForIndividualAirlineUse');
    }

    /** Free Baggage Allowance */
    get freeBaggageAllowance(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FreeBaggageAllowance');
    }

    /** Frequent Flyer Airline Designator */
    get frequentFlyerAirlineDesignator(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'FrequentFlyerAirlineDesignator'
      );
    }

    /** Frequent Flyer Number */
    get frequentFlyerNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FrequentFlyerNumber');
    }

    /** IDAD Indicator */
    get idadIndicator(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'IDADIndicator');
    }

    /** International Documentation Verification */
    get internationalDocumentationVerification(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'InternationalDocumentationVerification'
      );
    }

    /** Marketing Carrier Designator */
    get marketingCarrierDesignator(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'MarketingCarrierDesignator');
    }

    /** Operating Carrier Designator */
    get operatingCarrierDesignator(): Field {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'OperatingCarrierDesignator'
      ) as Field;
    }

    /** Operating Carrier PNR Code */
    get operatingCarrierPNRCode(): Field {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'OperatingCarrierPNRCode'
      ) as Field;
    }

    /** Passenger Description */
    get passengerDescription(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PassengerDescription');
    }

    /** Passenger Status */
    get passengerStatus(): Field {
      return this.document.fields.find((f: Field) => f.type.name === 'PassengerStatus') as Field;
    }

    /** Seat Number */
    get seatNumber(): Field {
      return this.document.fields.find((f: Field) => f.type.name === 'SeatNumber') as Field;
    }

    /** Second Non Consecutive Baggage Tag License Plate Number */
    get secondNonConsecutiveBaggageTagLicensePlateNumber(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'SecondNonConsecutiveBaggageTagLicensePlateNumber'
      );
    }

    /** Selectee Indicator */
    get selecteeIndicator(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'SelecteeIndicator');
    }

    /** Source Of Boarding Pass Issuance */
    get sourceOfBoardingPassIssuance(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'SourceOfBoardingPassIssuance'
      );
    }

    /** Source Of Check In */
    get sourceOfCheckIn(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'SourceOfCheckIn');
    }

    /** VersionNumber */
    get versionNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VersionNumber');
    }
  }
}

/** SwissQR */
export class SwissQR {
  private _document: GenericDocument;

  get document(): GenericDocument {
    return this._document;
  }

  constructor(document: GenericDocument) {
    if (document.type.name !== this.requiredDocumentType()) {
      throw new Error(
        `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
      );
    }

    this._document = document;
  }

  requiredDocumentType(): string {
    return SwissQRDocumentType;
  }

  /** Additional Billing Information */
  get additionalBillingInformation(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'AdditionalBillingInformation');
  }

  /** Additional Info Trailer */
  get additionalInfoTrailer(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'AdditionalInfoTrailer');
  }

  /** Additional Info Unstructured */
  get additionalInfoUnstructured(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'AdditionalInfoUnstructured');
  }

  /** Alternative Procedure Parameter */
  get alternativeProcedureParameter(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'AlternativeProcedureParameter');
  }

  /** Amount */
  get amount(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'Amount');
  }

  /** Currency */
  get currency(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'Currency');
  }

  /** Debtor Address Type */
  get debtorAddressType(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'DebtorAddressType');
  }

  /** Debtor Building Or Address Line 2 */
  get debtorBuildingOrAddressLine2(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'DebtorBuildingOrAddressLine2');
  }

  /** Debtor Country */
  get debtorCountry(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'DebtorCountry');
  }

  /** Debtor Name */
  get debtorName(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'DebtorName');
  }

  /** Debtor Place */
  get debtorPlace(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'DebtorPlace');
  }

  /** Debtor Postal Code */
  get debtorPostalCode(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'DebtorPostalCode');
  }

  /** Debtor Street Or Address Line 1 */
  get debtorStreetOrAddressLine1(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'DebtorStreetOrAddressLine1');
  }

  /** Due Date */
  get dueDate(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'DueDate');
  }

  /** Encoding */
  get encoding(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'Encoding');
  }

  /** Final Payee Address Type */
  get finalPayeeAddressType(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'FinalPayeeAddressType');
  }

  /** Final Payee Building Or Address Line 2 */
  get finalPayeeBuildingOrAddressLine2(): Field | undefined {
    return this.document.fields.find(
      (f: Field) => f.type.name === 'FinalPayeeBuildingOrAddressLine2'
    );
  }

  /** Final Payee Country */
  get finalPayeeCountry(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'FinalPayeeCountry');
  }

  /** Final Payee Name */
  get finalPayeeName(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'FinalPayeeName');
  }

  /** Final Payee Place */
  get finalPayeePlace(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'FinalPayeePlace');
  }

  /** Final Payee Postal Code */
  get finalPayeePostalCode(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'FinalPayeePostalCode');
  }

  /** Final Payee Street Or Address Line 1 */
  get finalPayeeStreetOrAddressLine1(): Field | undefined {
    return this.document.fields.find(
      (f: Field) => f.type.name === 'FinalPayeeStreetOrAddressLine1'
    );
  }

  /** IBAN */
  get iban(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'IBAN');
  }

  /** Payee Address Type */
  get payeeAddressType(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'PayeeAddressType');
  }

  /** Payee Building Or Address Line 2 */
  get payeeBuildingOrAddressLine2(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'PayeeBuildingOrAddressLine2');
  }

  /** Payee Country */
  get payeeCountry(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'PayeeCountry');
  }

  /** Payee Name */
  get payeeName(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'PayeeName');
  }

  /** Payee Place */
  get payeePlace(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'PayeePlace');
  }

  /** Payee Postal Code */
  get payeePostalCode(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'PayeePostalCode');
  }

  /** Payee Street Or Address Line 1 */
  get payeeStreetOrAddressLine1(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'PayeeStreetOrAddressLine1');
  }

  /** Payment Reference */
  get paymentReference(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'PaymentReference');
  }

  /** Payment Reference Type */
  get paymentReferenceType(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'PaymentReferenceType');
  }

  /** Version */
  get version(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'Version') as Field;
  }
}

/** Medical Plan */
export class DEMedicalPlan {
  private _document: GenericDocument;

  get document(): GenericDocument {
    return this._document;
  }

  constructor(document: GenericDocument) {
    if (document.type.name !== this.requiredDocumentType()) {
      throw new Error(
        `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
      );
    }

    this._document = document;
  }

  requiredDocumentType(): string {
    return DEMedicalPlanDocumentType;
  }

  /** Current Page */
  get currentPage(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'CurrentPage') as Field;
  }

  /** Document Version Number */
  get documentVersionNumber(): Field {
    return this.document.fields.find(
      (f: Field) => f.type.name === 'DocumentVersionNumber'
    ) as Field;
  }

  /** GUID */
  get guid(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'GUID') as Field;
  }

  /** Language Country Code */
  get languageCountryCode(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'LanguageCountryCode') as Field;
  }

  /** Patch Version Number */
  get patchVersionNumber(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'PatchVersionNumber') as Field;
  }

  /** Total Number Of Pages */
  get totalNumberOfPages(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'TotalNumberOfPages') as Field;
  }

  /** The child document of type "Patient". */
  get patient(): DEMedicalPlan.Patient {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Patient');
    return new DEMedicalPlan.Patient(child as GenericDocument);
  }

  /** The child document of type "Doctor". */
  get doctor(): DEMedicalPlan.Doctor {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Doctor');
    return new DEMedicalPlan.Doctor(child as GenericDocument);
  }

  /** An array of all children of type "Subheading". */
  get subheadings(): DEMedicalPlan.Subheading[] {
    return this.document.children
      .filter((c: GenericDocument) => c.type.name === 'Subheading')
      .map((c: GenericDocument) => new DEMedicalPlan.Subheading(c));
  }
}

export namespace DEMedicalPlan {
  /** Patient */
  export class Patient {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return DEMedicalPlanPatientDocumentType;
    }

    /** Allergies And Intolerances */
    get allergiesAndIntolerances(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AllergiesAndIntolerances');
    }

    /** Birth Date */
    get birthDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'BirthDate');
    }

    /** Breast Feeding */
    get breastFeeding(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'BreastFeeding');
    }

    /** Creatinine Value */
    get creatinineValue(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'CreatinineValue');
    }

    /** First Name */
    get firstName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FirstName');
    }

    /** Gender */
    get gender(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Gender');
    }

    /** Height */
    get height(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Height');
    }

    /** Last Name */
    get lastName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'LastName');
    }

    /** Patient Free Text */
    get patientFreeText(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PatientFreeText');
    }

    /** Patient ID */
    get patientID(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PatientID');
    }

    /** Pre Name */
    get preName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PreName');
    }

    /** Pregnant */
    get pregnant(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Pregnant');
    }

    /** Name Suffix */
    get suffix(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Suffix');
    }

    /** Title */
    get title(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Title');
    }

    /** Weight */
    get weight(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Weight');
    }
  }

  /** Doctor */
  export class Doctor {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return DEMedicalPlanDoctorDocumentType;
    }

    /** Doctor Number */
    get doctorNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DoctorNumber');
    }

    /** Email */
    get email(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Email');
    }

    /** Hospital ID */
    get hospitalID(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'HospitalID');
    }

    /** Issuer Name */
    get issuerName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'IssuerName');
    }

    /** Issuing Date And Time */
    get issuingDateAndTime(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'IssuingDateAndTime');
    }

    /** Pharmacy ID */
    get pharmacyID(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PharmacyID');
    }

    /** Place */
    get place(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Place');
    }

    /** Postal Code */
    get postalCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PostalCode');
    }

    /** Street */
    get street(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Street');
    }

    /** Telephone Number */
    get telephoneNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'TelephoneNumber');
    }
  }

  /** Subheading */
  export class Subheading {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return DEMedicalPlanSubheadingDocumentType;
    }

    /** General Note */
    get generalNotes(): Field[] {
      return this.document.fields.filter((f: Field) => f.type.name === 'GeneralNote');
    }

    /** Key Words */
    get keyWords(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'KeyWords');
    }

    /** Subheading Free Text */
    get subheadingFreeText(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'SubheadingFreeText');
    }

    /** An array of all children of type "Medicine". */
    get medicines(): DEMedicalPlan.Subheading.Medicine[] {
      return this.document.children
        .filter((c: GenericDocument) => c.type.name === 'Medicine')
        .map((c: GenericDocument) => new DEMedicalPlan.Subheading.Medicine(c));
    }

    /** An array of all children of type "Prescription". */
    get prescriptions(): DEMedicalPlan.Subheading.Prescription[] {
      return this.document.children
        .filter((c: GenericDocument) => c.type.name === 'Prescription')
        .map((c: GenericDocument) => new DEMedicalPlan.Subheading.Prescription(c));
    }
  }

  export namespace Subheading {
    /** Medicine */
    export class Medicine {
      private _document: GenericDocument;

      get document(): GenericDocument {
        return this._document;
      }

      constructor(document: GenericDocument) {
        if (document.type.name !== this.requiredDocumentType()) {
          throw new Error(
            `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
          );
        }

        this._document = document;
      }

      requiredDocumentType(): string {
        return DEMedicalPlanSubheadingMedicineDocumentType;
      }

      /** Dosage Form */
      get dosageForm(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'DosageForm');
      }

      /** Dosage Form Free Text */
      get dosageFormFreeText(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'DosageFormFreeText');
      }

      /** Dosage Free Text */
      get dosageFreeText(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'DosageFreeText');
      }

      /** Dosing Unit */
      get dosingUnit(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'DosingUnit');
      }

      /** Dosing Unit Free Text */
      get dosingUnitFreeText(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'DosingUnitFreeText');
      }

      /** Drug Name */
      get drugName(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'DrugName');
      }

      /** Evening Intake Dose */
      get evening(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'Evening');
      }

      /** General Notes */
      get generalNotes(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'GeneralNotes');
      }

      /** Midday Intake Dose */
      get midday(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'Midday');
      }

      /** Morning Intake Dose */
      get morning(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'Morning');
      }

      /** Night Intake Dose */
      get night(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'Night');
      }

      /** Pharmaceutical Number */
      get pharmaceuticalNumber(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'PharmaceuticalNumber');
      }

      /** Reason For Treatment */
      get reasonForTreatment(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'ReasonForTreatment');
      }

      /** Relevant Info */
      get relevantInfo(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'RelevantInfo');
      }

      /** An array of all children of type "Substance". */
      get substances(): DEMedicalPlan.Subheading.Medicine.Substance[] {
        return this.document.children
          .filter((c: GenericDocument) => c.type.name === 'Substance')
          .map((c: GenericDocument) => new DEMedicalPlan.Subheading.Medicine.Substance(c));
      }
    }

    export namespace Medicine {
      /** Substance */
      export class Substance {
        private _document: GenericDocument;

        get document(): GenericDocument {
          return this._document;
        }

        constructor(document: GenericDocument) {
          if (document.type.name !== this.requiredDocumentType()) {
            throw new Error(
              `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
            );
          }

          this._document = document;
        }

        requiredDocumentType(): string {
          return DEMedicalPlanSubheadingMedicineSubstanceDocumentType;
        }

        /** Active Substance */
        get activeSubstance(): Field | undefined {
          return this.document.fields.find((f: Field) => f.type.name === 'ActiveSubstance');
        }

        /** Potency */
        get potency(): Field | undefined {
          return this.document.fields.find((f: Field) => f.type.name === 'Potency');
        }
      }
    }

    /** Prescription */
    export class Prescription {
      private _document: GenericDocument;

      get document(): GenericDocument {
        return this._document;
      }

      constructor(document: GenericDocument) {
        if (document.type.name !== this.requiredDocumentType()) {
          throw new Error(
            `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
          );
        }

        this._document = document;
      }

      requiredDocumentType(): string {
        return DEMedicalPlanSubheadingPrescriptionDocumentType;
      }

      /** General Information */
      get generalInformation(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'GeneralInformation');
      }

      /** Prescription Free Text */
      get prescriptionFreeText(): Field | undefined {
        return this.document.fields.find((f: Field) => f.type.name === 'PrescriptionFreeText');
      }
    }
  }
}

/** ID Card */
export class IDCardPDF417 {
  private _document: GenericDocument;

  get document(): GenericDocument {
    return this._document;
  }

  constructor(document: GenericDocument) {
    if (document.type.name !== this.requiredDocumentType()) {
      throw new Error(
        `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
      );
    }

    this._document = document;
  }

  requiredDocumentType(): string {
    return IDCardPDF417DocumentType;
  }

  /** Birth Date. The format is ISO8601 with delimiters */
  get birthDate(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'BirthDate') as Field;
  }

  /** Date Expired. The format is ISO8601 with delimiters */
  get dateExpired(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'DateExpired') as Field;
  }

  /** Date Issued. The format is ISO8601 with delimiters */
  get dateIssued(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'DateIssued') as Field;
  }

  /** Document Code */
  get documentCode(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'DocumentCode') as Field;
  }

  /** First Name */
  get firstName(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'FirstName') as Field;
  }

  /** Last Name */
  get lastName(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'LastName') as Field;
  }

  /** Optional */
  get optional(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'Optional') as Field;
  }
}

/** GS1 */
export class GS1 {
  private _document: GenericDocument;

  get document(): GenericDocument {
    return this._document;
  }

  constructor(document: GenericDocument) {
    if (document.type.name !== this.requiredDocumentType()) {
      throw new Error(
        `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
      );
    }

    this._document = document;
  }

  requiredDocumentType(): string {
    return GS1DocumentType;
  }

  /** An array of all children of type "Element". */
  get elements(): GS1.Element[] {
    return this.document.children
      .filter((c: GenericDocument) => c.type.name === 'Element')
      .map((c: GenericDocument) => new GS1.Element(c));
  }
}

export namespace GS1 {
  /** GS1 Element */
  export class Element {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return GS1ElementDocumentType;
    }

    /** Application Identifier */
    get applicationIdentifier(): Field {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'ApplicationIdentifier'
      ) as Field;
    }

    /** Data Title */
    get dataTitle(): Field {
      return this.document.fields.find((f: Field) => f.type.name === 'DataTitle') as Field;
    }

    /** Description */
    get elementDescription(): Field {
      return this.document.fields.find((f: Field) => f.type.name === 'ElementDescription') as Field;
    }

    /** Raw Value */
    get rawValue(): Field {
      return this.document.fields.find((f: Field) => f.type.name === 'RawValue') as Field;
    }

    /** An array of all children of type "ValidationError". */
    get validationErrors(): GS1.Element.ValidationError[] {
      return this.document.children
        .filter((c: GenericDocument) => c.type.name === 'ValidationError')
        .map((c: GenericDocument) => new GS1.Element.ValidationError(c));
    }
  }

  export namespace Element {
    /** Validation Errors */
    export class ValidationError {
      private _document: GenericDocument;

      get document(): GenericDocument {
        return this._document;
      }

      constructor(document: GenericDocument) {
        if (document.type.name !== this.requiredDocumentType()) {
          throw new Error(
            `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
          );
        }

        this._document = document;
      }

      requiredDocumentType(): string {
        return GS1ElementValidationErrorDocumentType;
      }

      /** Error Code */
      get code(): Field {
        return this.document.fields.find((f: Field) => f.type.name === 'Code') as Field;
      }

      /** Reason */
      get reason(): Field {
        return this.document.fields.find((f: Field) => f.type.name === 'Reason') as Field;
      }
    }
  }
}

/** SEPA */
export class SEPA {
  private _document: GenericDocument;

  get document(): GenericDocument {
    return this._document;
  }

  constructor(document: GenericDocument) {
    if (document.type.name !== this.requiredDocumentType()) {
      throw new Error(
        `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
      );
    }

    this._document = document;
  }

  requiredDocumentType(): string {
    return SEPADocumentType;
  }

  /** Amount */
  get amount(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'Amount');
  }

  /** Character Set */
  get characterSet(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'CharacterSet') as Field;
  }

  /** Identification */
  get identification(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'Identification') as Field;
  }

  /** Information */
  get information(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'Information');
  }

  /** Amount */
  get purpose(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'Purpose');
  }

  /** Receiver BIC */
  get receiverBIC(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'ReceiverBIC') as Field;
  }

  /** Receiver IBAN */
  get receiverIBAN(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'ReceiverIBAN') as Field;
  }

  /** Receiver Name */
  get receiverName(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'ReceiverName') as Field;
  }

  /** Remittance */
  get remittance(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'Remittance');
  }

  /** Service Tag */
  get serviceTag(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'ServiceTag') as Field;
  }

  /** Version */
  get version(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'Version') as Field;
  }
}

/** Medical Certificate */
export class MedicalCertificate {
  private _document: GenericDocument;

  get document(): GenericDocument {
    return this._document;
  }

  constructor(document: GenericDocument) {
    if (document.type.name !== this.requiredDocumentType()) {
      throw new Error(
        `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
      );
    }

    this._document = document;
  }

  requiredDocumentType(): string {
    return MedicalCertificateDocumentType;
  }

  /** Accident */
  get accident(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'Accident');
  }

  /** Assigned To Accident Insurance Doctor */
  get assignedToAccidentInsuranceDoctor(): Field | undefined {
    return this.document.fields.find(
      (f: Field) => f.type.name === 'AssignedToAccidentInsuranceDoctor'
    );
  }

  /** Birth Date. The format is ISO8601 with delimiters */
  get birthDate(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'BirthDate');
  }

  /** Child Needs Care From */
  get childNeedsCareFrom(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'ChildNeedsCareFrom');
  }

  /** Child Needs Care Until */
  get childNeedsCareUntil(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'ChildNeedsCareUntil');
  }

  /** Diagnose */
  get diagnose(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'Diagnose');
  }

  /** Diagnosed On. The format is ISO8601 with delimiters */
  get diagnosedOn(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'DiagnosedOn');
  }

  /** Doctor Number */
  get doctorNumber(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'DoctorNumber');
  }

  /** Document Date. The format is ISO8601 with delimiters */
  get documentDate(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'DocumentDate');
  }

  /** First Name */
  get firstName(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'FirstName');
  }

  /** Health Insurance Number */
  get healthInsuranceNumber(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'HealthInsuranceNumber');
  }

  /** Incapable Of Work Since. The format is ISO8601 with delimiters */
  get incapableOfWorkSince(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'IncapableOfWorkSince');
  }

  /** Incapable Of Work Until. The format is ISO8601 with delimiters */
  get incapableOfWorkUntil(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'IncapableOfWorkUntil');
  }

  /** Initial Certificate */
  get initialCertificate(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'InitialCertificate');
  }

  /** Insured Person Number */
  get insuredPersonNumber(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'InsuredPersonNumber');
  }

  /** Last Name */
  get lastName(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'LastName');
  }

  /** Place Of Operation Number */
  get placeOfOperationNumber(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'PlaceOfOperationNumber');
  }

  /** Renewed Certificate */
  get renewedCertificate(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'RenewedCertificate');
  }

  /** Requires Care */
  get requiresCare(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'RequiresCare');
  }

  /** Status */
  get status(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'Status');
  }

  /** Work Accident */
  get workAccident(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'WorkAccident');
  }
}

/** VCard */
export class VCard {
  private _document: GenericDocument;

  get document(): GenericDocument {
    return this._document;
  }

  constructor(document: GenericDocument) {
    if (document.type.name !== this.requiredDocumentType()) {
      throw new Error(
        `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
      );
    }

    this._document = document;
  }

  requiredDocumentType(): string {
    return VCardDocumentType;
  }

  /** The child document of type "Version". */
  get version(): VCard.Version {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Version');
    return new VCard.Version(child as GenericDocument);
  }

  /** The child document of type "Source". */
  get source(): VCard.Source | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Source');
    return child ? new VCard.Source(child) : undefined;
  }

  /** The child document of type "Kind". */
  get kind(): VCard.Kind | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Kind');
    return child ? new VCard.Kind(child) : undefined;
  }

  /** The child document of type "XML". */
  get xml(): VCard.XML | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'XML');
    return child ? new VCard.XML(child) : undefined;
  }

  /** The child document of type "Name". */
  get name(): VCard.Name | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Name');
    return child ? new VCard.Name(child) : undefined;
  }

  /** The child document of type "FirstName". */
  get firstName(): VCard.FirstName | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'FirstName');
    return child ? new VCard.FirstName(child) : undefined;
  }

  /** The child document of type "Nickname". */
  get nickname(): VCard.Nickname | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Nickname');
    return child ? new VCard.Nickname(child) : undefined;
  }

  /** The child document of type "Birthday". */
  get birthday(): VCard.Birthday | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Birthday');
    return child ? new VCard.Birthday(child) : undefined;
  }

  /** The child document of type "Anniversary". */
  get anniversary(): VCard.Anniversary | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'Anniversary'
    );
    return child ? new VCard.Anniversary(child) : undefined;
  }

  /** The child document of type "Gender". */
  get gender(): VCard.Gender | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Gender');
    return child ? new VCard.Gender(child) : undefined;
  }

  /** The child document of type "DeliveryAddress". */
  get deliveryAddress(): VCard.DeliveryAddress | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'DeliveryAddress'
    );
    return child ? new VCard.DeliveryAddress(child) : undefined;
  }

  /** The child document of type "Photo". */
  get photo(): VCard.Photo | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Photo');
    return child ? new VCard.Photo(child) : undefined;
  }

  /** The child document of type "TelephoneNumber". */
  get telephoneNumber(): VCard.TelephoneNumber | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'TelephoneNumber'
    );
    return child ? new VCard.TelephoneNumber(child) : undefined;
  }

  /** The child document of type "Email". */
  get email(): VCard.Email | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Email');
    return child ? new VCard.Email(child) : undefined;
  }

  /** The child document of type "IMPP". */
  get impp(): VCard.IMPP | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'IMPP');
    return child ? new VCard.IMPP(child) : undefined;
  }

  /** The child document of type "Languages". */
  get languages(): VCard.Languages | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Languages');
    return child ? new VCard.Languages(child) : undefined;
  }

  /** The child document of type "TimeZone". */
  get timeZone(): VCard.TimeZone | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'TimeZone');
    return child ? new VCard.TimeZone(child) : undefined;
  }

  /** The child document of type "GeoLocation". */
  get geoLocation(): VCard.GeoLocation | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'GeoLocation'
    );
    return child ? new VCard.GeoLocation(child) : undefined;
  }

  /** The child document of type "Title". */
  get title(): VCard.Title | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Title');
    return child ? new VCard.Title(child) : undefined;
  }

  /** The child document of type "Role". */
  get role(): VCard.Role | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Role');
    return child ? new VCard.Role(child) : undefined;
  }

  /** The child document of type "Logo". */
  get logo(): VCard.Logo | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Logo');
    return child ? new VCard.Logo(child) : undefined;
  }

  /** The child document of type "Organisation". */
  get organisation(): VCard.Organisation | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'Organisation'
    );
    return child ? new VCard.Organisation(child) : undefined;
  }

  /** The child document of type "Member". */
  get member(): VCard.Member | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Member');
    return child ? new VCard.Member(child) : undefined;
  }

  /** The child document of type "Related". */
  get related(): VCard.Related | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Related');
    return child ? new VCard.Related(child) : undefined;
  }

  /** The child document of type "Categories". */
  get categories(): VCard.Categories | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Categories');
    return child ? new VCard.Categories(child) : undefined;
  }

  /** The child document of type "Note". */
  get note(): VCard.Note | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Note');
    return child ? new VCard.Note(child) : undefined;
  }

  /** The child document of type "ProductId". */
  get productId(): VCard.ProductId | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'ProductId');
    return child ? new VCard.ProductId(child) : undefined;
  }

  /** The child document of type "Revision". */
  get revision(): VCard.Revision | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Revision');
    return child ? new VCard.Revision(child) : undefined;
  }

  /** The child document of type "Sound". */
  get sound(): VCard.Sound | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'Sound');
    return child ? new VCard.Sound(child) : undefined;
  }

  /** The child document of type "UID". */
  get uid(): VCard.UID | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'UID');
    return child ? new VCard.UID(child) : undefined;
  }

  /** The child document of type "ClientPIDMap". */
  get clientPIDMap(): VCard.ClientPIDMap | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'ClientPIDMap'
    );
    return child ? new VCard.ClientPIDMap(child) : undefined;
  }

  /** The child document of type "URL". */
  get url(): VCard.URL | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'URL');
    return child ? new VCard.URL(child) : undefined;
  }

  /** The child document of type "PublicKey". */
  get publicKey(): VCard.PublicKey | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'PublicKey');
    return child ? new VCard.PublicKey(child) : undefined;
  }

  /** The child document of type "BusyTimeURL". */
  get busyTimeURL(): VCard.BusyTimeURL | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'BusyTimeURL'
    );
    return child ? new VCard.BusyTimeURL(child) : undefined;
  }

  /** The child document of type "CalendarURIForRequests". */
  get calendarURIForRequests(): VCard.CalendarURIForRequests | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'CalendarURIForRequests'
    );
    return child ? new VCard.CalendarURIForRequests(child) : undefined;
  }

  /** The child document of type "CalendarURI". */
  get calendarURI(): VCard.CalendarURI | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'CalendarURI'
    );
    return child ? new VCard.CalendarURI(child) : undefined;
  }

  /** An array of all children of type "Custom". */
  get customs(): VCard.Custom[] {
    return this.document.children
      .filter((c: GenericDocument) => c.type.name === 'Custom')
      .map((c: GenericDocument) => new VCard.Custom(c));
  }
}

export namespace VCard {
  /** VCard Entry */
  export abstract class Entry {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    abstract requiredDocumentType(): string;

    /** Raw Value */
    get rawValue(): Field {
      return this.document.fields.find((f: Field) => f.type.name === 'RawValue') as Field;
    }

    /** Type Modifier */
    get typeModifiers(): Field[] {
      return this.document.fields.filter((f: Field) => f.type.name === 'TypeModifier');
    }

    /** Value */
    get values(): Field[] {
      return this.document.fields.filter((f: Field) => f.type.name === 'Value');
    }
  }

  /** Version */
  export class Version extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardVersionDocumentType;
    }
  }

  /** Source */
  export class Source extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardSourceDocumentType;
    }
  }

  /** Kind */
  export class Kind extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardKindDocumentType;
    }
  }

  /** XML */
  export class XML extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardXMLDocumentType;
    }
  }

  /** Name */
  export class Name extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardNameDocumentType;
    }
  }

  /** First Name */
  export class FirstName extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardFirstNameDocumentType;
    }
  }

  /** Nickname */
  export class Nickname extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardNicknameDocumentType;
    }
  }

  /** Birthday */
  export class Birthday extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardBirthdayDocumentType;
    }
  }

  /** Anniversary */
  export class Anniversary extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardAnniversaryDocumentType;
    }
  }

  /** Gender */
  export class Gender extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardGenderDocumentType;
    }
  }

  /** Delivery Address */
  export class DeliveryAddress extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardDeliveryAddressDocumentType;
    }
  }

  /** Photo */
  export class Photo extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardPhotoDocumentType;
    }
  }

  /** Telephone Number */
  export class TelephoneNumber extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardTelephoneNumberDocumentType;
    }
  }

  /** Email */
  export class Email extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardEmailDocumentType;
    }
  }

  /** IMPP */
  export class IMPP extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardIMPPDocumentType;
    }
  }

  /** Languages */
  export class Languages extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardLanguagesDocumentType;
    }
  }

  /** Time Zone */
  export class TimeZone extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardTimeZoneDocumentType;
    }
  }

  /** Geo Location */
  export class GeoLocation extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardGeoLocationDocumentType;
    }
  }

  /** Title */
  export class Title extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardTitleDocumentType;
    }
  }

  /** Role */
  export class Role extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardRoleDocumentType;
    }
  }

  /** Logo */
  export class Logo extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardLogoDocumentType;
    }
  }

  /** Organisation */
  export class Organisation extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardOrganisationDocumentType;
    }
  }

  /** Member */
  export class Member extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardMemberDocumentType;
    }
  }

  /** Related */
  export class Related extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardRelatedDocumentType;
    }
  }

  /** Categories */
  export class Categories extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardCategoriesDocumentType;
    }
  }

  /** Note */
  export class Note extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardNoteDocumentType;
    }
  }

  /** ProductId */
  export class ProductId extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardProductIdDocumentType;
    }
  }

  /** Revision */
  export class Revision extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardRevisionDocumentType;
    }
  }

  /** Sound */
  export class Sound extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardSoundDocumentType;
    }
  }

  /** UID */
  export class UID extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardUIDDocumentType;
    }
  }

  /** Client PID Map */
  export class ClientPIDMap extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardClientPIDMapDocumentType;
    }
  }

  /** URL */
  export class URL extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardURLDocumentType;
    }
  }

  /** Public Key */
  export class PublicKey extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardPublicKeyDocumentType;
    }
  }

  /** Busy Time URL */
  export class BusyTimeURL extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardBusyTimeURLDocumentType;
    }
  }

  /** Calendar URI For Requests */
  export class CalendarURIForRequests extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardCalendarURIForRequestsDocumentType;
    }
  }

  /** Calendar URI */
  export class CalendarURI extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardCalendarURIDocumentType;
    }
  }

  /** Custom */
  export class Custom extends Entry {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return VCardCustomDocumentType;
    }
  }
}

/** AAMVA */
export class AAMVA {
  private _document: GenericDocument;

  get document(): GenericDocument {
    return this._document;
  }

  constructor(document: GenericDocument) {
    if (document.type.name !== this.requiredDocumentType()) {
      throw new Error(
        `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
      );
    }

    this._document = document;
  }

  requiredDocumentType(): string {
    return AAMVADocumentType;
  }

  /** Issuer Identification Number */
  get issuerIdentificationNumber(): Field {
    return this.document.fields.find(
      (f: Field) => f.type.name === 'IssuerIdentificationNumber'
    ) as Field;
  }

  /** Jurisdiction Version Number */
  get jurisdictionVersionNumber(): Field | undefined {
    return this.document.fields.find((f: Field) => f.type.name === 'JurisdictionVersionNumber');
  }

  /** Version */
  get version(): Field {
    return this.document.fields.find((f: Field) => f.type.name === 'Version') as Field;
  }

  /** The child document of type "TitleData". */
  get titleData(): AAMVA.TitleData | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'TitleData');
    return child ? new AAMVA.TitleData(child) : undefined;
  }

  /** The child document of type "RegistrationData". */
  get registrationData(): AAMVA.RegistrationData | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'RegistrationData'
    );
    return child ? new AAMVA.RegistrationData(child) : undefined;
  }

  /** The child document of type "MotorCarrierData". */
  get motorCarrierData(): AAMVA.MotorCarrierData | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'MotorCarrierData'
    );
    return child ? new AAMVA.MotorCarrierData(child) : undefined;
  }

  /** The child document of type "RegistrantAndVehicleData". */
  get registrantAndVehicleData(): AAMVA.RegistrantAndVehicleData | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'RegistrantAndVehicleData'
    );
    return child ? new AAMVA.RegistrantAndVehicleData(child) : undefined;
  }

  /** The child document of type "VehicleOwnerData". */
  get vehicleOwnerData(): AAMVA.VehicleOwnerData | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'VehicleOwnerData'
    );
    return child ? new AAMVA.VehicleOwnerData(child) : undefined;
  }

  /** The child document of type "VehicleData". */
  get vehicleData(): AAMVA.VehicleData | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'VehicleData'
    );
    return child ? new AAMVA.VehicleData(child) : undefined;
  }

  /** The child document of type "VehicleSafetyInspectionData". */
  get vehicleSafetyInspectionData(): AAMVA.VehicleSafetyInspectionData | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'VehicleSafetyInspectionData'
    );
    return child ? new AAMVA.VehicleSafetyInspectionData(child) : undefined;
  }

  /** The child document of type "DriverLicense". */
  get driverLicense(): AAMVA.DriverLicense | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'DriverLicense'
    );
    return child ? new AAMVA.DriverLicense(child) : undefined;
  }

  /** The child document of type "IDCard". */
  get idCard(): AAMVA.IDCard | undefined {
    const child = this.document.children.find((c: GenericDocument) => c.type.name === 'IDCard');
    return child ? new AAMVA.IDCard(child) : undefined;
  }

  /** The child document of type "EnhancedDriverLicense". */
  get enhancedDriverLicense(): AAMVA.EnhancedDriverLicense | undefined {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'EnhancedDriverLicense'
    );
    return child ? new AAMVA.EnhancedDriverLicense(child) : undefined;
  }

  /** The child document of type "RawDocument". */
  get rawDocument(): AAMVA.RawDocument {
    const child = this.document.children.find(
      (c: GenericDocument) => c.type.name === 'RawDocument'
    );
    return new AAMVA.RawDocument(child as GenericDocument);
  }
}

export namespace AAMVA {
  /** Title Data. File type "TD". */
  export class TitleData {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return AAMVATitleDataDocumentType;
    }

    /** Data element ID "NAT". City portion of the owner's address. */
    get addressCity(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressCity');
    }

    /** Data element ID "NAU". Jurisdiction portion of the owner's address. */
    get addressJurisdictionCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressJurisdictionCode');
    }

    /** Data element ID "NAR". Street portion of the owner's address. */
    get addressStreet(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressStreet');
    }

    /** Data element ID "NAV". The ZIP code or Postal code portion of the owner's address. */
    get addressZipCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressZipCode');
    }

    /** Data element ID "BBC". The name of business that owns the vehicle. */
    get businessName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'BusinessName');
    }

    /** Data element ID "NAA". Family name (commonly called surname or last name) of the owner of the vehicle. */
    get familyName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FamilyName');
    }

    /** Data element ID "LAF". A code that uniquely identifies the first holder of a lien. */
    get firstLienHolderId(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FirstLienHolderId');
    }

    /** Data element ID "LAA". Name of the first lien holder of the vehicle. */
    get firstLienHolderName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FirstLienHolderName');
    }

    /** Data element ID "NAE". Given name or names (includes all of what are commonly referred to as first and middle names) of the owner of the vehicle. */
    get givenName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'GivenName');
    }

    /** Data element ID "TAW". This code represents whether the vehicle/vessel is new or used. Note: jurisdictions' definitions of these classifications may vary a little due to state regulations on demo vehicles, slates between dealers, application of state taxes, etc. N = New, U = Used. */
    get newUsedIndicator(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'NewUsedIndicator');
    }

    /** Data element ID "TAH". The date the odometer reading was recorded by the jurisdiction. */
    get odometerDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'OdometerDate');
    }

    /** Data element ID "TAG". This is the federal odometer mileage disclosure. The mandatory information is: (1) Actual vehicle mileage; (2) Mileage exceeds mechanical limitations; (3) Not actual mileage; (4) Mileage disclosure not required. */
    get odometerDisclosure(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'OdometerDisclosure');
    }

    /** Data element ID "TAI". This is the odometer reading registered with the DMV either at the time of titling or registration renewal in kilometers. */
    get odometerReadingKilometers(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'OdometerReadingKilometers');
    }

    /** Data element ID "TAF". This is the odometer reading registered with the DMV either at the time of titling or registration renewal. */
    get odometerReadingMileage(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'OdometerReadingMileage');
    }

    /** Data element ID "TAZ". The title number assigned to the vehicle by the previous titling jurisdiction. */
    get previousTitleNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PreviousTitleNumber');
    }

    /** Data element ID "TPJ". The code for the jurisdiction (U.S., Canadian, or Mexican) that titled the vehicle immediately prior to the current titling jurisdiction. */
    get previousTitlingJurisdiction(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PreviousTitlingJurisdiction');
    }

    /** Data element ID "TAY". Code providing information about the brand applied to the title. */
    get titleBrand(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'TitleBrand');
    }

    /** Data element ID "TAV". The date the jurisdiction's titling authority issued a title to the owner of the vehicle. The format is CCYYMMDD. */
    get titleIssueDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'TitleIssueDate');
    }

    /** Data element ID "TAA". The date the jurisdiction's titling authority issued a title to the owner of the vehicle. The format is CCYYMMDD. */
    get titleNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'TitleNumber');
    }

    /** Data element ID "TAC". A unique set of alphanumeric characters assigned by the titling jurisdiction to the certificate of title of a vehicle. */
    get titlingJurisdiction(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'TitlingJurisdiction');
    }

    /** Data element ID "VAO". The general configuration or shape of a vehicle distinguished by characteristics such as number of doors, seats, windows, roofline, and type of top. The vehicle body type is 2-character alphanumeric. */
    get vehicleBodyStyle(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleBodyStyle');
    }

    /** Data element ID "VBD". Where the vehicle/vessel is one color, this is the appropriate code describing that color. When the vehicle is two colors, this is the code for the top-most or front-most color. */
    get vehicleColor(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleColor');
    }

    /** Data element ID "VAD". A unique combination of alphanumeric characters that identifies a specific vehicle or component. The VIN is affixed to the vehicle in specific locations and formulated by the manufacturer. State agencies under some controlled instances may assign a VIN to a vehicle. */
    get vehicleIdentificationNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleIdentificationNumber');
    }

    /** Data element ID "VAK". The distinctive (coded) name applied to a group of vehicles by a manufacturer. */
    get vehicleMake(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleMake');
    }

    /** Data element ID "VAM". A code denoting a family of vehicles (within a make), which has a degree of similarity in construction, such as body, chassis, etc. The field does not necessarily contain a standard code; it may contain a value provided by the originator of the field. */
    get vehicleModel(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleModel');
    }

    /** Data element ID "VAL". The year that is assigned to a vehicle by the manufacturer. The format is CCYY. */
    get vehicleModelYear(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleModelYear');
    }

    /** Data element ID "TAU". The date a vehicle was purchased by the current owner. The format is ISO8601 with delimiters. */
    get vehiclePurchaseDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehiclePurchaseDate');
    }
  }

  /** Registration Data. File type "RG". */
  export class RegistrationData {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return AAMVARegistrationDataDocumentType;
    }

    /** Data element ID "RBK". City portion of the owner's address. */
    get addressCity(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressCity');
    }

    /** Data element ID "RBL". Jurisdiction portion of the owner's address. */
    get addressJurisdictionCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressJurisdictionCode');
    }

    /** Data element ID "RBI". Street portion of the owner's address. */
    get addressStreet(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressStreet');
    }

    /** Data element ID "RBM". The Zip code or Postal code of the vehicle owner's residence address. */
    get addressZipCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressZipCode');
    }

    /** Data element ID "VBC". The number of common axles of rotation of one or more wheels of a vehicle, whether power driven or freely rotating. */
    get axles(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Axles');
    }

    /** Data element ID "BBC". The business name of the first registrant of a vehicle. */
    get businessName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'BusinessName');
    }

    /** Data element ID "FUL". The type of fuel used by the vehicle. In most cases, the fuel type would be diesel. */
    get fuel(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Fuel');
    }

    /** Data element ID "VAT". The unladen weight of the vehicle (e.g., the single-unit truck, truck combination) plus the weight of the load being carried at a specific point in time. */
    get grossVehicleWeight(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'GrossVehicleWeight');
    }

    /** Data element ID "RBD". Family name (commonly called surname or last name) of the registered owner of a vehicle. */
    get registrantFamilyName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RegistrantFamilyName');
    }

    /** Data element ID "RBE". Given name or names (includes all of what are commonly referred to as first and middle names) of the registered owner of a vehicle. */
    get registrantGivenName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RegistrantGivenName');
    }

    /** Data element ID "RAG". The date in which the registration expired. The format is ISO8601 with delimiters. */
    get registrationExpiryDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RegistrationExpiryDate');
    }

    /** Data element ID "RBB". The date in which the registration was issued. The format is ISO8601 with delimiters. */
    get registrationIssueDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RegistrationIssueDate');
    }

    /** Data element ID "RAM". The characters assigned to a registration plate or tag affixed to the vehicle, assigned by the jurisdiction. */
    get registrationPlateNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RegistrationPlateNumber');
    }

    /** Data element ID "RBU". A unique number printed on the tab/decal and stored as part of the registration record. */
    get registrationWindowStickerDecal(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'RegistrationWindowStickerDecal'
      );
    }

    /** Data element ID "RBT". The year of registration. */
    get registrationYear(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RegistrationYear');
    }

    /** Data element ID "VAO". The general configuration or shape of a vehicle distinguished by characteristics such as number of doors, seats, windows, roofline, and type of top. The vehicle body type is 2-character alphanumeric. */
    get vehicleBodyStyle(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleBodyStyle');
    }

    /** Data element ID "VBD". Where the vehicle is one color, this is the appropriate code describing that color. When the vehicle is two colors, this is the code for the top-most or front-most color. */
    get vehicleColor(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleColor');
    }

    /** Data element ID "VAD". A unique combination of alphanumeric characters that identifies a specific vehicle or component. The VIN is affixed to the vehicle in specific locations and formulated by the manufacturer. State agencies under some controlled instances my assign a VIN to a vehicle. */
    get vehicleIdentificationNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleIdentificationNumber');
    }

    /** Data element ID "VAK". The distinctive (coded) name applied to a group of vehicles by a manufacturer. */
    get vehicleMake(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleMake');
    }

    /** Data element ID "VAM". A code denoting a family of vehicles (within a make), which has a degree of similarity in construction, such as body, chassis, etc. The field does not necessarily contain a standard code; it may contain a value provided by the originator of the field. */
    get vehicleModel(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleModel');
    }

    /** Data element ID "VAL". The year which is assigned to a vehicle by the manufacturer. The format is CCYY. */
    get vehicleModelYear(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleModelYear');
    }

    /** Data element ID "VPC". Indicates the use of the vehicle. */
    get vehicleUse(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleUse');
    }
  }

  /** Motor Carrier Data. File type "MC". */
  export class MotorCarrierData {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return AAMVAMotorCarrierDataDocumentType;
    }

    /** Data element ID "MAA". The name of the carrier responsible for safety. This can be an individual, partnership or corporation responsible for the transportation of persons or property. This is the name that is recognized by law. */
    get carrierName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'CarrierName');
    }

    /** Data element ID "MAL". This is the city for the mailing address of the individual carrier. This information is utilized by the base jurisdiction to send information to the carrier that purchased the IRP credentials. */
    get city(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'City');
    }

    /** Data element ID "MAI". This is the jurisdiction of the residential address of the individual carrier. This information is utilized by the base jurisdiction to send information to the carrier that purchased the IRP credentials. */
    get jurisdiction(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Jurisdiction');
    }

    /** Data element ID "MAK". This is the mailing address of the individual carrier. This information is utilized by the base jurisdiction to send information to the carrier that purchased the IRP credentials. */
    get streetAddress(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'StreetAddress');
    }

    /** Data element ID "MAN". A unique identifier assigned to the carrier responsible for safety issued by the U.S. Department of Transportation – Federal Motor Carrier Safety Administration. */
    get usdotNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'USDOTNumber');
    }

    /** Data element ID "MAO". The ZIP or Postal code of the resident address of the vehicle owner. */
    get zip(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Zip');
    }
  }

  /** Registrant And Vehicle Data. File type "IR". */
  export class RegistrantAndVehicleData {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return AAMVARegistrantAndVehicleDataDocumentType;
    }

    /** Data element ID "RBI". The first line of the registrant's residence address. */
    get address(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Address');
    }

    /** Data element ID "RAU". The declared base jurisdiction registration weight. */
    get baseJurisdictionRegisteredWeight(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'BaseJurisdictionRegisteredWeight'
      );
    }

    /** Data element ID "RBC". The name of the first registrant of a vehicle. Registrant's name may be a combined individual name or the name of a business */
    get carrierNameRegistrant(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'CarrierNameRegistrant');
    }

    /** Data element ID "RBK". The registrant's residence city name. */
    get city(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'City');
    }

    /** Data element ID "VAT". The unladen weight of the vehicle (e.g., single-unit truck, truck combination) plus the weight of the maximum load for which vehicle registration fees have been paid within a particular jurisdiction. */
    get grossVehicleWeight(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'GrossVehicleWeight');
    }

    /** Data element ID "RBL". The state or province of the registrant's residence address. */
    get jurisdiction(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Jurisdiction');
    }

    /** Data element ID "VAL". The year which is assigned to a vehicle by the manufacturer. The format is YY. */
    get modelYear(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'ModelYear');
    }

    /** Data element IDs "RAP", "VBC". The seat capacity of a commercial vehicle designed for transportation of more than then passengers. The number of common axles of rotation of one or more wheels of a vehicle, whether power design or freely rotating. */
    get numberOfSeats(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'NumberOfSeats');
    }

    /** Data element ID "RAD". The number assigned to the registration decal in those jurisdictions that issue decals. */
    get registrationDecalNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RegistrationDecalNumber');
    }

    /** Data element ID "RAF". The registration enforcement date is the date that the current registration was enforced. This may or may not be the original registration date. The format is ISO8601 with delimiters */
    get registrationEnforcementDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RegistrationEnforcementDate');
    }

    /** Data element ID "RAG". The date in which the registration expired. The format is ISO8601 with delimiters. */
    get registrationExpirationDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RegistrationExpirationDate');
    }

    /** Data element ID "IFJ". The date in which the registration was issued. The format is ISO8601 with delimiters. */
    get registrationIssueDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RegistrationIssueDate');
    }

    /** Data element ID "RAM". The characters assigned to a registration plate or tag affixed to the vehicle, assigned by the jurisdiction. */
    get registrationPlateNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RegistrationPlateNumber');
    }

    /** Data element ID "RBT". This field is the registration year assigned by the jurisdiction. The format is CCYY. */
    get registrationYear(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RegistrationYear');
    }

    /** Data element ID "VBB". The type of vehicle operated for the transportation of persons or property in the furtherance of any commercial or industrial enterprise, for hire or not for hire. Not all states will use all values. */
    get typeOfVehicle(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'TypeOfVehicle');
    }

    /** Data element ID "IEG". A number, assigned by the registrant of the commercial vehicle or trailer, to identify the vehicle or trailer in the fleet. No two units in a fleet can have the same number. A.K.A vehicle unit number or owner's equipment number. */
    get unitNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'UnitNumber');
    }

    /** Data element ID "VAD". A unique combination of alphanumeric characters that identifies a specific vehicle or component. The VIN is affixed to the vehicle in specific locations and formulated by the manufacturer. State agencies under some controlled instances may assign a VIN to a vehicle. */
    get vehicleIdentificationNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleIdentificationNumber');
    }

    /** Data element ID "VAK". The distinctive (coded) name applied to a group of vehicles by a manufacturer. */
    get vehicleMake(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleMake');
    }

    /** Data element ID "RBM". The ZIP or Postal code of the resident address of the registrant. */
    get zipCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'ZipCode');
    }
  }

  /** Vehicle Owner Data. File type "OW". */
  export class VehicleOwnerData {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return AAMVAVehicleOwnerDataDocumentType;
    }

    /** Data element ID "NAX". The unique customer number/ID of the first vehicle owner. */
    get firstOwnerIdNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FirstOwnerIdNumber');
    }

    /** Data element ID "NAB". Last Name or Surname of the Owner. Hyphenated names acceptable, spaces between names acceptable, but no other use of special symbols. */
    get firstOwnerLastName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FirstOwnerLastName');
    }

    /** Data element ID "NBA". The legal status of the first vehicle owner. This is only used when a vehicle has multiple owners. A legal status may be ("AND", "OR"). */
    get firstOwnerLegalStatus(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FirstOwnerLegalStatus');
    }

    /** Data element ID "NAD". Middle Name(s) or Initial(s) of the Owner. Hyphenated names acceptable, spaces, between names acceptable, but no other use of special symbols. */
    get firstOwnerMiddleName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FirstOwnerMiddleName');
    }

    /** Data element ID "NAC". First Name or Given Name of the Owner. Hyphenated names acceptable, but no other use of special symbols. */
    get firstOwnerName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FirstOwnerName');
    }

    /** Data element ID "NAA". Name of the (or one of the) individual(s) who owns the Vehicle as defined in the ANSI D- 20 Data Element Dictionary. (Lastname@Firstname@MI@Suffix if any.) */
    get firstOwnerTotalName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FirstOwnerTotalName');
    }

    /** Data element ID "NAR". Street address line 1. (Mailing) */
    get mailingAddress1(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'MailingAddress1');
    }

    /** Data element ID "NAS". Street address line 2. (Mailing) */
    get mailingAddress2(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'MailingAddress2');
    }

    /** Data element ID "NAT". Name of city for mailing address. */
    get mailingCity(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'MailingCity');
    }

    /** Data element ID "NAU". Jurisdiction code for mailing address. Conforms to Canadian, Mexican and US jurisdictions as appropriate. Codes for provinces (Canada) and states (US and Mexico). */
    get mailingJurisdictionCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'MailingJurisdictionCode');
    }

    /** Data element ID "NAV". The ZIP code or Postal code used for mailing. (As used by Canadian, Mexican and US jurisdictions.) */
    get mailingZipCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'MailingZipCode');
    }

    /** Data element ID "NAM". Street address line 1. (Mailing) */
    get residenceAddress1(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'ResidenceAddress1');
    }

    /** Data element ID "NAN". Street address line 2. (Mailing) */
    get residenceAddress2(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'ResidenceAddress2');
    }

    /** Data element ID "NAO". Name of city for mailing address. */
    get residenceCity(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'ResidenceCity');
    }

    /** Data element ID "NAP". Jurisdiction code for mailing address. Conforms to Canadian, Mexican and US jurisdictions as appropriate. Codes for provinces (Canada) and states (US and Mexico). */
    get residenceJurisdictionCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'ResidenceJurisdictionCode');
    }

    /** Data element ID "NAQ". The ZIP code or Postal code used for mailing. (As used by Canadian, Mexican and US jurisdictions). */
    get residenceZipCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'ResidenceZipCode');
    }

    /** Data element ID "NAY". The unique customer number/ID of the second vehicle owner. */
    get secondOwnerIdNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'SecondOwnerIdNumber');
    }

    /** Data element ID "NAF". Last Name or Surname of the Owner. Hyphenated names acceptable, spaces between names acceptable, but no other use of special symbols. */
    get secondOwnerLastName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'SecondOwnerLastName');
    }

    /** Data element ID "NBB". The legal status of the second vehicle owner. This is only used when a vehicle has multiple owners. A legal status may be ("AND", "OR"). */
    get secondOwnerLegalStatus(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'SecondOwnerLegalStatus');
    }

    /** Data element ID "NAH". Middle Name(s) or Initial(s) of the Owner. Hyphenated names acceptable, spaces between names acceptable, but no other use of special symbols. */
    get secondOwnerMiddleName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'SecondOwnerMiddleName');
    }

    /** Data element ID "NAG". First Name or Given Name of the Owner. Hyphenated names acceptable, but no other use of special symbols. */
    get secondOwnerName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'SecondOwnerName');
    }

    /** Data element ID "NAE". Name of the (or one of the) individual(s) who owns the Vehicle as defined in the ANSI D- 20 Data Element Dictionary. (Lastname@Firstname@MI@Suffix if any.) */
    get secondOwnerTotalName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'SecondOwnerTotalName');
    }
  }

  /** Vehicle Data. File type "VH". */
  export class VehicleData {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return AAMVAVehicleDataDocumentType;
    }

    /** Data element ID "VAO". Vehicle manufacture body style. */
    get bodyStyle(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'BodyStyle');
    }

    /** Data element ID "VAG". Date vehicle reported junked. The format is ISO8601 with delimiters. */
    get dateJunked(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DateJunked');
    }

    /** Data element ID "VAJ". Date vehicle reported recovered. The format is ISO8601 with delimiters. */
    get dateRecovered(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DateRecovered');
    }

    /** Data element ID "VAI". Date vehicle reported stolen. The format is ISO8601 with delimiters. */
    get dateStolen(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DateStolen');
    }

    /** Data element ID "VAW". Manufacturer's rated engine displacement. */
    get engineDisplacement(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'EngineDisplacement');
    }

    /** Data element ID "VAR". The size of a vehicle's engine. */
    get engineSize(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'EngineSize');
    }

    /** Data element ID "VAN". Type of fuel the vehicle utilizes. */
    get fuelType(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FuelType');
    }

    /** Data element ID "VAU". Manufacturer's rated horsepower. */
    get horsepower(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Horsepower');
    }

    /** Data element ID "VAY". International fuel tax indicator */
    get iftaIndicator(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'IFTAIndicator');
    }

    /** Data element ID "VAX". International registration plan indicator. */
    get irpIndicator(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'IRPIndicator');
    }

    /** Data element ID "VAF". Vehicle has been junked. */
    get junkedIndicator(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'JunkedIndicator');
    }

    /** Data element ID "VAE". Manufacturer's Suggested Retail Price. No decimal places. Right Justified Zero or space fill. */
    get msrp(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'MSRP');
    }

    /** Data element ID "VAA". State to provide definition. */
    get majorCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'MajorCode');
    }

    /** Data element ID "VAL". Vehicle manufacture year. */
    get makeYear(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'MakeYear');
    }

    /** Data element ID "VAT". Manufacturer's gross vehicle weight rating. */
    get manufactureGrossWeight(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'ManufactureGrossWeight');
    }

    /** Data element ID "VAB". State to provide definition. */
    get minorCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'MinorCode');
    }

    /** Data element ID "VBC". Number of axles the vehicle has. */
    get numberOfAxles(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'NumberOfAxles');
    }

    /** Data element ID "VAQ". Number of cylinders the vehicle has. */
    get numberOfCylinders(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'NumberOfCylinders');
    }

    /** Data element ID "VAP". Number of doors on the vehicle. */
    get numberOfDoors(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'NumberOfDoors');
    }

    /** Data element ID "VAH". Indicates stolen vehicle. */
    get stolenIndicator(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'StolenIndicator');
    }

    /** Data element ID "VAC". Type of transmission the vehicle carries. */
    get transmissionCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'TransmissionCode');
    }

    /** Data element ID "VAV". Gross weight of the vehicle unloaded. */
    get unladenWeight(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'UnladenWeight');
    }

    /** Data element ID "VAZ". Vehicle license tax calculation from date of purchase. */
    get vltClacFromDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VLTClacFromDate');
    }

    /** Data element ID "VBA". Unique number to identify the vehicle record. */
    get vehicleIdNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleIdNumber');
    }

    /** Data element ID "VAD". A unique combination of alphanumeric characters that identifies a specific vehicle or component. The VIN is affixed to the vehicle in specific locations and formulated by the manufacturer. State agencies under some controlled instances may assign a VIN to a vehicle. */
    get vehicleIdentificationNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleIdentificationNumber');
    }

    /** Data element ID "VAK". The distinctive (coded) name applied to a group of vehicles by a manufacturer. */
    get vehicleMake(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleMake');
    }

    /** Data element ID "VAM". Vehicle manufacture model. */
    get vehicleModel(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleModel');
    }

    /** Data element ID "VAS". This is the status of the vehicle (e.g., active, suspend, etc.) */
    get vehicleStatusCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleStatusCode');
    }

    /** Data element ID "VBB". EPA vehicle classification. */
    get vehicleTypeCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleTypeCode');
    }
  }

  /** Vehicle Safety Inspection Data. File type "VS". */
  export class VehicleSafetyInspectionData {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return AAMVAVehicleSafetyInspectionDataDocumentType;
    }

    /** Data element ID "IAN". The street name and number, city, state and zip code of the inspection facility. */
    get inspectionAddress(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'InspectionAddress');
    }

    /** Data element ID "IPD". Identifies whether the pollution control devices meet the minimum inspection criteria. */
    get inspectionAirPollutionDeviceConditions(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'InspectionAirPollutionDeviceConditions'
      );
    }

    /** Data element ID "IFI". The unique number assigned to an inspection facility. */
    get inspectionFacilityIdentifier(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'InspectionFacilityIdentifier'
      );
    }

    /** Data element ID "INC". A unique number assigned to a current vehicle inspection form for identification purposes or a preprinted unique number on the motor vehicle inspection sticker currently issued to a motor vehicle which has passed inspection. */
    get inspectionFormOrStickerNumberCurrent(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'InspectionFormOrStickerNumberCurrent'
      );
    }

    /** Data element ID "INP". The number of the last inspection form excluding the current inspection or the certification number of the last inspection sticker, excluding the current inspection. */
    get inspectionFormOrStickerNumberPrevious(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'InspectionFormOrStickerNumberPrevious'
      );
    }

    /** Data element ID "ISC". An indicator that specifies whether or not the vehicle has a current smog certificate. */
    get inspectionSmogCertificateIndicator(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'InspectionSmogCertificateIndicator'
      );
    }

    /** Data element ID "ISN". Station number performing the inspection. */
    get inspectionStationNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'InspectionStationNumber');
    }

    /** Data element ID "IIN". A unique number assigned to each licensed vehicle inspector. */
    get inspectorIdentificationNumber(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'InspectorIdentificationNumber'
      );
    }

    /** Data element ID "ORI". The vehicle's odometer reading (to the nearest mile or kilometer) at the time of inspection. */
    get odometerReadingAtInspection(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'OdometerReadingAtInspection');
    }

    /** Data element ID "VAO". The general configuration or shape of a vehicle distinguished by characteristics such as number of doors, seats, windows, roofline, and type of top. The vehicle body type is 2- character alphanumeric. */
    get vehicleBodyType(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleBodyType');
    }

    /** Data element ID "VAK". The distinctive (coded) name applied to a group of vehicles by a manufacturer. */
    get vehicleMake(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleMake');
    }

    /** Data element ID "VAL". The year which is assigned to a vehicle by the manufacturer. The format is CCYY. */
    get vehicleModelYear(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VehicleModelYear');
    }
  }

  /** Driver License Or ID Document */
  export abstract class DLID {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    abstract requiredDocumentType(): string;

    /** Data element ID "DAI". City portion of the cardholder address. */
    get addressCity(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressCity');
    }

    /** Data element ID "DAJ". State portion of the cardholder address. */
    get addressJurisdictionCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressJurisdictionCode');
    }

    /** Data element ID "DAK". Postal code portion of the cardholder address in the U.S. and Canada. If the trailing portion of the postal code in the U.S. is not known, zeros will be used to fill the trailing set of numbers up to nine (9) digits. */
    get addressPostalCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressPostalCode');
    }

    /** Data element ID "DAG". Street portion of the cardholder address. */
    get addressStreet1(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressStreet1');
    }

    /** Data element ID "DAH". Second line of street portion of the cardholder address. */
    get addressStreet2(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AddressStreet2');
    }

    /** Data element ID "DCJ". A string of letters and/or numbers that identifies when, where, and by whom a driver license/ID card was made. If audit information is not used on the card or the MRT, it must be included in the driver record. */
    get adultInformation(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AdultInformation');
    }

    /** Data element ID "DBN". Other family name by which cardholder is known. */
    get aliasFamilyName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AliasFamilyName');
    }

    /** Data element ID "DBG". Other given name by which cardholder is known. */
    get aliasGivenName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AliasGivenName');
    }

    /** Data element ID "DBQ". Other middle name by which cardholder is known. */
    get aliasMiddleName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AliasMiddleName');
    }

    /** Data element ID "DBR". Other prefix by which cardholder is known. */
    get aliasPrefixName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AliasPrefixName');
    }

    /** Data element ID "DBS". Other suffix by which cardholder is known. */
    get aliasSuffixName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'AliasSuffixName');
    }

    /** Data element ID "DDB". DHS required field that indicates date of the most recent version change or modification to the visible format of the DL/ID. The format is ISO8601 with delimiters. */
    get cardRevisionDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'CardRevisionDate');
    }

    /** Data element ID "DDA". DHS required field that indicates compliance: "F" = compliant; and, "N" = non-compliant. */
    get complianceType(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'ComplianceType');
    }

    /** Data element ID "DCG". Country in which DL/ID is issued. U.S. = USA, Canada = CAN. */
    get countryIdentification(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'CountryIdentification');
    }

    /** Data element ID "DCS". Family name of the cardholder. (Family name is sometimes also called “last name” or “surname.”) Collect full name for record, print as many characters as possible on portrait side of DL/ID. */
    get customerFamilyName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'CustomerFamilyName');
    }

    /** Data element ID "DAC". First name of the cardholder. */
    get customerFirstName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'CustomerFirstName');
    }

    /** Data element ID "DCT". Given names of the cardholder. (Given names include all names other than the Family Name. This includes all those names sometimes also called “first” and “middle” names.) */
    get customerGivenNames(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'CustomerGivenNames');
    }

    /** Data element ID "DAQ". The number assigned or calculated by the issuing authority. */
    get customerIdNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'CustomerIdNumber');
    }

    /** Data element ID "DAD". Middle name(s) of the cardholder. In the case of multiple middle names they shall be separated by a comma “,”. */
    get customerMiddleName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'CustomerMiddleName');
    }

    /** Data element ID "DBB". Date on which the cardholder was born. The format is ISO8601 with delimiters. */
    get dateOfBirth(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DateOfBirth');
    }

    /** Data element ID "DCF". Number must uniquely identify a particular document issued to that customer from others that may have been issued in the past. This number may serve multiple purposes of document discrimination, audit information number, and/or inventory control. */
    get documentDiscriminator(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DocumentDiscriminator');
    }

    /** Data element ID "DBA". Date on which the driving and identification privileges granted by the document are no longer valid. The format is ISO8601 with delimtiers. */
    get documentExpirationDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DocumentExpirationDate');
    }

    /** Data element ID "DBD". Date on which the document was issued. The format is ISO8601 with delimiters. */
    get documentIssueDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DocumentIssueDate');
    }

    /** Data element ID "DBL". Alternative dates given as date of birth. */
    get driverAliasDateOfBirthField(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DriverAliasDateOfBirthField');
    }

    /** Data element ID "DBP". Alternative fist name or given name of the individual holding the Driver License or ID. Hyphenated names acceptable, but no other use of special symbols. */
    get driverAliasFirstName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DriverAliasFirstName');
    }

    /** Data element ID "DBO". Alternative last name or surname of the individual holding the Driver License or ID. Hyphenated names acceptable, but no other use of special symbols. */
    get driverAliasLastName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DriverAliasLastName');
    }

    /** Data element ID "DBM". DriverAliasSocialSecurityNumber */
    get driverAliasSocialSecurityNumber(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'DriverAliasSocialSecurityNumber'
      );
    }

    /** Data element ID "DAB". Last name or surname of the individual holding the Driver License or ID. Hyphenated names acceptable, but no other use of special symbols. */
    get driverLastName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DriverLastName');
    }

    /** Data element ID "DAR". A=Class A; B=Class B; C=Class C (Class A, B and C are defined by Federal Highway regulations); M=Class M motorcycle as defined by AAMVA; others are defined by DL Classification Code Standards. */
    get driverLicenseClassificationCode(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'DriverLicenseClassificationCode'
      );
    }

    /** Data element ID "DAT". Any endorsements on a driver license which authorize the operation of specified types of vehicles or the operation of vehicles carrying specified loads. Endorsements shall be specific to classification of a driver license. */
    get driverLicenseEndorsementsCode(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'DriverLicenseEndorsementsCode'
      );
    }

    /** Data element ID "DAA". Name of the individual holding the Driver License or ID as defined in ANSI D20 Data Dictionary. (Lastname@Firstname@MI@ suffix if any) (Machine, Mag Stripe uses ‘$' and Bar Code uses ‘,' in place of ‘@') Firstname, Middle Initial, Lastname (Human) */
    get driverLicenseName(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DriverLicenseName');
    }

    /** Data element ID "DAS". A restriction applicable to a driver license. */
    get driverLicenseRestrictionCode(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'DriverLicenseRestrictionCode'
      );
    }

    /** Data element ID "DAF". Prefix to Driver Name. Not defined in ANSI D20. Freeform as defined by issuing jurisdiction. */
    get driverNamePrefix(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DriverNamePrefix');
    }

    /** Data element ID "DAE". An affix occurring at the end of a word, e.g.; Sr., Jr., II, III, IV, etc. */
    get driverNameSuffix(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DriverNameSuffix');
    }

    /** Data element ID "PAA". Identifies the type of permit as defined by ANSI D20. */
    get driverPermitClassificationCode(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'DriverPermitClassificationCode'
      );
    }

    /** Data element ID "PAF". Permit endorsements as defined by ANSI D20. */
    get driverPermitEndorsementCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DriverPermitEndorsementCode');
    }

    /** Data element ID "PAD".  Date permit was issued. The format is ISO8601 with delimiters. */
    get driverPermitIssueDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DriverPermitIssueDate');
    }

    /** Data element ID "PAE". Permit restrictions as defined by ANSI D20. */
    get driverPermitRestrictionCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DriverPermitRestrictionCode');
    }

    /** Data element ID "DAN". Name of city for mailing address. */
    get driverResidenceCity(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DriverResidenceCity');
    }

    /** Data element ID "DAO". Jurisdiction code for mailing address. Conforms to Canadian, Mexican and US Jurisdictions as appropriate. Codes for provinces (Canada) and states (US and Mexico). */
    get driverResidenceJurisdictionCode(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'DriverResidenceJurisdictionCode'
      );
    }

    /** Data element ID "DAP". Postal code of residence */
    get driverResidencePostalCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'DriverResidencePostalCode');
    }

    /** Data element ID "DAL". Street address line 1 (mailing). */
    get driverResidenceStreetAddress1(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'DriverResidenceStreetAddress1'
      );
    }

    /** Data element ID "DAM". Street address line 2 (mailing). */
    get driverResidenceStreetAddress2(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'DriverResidenceStreetAddress2'
      );
    }

    /** Data element ID "DDE". A code that indicates whether a field has been truncated (T), has not been truncated (N), or – unknown whether truncated (U). */
    get familyNameTruncation(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FamilyNameTruncation');
    }

    /** Data element ID "DCH". Federal Commercial Vehicle Codes */
    get federalCommercialVehicleCodes(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'FederalCommercialVehicleCodes'
      );
    }

    /** Data element ID "DDF". A code that indicates whether a field has been truncated (T), has not been truncated (N), or – unknown whether truncated (U). */
    get firstNameTruncation(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'FirstNameTruncation');
    }

    /** Data element ID "DDC". Date on which the hazardous material endorsement granted by the document is no longer valid. The format is ISO8601 with delimiters. */
    get hazmatEndorsementExpirationDate(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'HAZMATEndorsementExpirationDate'
      );
    }

    /** Data element ID "DAZ". Color of cardholder's hair. ANSI D-20 codes converted to human readable format according to the ANSI D20 Data Dictionary. */
    get hairColor(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'HairColor');
    }

    /** Data element ID "DAV". Height in centimeters */
    get height(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Height');
    }

    /** Data element ID "DCK". A string of letters and/or numbers that is affixed to the raw materials (card stock, laminate, etc.) used in producing driver licenses and ID cards. (DHS recommended field). */
    get inventoryControlNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'InventoryControlNumber');
    }

    /** Data element ID "DBE". A string used by some jurisdictions to validate the document against their data base. */
    get issueTimeStamp(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'IssueTimeStamp');
    }

    /** Data element ID "DCQ". Text that explains the jurisdiction-specific code(s) that indicates additional driving privileges granted to the cardholder beyond the vehicle class. */
    get jurisdictionSpecificEndorsementCodeDescription(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'JurisdictionSpecificEndorsementCodeDescription'
      );
    }

    /** Data element ID "DCD". Jurisdiction-specific codes that represent additional privileges granted to the cardholder beyond the vehicle class (such as transportation of passengers, hazardous materials, operation of motorcycles, etc.). */
    get jurisdictionSpecificEndorsementCodes(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'JurisdictionSpecificEndorsementCodes'
      );
    }

    /** Data element ID "DCR". Text describing the jurisdiction-specific restriction code(s) that curtail driving privileges. */
    get jurisdictionSpecificRestrictionCodeDescription(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'JurisdictionSpecificRestrictionCodeDescription'
      );
    }

    /** Data element ID "DCB". Jurisdiction-specific codes that represent restrictions to driving privileges (such as airbrakes, automatic transmission, daylight only, etc.). */
    get jurisdictionSpecificRestrictionCodes(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'JurisdictionSpecificRestrictionCodes'
      );
    }

    /** Data element ID "DCA". Jurisdiction-specific vehicle class / group code, designating the type of vehicle the cardholder has privilege to drive. */
    get jurisdictionSpecificVehicleClass(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'JurisdictionSpecificVehicleClass'
      );
    }

    /** Data element ID "DCP". Text that explains the jurisdiction-specific code(s) for classifications of vehicles cardholder is authorized to drive. */
    get jurisdictionSpecificVehicleClassificationDescription(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'JurisdictionSpecificVehicleClassificationDescription'
      );
    }

    /** Data element ID "DDD". DHS required field that indicates that the cardholder has temporary lawful status = "1". */
    get limitedDurationDocumentIndicator(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'LimitedDurationDocumentIndicator'
      );
    }

    /** Data element ID "DDG". A code that indicates whether a field has been truncated (T), has not been truncated (N), or – unknown whether truncated (U). */
    get middleNameTruncation(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'MiddleNameTruncation');
    }

    /** Data element ID "DCU". Name Suffix (If jurisdiction participates in systems requiring name suffix (PDPS, CDLIS, etc.), the suffix must be collected and displayed on the DL/ID and in the MRT). Collect full name for record, print as many characters as possible on portrait side of DL/ID. JR (Junior), SR (Senior), 1ST or I (First), 2ND or II (Second),  3RD or III (Third),  4TH or IV (Fourth), 5TH or V (Fifth), 6TH or VI (Sixth), 7TH or VII (Seventh), 8TH or VIII (Eighth), 9TH or IX (Ninth). */
    get nameSuffix(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'NameSuffix');
    }

    /** Data element ID "DBI". "Y"; Used by some jurisdictions to indicate holder of the document is a non-resident. */
    get nonResidentIndicator(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'NonResidentIndicator');
    }

    /** Data element ID "DBF". Number of duplicate cards issued for a license or ID if any. */
    get numberOfDuplicates(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'NumberOfDuplicates');
    }

    /** Data element ID "DBH". Organ Donor */
    get organDonor(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'OrganDonor');
    }

    /** Data element ID "DDK". Field that indicates that the cardholder is an organ donor = "1". */
    get organDonorIndicator(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'OrganDonorIndicator');
    }

    /** Data element ID "PAB". Date permit expires, The format is ISO8601 with delimiters. */
    get permitExpirationDate(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PermitExpirationDate');
    }

    /** Data element ID "PAC". Type of permit. */
    get permitIdentifier(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PermitIdentifier');
    }

    /** Data element ID "DAY". Color of cardholder's eyes. ANSI D-20 codes converted to human readable format according to the ANSI D20 Data Dictionary. */
    get physicalDescriptionEyeColor(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PhysicalDescriptionEyeColor');
    }

    /** Data element ID "DAU". Height of cardholder. Inches (in): number of inches followed by " in" or Centimeters (cm): number of centimeters followed by " cm." */
    get physicalDescriptionHeight(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PhysicalDescriptionHeight');
    }

    /** Data element ID "DBC". Gender of the cardholder. "Male" or "Female". */
    get physicalDescriptionSex(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PhysicalDescriptionSex');
    }

    /** Data element ID "DCE". Indicates the approximate weight range of the cardholder: 0 = up to 31 kg (up to 70 lbs), 1 = 32 – 45 kg (71 – 100 lbs), 2 = 46 - 59 kg (101 – 130 lbs), 3 = 60 - 70 kg (131 – 160 lbs), 4 = 71 - 86 kg (161 – 190 lbs), 5 = 87 - 100 kg (191 – 220 lbs), 6 = 101 - 113 kg (221 – 250 lbs), 7 = 114 - 127 kg (251 – 280 lbs), 8 = 128 – 145 kg (281 – 320 lbs), 9 = 146+ kg (321+ lbs). */
    get physicalDescriptionWeightRange(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'PhysicalDescriptionWeightRange'
      );
    }

    /** Data element ID "DCI". Country and municipality and/or state/province. */
    get placeOfBirth(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'PlaceOfBirth');
    }

    /** Data element ID "DCL". Codes for race or ethnicity of the cardholder. ANSI D-20 codes converted to human readable format according to the ANSI D20 Data Dictionary. */
    get raceEthnicity(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'RaceEthnicity');
    }

    /** Data element ID "DBK". The number assigned to an individual by the Social Security Administration. */
    get socialSecurityNumber(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'SocialSecurityNumber');
    }

    /** Data element ID "DCN". Standard endorsement code(s) for cardholder. See codes in D20. This data element is a placeholder for future efforts to standardize endorsement codes. */
    get standardEndorsementCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'StandardEndorsementCode');
    }

    /** Data element ID "DCO". Standard restriction code(s) for cardholder. See codes in D20. This data element is a placeholder for future efforts to standardize restriction codes. */
    get standardRestrictionCode(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'StandardRestrictionCode');
    }

    /** Data element ID "DCM". Standard vehicle classification code(s) for cardholder. This data element is a placeholder for future efforts to standardize vehicle classifications. */
    get standardVehicleClassification(): Field | undefined {
      return this.document.fields.find(
        (f: Field) => f.type.name === 'StandardVehicleClassification'
      );
    }

    /** Data element ID "DDH". Date on which the cardholder turns 18 years old. The format is ISO8601 with delimiters. */
    get under18Until(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Under18Until');
    }

    /** Data element ID "DDI". Date on which the cardholder turns 19 years old. The format is ISO8601 with delimiters. */
    get under19Until(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Under19Until');
    }

    /** Data element ID "DDJ". Date on which the cardholder turns 21 years old. The format is ISO8601 with delimiters. */
    get under21Until(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'Under21Until');
    }

    /** Data element ID "DBJ". A number or alphanumeric string used by some jurisdictions to identify a "customer" across multiple data bases. */
    get uniqueCustomerIdentifier(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'UniqueCustomerIdentifier');
    }

    /** Data element ID "DDL". Field that indicates that the cardholder is a veteran = "1". */
    get veteranIndicator(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'VeteranIndicator');
    }

    /** Data element ID "DAX". Cardholder weight in kilograms Ex. 84 kg = "084" */
    get weightKilograms(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'WeightKilograms');
    }

    /** Data element ID "DAW". Cardholder weight in pounds Ex. 185 lb = "185" */
    get weightPounds(): Field | undefined {
      return this.document.fields.find((f: Field) => f.type.name === 'WeightPounds');
    }
  }

  /** Driver License. File type "DL". */
  export class DriverLicense extends DLID {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return AAMVADriverLicenseDocumentType;
    }
  }

  /** ID Card. File type "ID". */
  export class IDCard extends DLID {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return AAMVAIDCardDocumentType;
    }
  }

  /** Enhanced Driver License. File type "EN". */
  export class EnhancedDriverLicense extends DLID {
    constructor(document: GenericDocument) {
      super(document);
    }

    requiredDocumentType(): string {
      return AAMVAEnhancedDriverLicenseDocumentType;
    }
  }

  /** The raw document as was parsed from the barcode. The original field key names and field values as they appear in the barcode are left as-is. The mnemonic field keys from the AAMVA specification are not replaced with human-readable names. No field value normalization, like ISO 8601 date reformatting, etc., is done. */
  export class RawDocument {
    private _document: GenericDocument;

    get document(): GenericDocument {
      return this._document;
    }

    constructor(document: GenericDocument) {
      if (document.type.name !== this.requiredDocumentType()) {
        throw new Error(
          `Expected document type ${this.requiredDocumentType()}, got ${document.type.name}`
        );
      }

      this._document = document;
    }

    requiredDocumentType(): string {
      return AAMVARawDocumentDocumentType;
    }
  }
}
