class ActiveFedora::Associations::DirectlyContainsOneAssociation

:nodoc:
Filters a DirectContainer relationship, returning the first item that matches the given :type

def add_to_container(record)

Relies on container_association.initialize_attributes to appropriately set things like record.uri
Adds record to the DirectContainer identified by the container_association
def add_to_container(record)
  container_association.add_to_target(record) # adds record to corresponding Container
  # TODO is send necessary?
  container_association.send(:initialize_attributes, record) # Uses the :through association initialize the record with things like the correct URI for a direclty contained object
end

def add_type_to_record(record, type_uri)

Adds type_uri to the RDF.type assertions on record
def add_type_to_record(record, type_uri)
  metadata_node = metadata_node_for_record(record)
  types = metadata_node.type
  unless types.include?(type_uri)
    types << type_uri
    metadata_node.set_value(:type, types)
  end
  record
end

def container_association

Returns the DirectContainerAssociation corresponding to the direct container that's being filtered
def container_association
  container_association_proxy.proxy_association
end

def container_association_proxy

Returns the ContainerAssociationProxy corresponding to the direct container that's being filtered
def container_association_proxy
  @owner.send(@reflection.options[:through])
end

def container_reflection

Returns the Reflection corresponding to the direct container association that's being filtered
def container_reflection
  @container_reflection ||= @owner.class._reflect_on_association(@reflection.options[:through])
end

def find_target

See https://github.com/samvera/active_fedora/issues/1335
TODO: Refactor this to use solr (for efficiency) instead of parsing the RDF graph. Requires indexing ActiveFedora::File objects into solr, including their RDF.type and, if possible, the id of their container
Finds objects contained by the container predicate (either the configured has_member_relation or ldp:contains)
:nodoc:
Filters a DirectContainer relationship, returning the first item that matches the given :type
def find_target
  # filtered_objects = container_association_proxy.to_a.select { |o| o.metadata_node.type.include?(options[:type]) }
  query_node = if container_predicate = options[:has_member_relation]
                 owner
               else
                 container_predicate = ::RDF::Vocab::LDP.contains
                 container_association.container # Use the :through association's container
               end
  contained_uris = query_node.resource.query({ predicate: container_predicate }).map { |r| r.object.to_s }
  contained_uris.each do |object_uri|
    contained_object = klass.find(klass.uri_to_id(object_uri))
    return contained_object if get_type_from_record(contained_object).include?(options[:type])
  end
  nil # if nothing was found & returned while iterating on contained_uris, return nil
end

def get_type_from_record(record)

Returns the RDF.type assertions for the record
def get_type_from_record(record)
  metadata_node_for_record(record).type
end

def initialize_attributes(record)

Overrides initialize_attributes to ensure that record is initialized with attributes from the corresponding container
def initialize_attributes(record)
  super
  container_association.initialize_attributes(record)
end

def metadata_node_for_record(record)

Sometimes this is the record, other times it's record.metadata_node
Returns the RDF node that contains metadata like RDF.type assertions for the record
def metadata_node_for_record(record)
  return record if record.respond_to?(:type) && record.respond_to?(:set_value)
  return record.metadata_node if record.respond_to?(:metadata_node)
  raise ArgumentError, "record must either have a metadata node or must respond to .type"
end

def remove_existing_target

def remove_existing_target
  @target ||= find_target
  return unless @target
  container_association_proxy.delete @target
  @updated = true
end

def replace(record, *)

Ensures that this association's +type+ is set on the record and adds the record to the association's DirectContainer
Replaces association +target+ with +record+
def replace(record, *)
  if record
    raise_on_type_mismatch!(record)
    remove_existing_target
    add_type_to_record(record, options[:type])
    add_to_container(record)
  else
    remove_existing_target
  end
  self.target = record
end

def updated?

def updated?
  @updated
end