class SourceStructuredDateToDate(odin.Mapping):
    """Maps SourceStructuredDate to Date object."""
    from_obj = SourceStructuredDate
    to_obj = Date

    mappings = (
        odin.define(from_field="date_type_structured", to_field="type"),
        odin.define(from_field="date_label", to_field="label")
    )

    @odin.map_field(from_field="date_type_structured", to_field="begin")
    def begin(self, value):
        if value == "single":
            return self.source.structured_date_single.date_standardized
        else:
            return self.source.structured_date_range.begin_date_standardized

    @odin.map_field(from_field="date_type_structured", to_field="end")
    def end(self, value):
        if value == "single":
            return self.source.structured_date_single.date_standardized
        else:
            return self.source.structured_date_range.end_date_standardized

    @odin.map_field(from_field="date_type_structured", to_field="expression")
    def expression(self, value):
        if value == "single":
            date_obj = self.source.structured_date_single
            return date_obj.date_expression if date_obj.date_expression else date_obj.date_standardized
        else:
            date_obj = self.source.structured_date_range
            begin = date_obj.begin_date_expression if date_obj.begin_date_expression else date_obj.begin_date_standardized
            end = date_obj.end_date_expression if date_obj.end_date_expression else date_obj.end_date_standardized
            return "{}-{}".format(begin, end)
class SourceAgentPersonToAgent(odin.Mapping):
    """Maps SourceAgentPerson to Agent object."""
    from_obj = SourceAgentPerson
    to_obj = Agent

    mappings = (
        odin.define(from_field="title", to_field="authorized_name"),
    )

    def parse_name(self, value):
        """Parses names of people agents."""
        first_name = value.rest_of_name if value.rest_of_name else ""
        last_name = value.primary_name if value.primary_name else ""
        return f'{first_name} {last_name}'.strip()

    @odin.map_field(from_field="display_name", to_field="title")
    def title(self, value):
        return self.parse_name(value)

    @odin.map_list_field(from_field="notes", to_field="notes", to_list=True)
    def notes(self, value):
        return SourceNoteToNote.apply([v for v in value if (v.publish and v.jsonmodel_type.split("_")[-1] in NOTE_TYPE_CHOICES_TRANSFORM)])

    @odin.map_list_field(from_field="dates_of_existence", to_field="dates")
    def dates(self, value):
        return convert_dates(value)

    @odin.map_field(from_field="agent_record_identifiers", to_field="external_identifiers", to_list=True)
    def external_identifiers(self, value):
        external_ids = [ExternalIdentifier(identifier=v.record_identifier, source=v.source) for v in value] if value else []
        return external_ids + [ExternalIdentifier(identifier=self.source.uri, source="archivesspace")]

    @odin.map_field(from_field="uri", to_field="uri")
    def uri(self, value):
        return "/agents/{}".format(identifier_from_uri(value))

    @odin.assign_field(to_field="agent_type")
    def agent_types(self):
        return "person"

    @odin.assign_field(to_field="category")
    def category(self):
        return "person"

    @odin.map_list_field(from_field="jsonmodel_type", to_field="people")
    def people(self, value):
        return [SourceAgentPersonToAgentReference.apply(self.source)]

    @odin.map_field(from_field="group", to_field="group")
    def group(self, value):
        value.title = self.parse_name(self.source.display_name)
        return transform_group(value, "agents")
class SourceDateToDate(odin.Mapping):
    """Maps SourceDate to Date object."""
    from_obj = SourceDate
    to_obj = Date

    mappings = (
        odin.define(from_field="date_type", to_field="type"),
    )

    @odin.map_field(from_field="end", to_field="end")
    def end(self, value):
        return self.source.begin if self.source.date_type == "single" else value

    @odin.map_field(from_field="expression", to_field="expression")
    def expression(self, value):
        if not value:
            value = "{}-{}".format(self.source.begin, self.source.end) if self.source.end else "{}-".format(self.source.begin)
        return value
class SourceAgentFamilyToAgent(odin.Mapping):
    """Maps SourceAgentFamily to Agent object."""
    from_obj = SourceAgentFamily
    to_obj = Agent

    mappings = (
        odin.define(from_field="title", to_field="authorized_name"),
    )

    @odin.map_list_field(from_field="notes", to_field="notes", to_list=True)
    def notes(self, value):
        return SourceNoteToNote.apply([v for v in value if (v.publish and v.jsonmodel_type.split("_")[-1] in NOTE_TYPE_CHOICES_TRANSFORM)])

    @odin.map_list_field(from_field="dates_of_existence", to_field="dates")
    def dates(self, value):
        return convert_dates(value)

    @odin.map_field(from_field="agent_record_identifiers", to_field="external_identifiers", to_list=True)
    def external_identifiers(self, value):
        external_ids = [ExternalIdentifier(identifier=v.record_identifier, source=v.source) for v in value] if value else []
        return external_ids + [ExternalIdentifier(identifier=self.source.uri, source="archivesspace")]

    @odin.map_field(from_field="uri", to_field="uri")
    def uri(self, value):
        return "/agents/{}".format(identifier_from_uri(value))

    @odin.assign_field(to_field="agent_type")
    def agent_types(self):
        return "family"

    @odin.assign_field(to_field="category")
    def category(self):
        return "person"

    @odin.map_list_field(from_field="jsonmodel_type", to_field="families")
    def families(self, value):
        return [SourceAgentFamilyToAgentReference.apply(self.source)]

    @odin.map_field(from_field="group", to_field="group")
    def group(self, value):
        return transform_group(value, "agents")