def get_archivelab_org_validator():
    class PatchedManifestValidator(ManifestValidator):
        # Replace the image API with the presentation API at manifest level.
        def context_field(self, value):
            if value == 'http://iiif.io/api/image/2/context.json':
                self.log_warning("@context", "Applied library specific corrections. "
                                                 "Replaced image context with presentation context.")
                return self.PRESENTATION_API_URI
            return value

    class PatchedSequenceValidator(SequenceValidator):
        @SequenceValidator.errors_to_warnings
        def context_field(self, value):
            return super().context_field(value)

    class PatchedAnnotationValidator(AnnotationValidator):
        REQUIRED_FIELDS = AnnotationValidator.REQUIRED_FIELDS - {"on", "@type"}

        def setup(self):
            self.ImageSchema['type'] = self.type_field

    iv = IIIFValidator()
    iv.ManifestValidator = PatchedManifestValidator
    iv.AnnotationValidator = PatchedAnnotationValidator
    iv.SequenceValidator = PatchedSequenceValidator
    return iv
def get_harvard_edu_validator():
    def str_to_int(self, field, value):
        """Coerce strings to ints."""
        if isinstance(value, int):
            return value
        try:
            val = int(value)
            self.log_warning(field, "Coerced to int.")
            return val
        except ValueError:
            self.log_error(field, "Could not coerce to int.")
            return value

    BaseValidator.width_field = lambda self, value: str_to_int(self, "width", value)
    BaseValidator.height_field = lambda self, value: str_to_int(self, "height", value)

    class PatchedImageContentValidator(ImageContentValidator):
        def service_field(self, value):
            """Add a context to the service if none exists."""
            val, errs = self.mute_errors(super().service_field, value)
            if not val.get('@context'):
                val['@context'] = 'http://library.stanford.edu/iiif/image-api/1.1/context.json'
                self.log_warning("@context", "Applied library specific corrections. Added @context to images.")
            return val

    class PatchedManifestValidator(ManifestValidator):
        @ManifestValidator.errors_to_warnings
        def context_field(self, value):
            """Allow the unknown top level context (since it doesn't seem to break things)"""
            return super().context_field(value)

        @ManifestValidator.errors_to_warnings
        def license_field(self, value):
            """Allow non uri in license field."""

            return super().license_field(value)

    iv = IIIFValidator()
    iv.ManifestValidator = PatchedManifestValidator
    iv.ImageContentValidator = PatchedImageContentValidator
    return iv
def get_gallica_bnf_fr_validator():

    class PatchedManifestValidator(ManifestValidator):
        # Squash the lang-val pairs down to one value, separated by semicolon.

        def metadata_field(self, value):

            """Correct any metadata entries missing a language key in lang-val pairs."""
            values, errs = self.mute_errors(super().metadata_field, value)
            if not errs:
                return values
            for value in values:
                v = value.get('value')
                if isinstance(v, list) and not all(vsub.get("@language") for vsub in v):
                    value['value'] = "; ".join((vsub.get("@value", "") for vsub in v))
                    self.log_warning("metadata", "Applied library specific corrections: "
                                                     "metadata field bad formatting ignored.")
            return values

    iv = IIIFValidator()
    iv.ManifestValidator = PatchedManifestValidator
    return iv