code: package it.unibz.inf.ontop.spec.mapping.impl;
  
  import com.google.common.collect.ImmutableList;
  import it.unibz.inf.ontop.model.atom.RDFAtomPredicate;
  import it.unibz.inf.ontop.spec.mapping.TargetAtom;
  import it.unibz.inf.ontop.model.atom.DistinctVariableOnlyDataAtom;
  import it.unibz.inf.ontop.substitution.ImmutableSubstitution;
  import it.unibz.inf.ontop.model.term.ImmutableTerm;
  import it.unibz.inf.ontop.substitution.InjectiveVar2VarSubstitution;
  import it.unibz.inf.ontop.utils.ImmutableCollectors;
  import org.apache.commons.rdf.api.IRI;
  
  import java.util.Optional;
  
  public class TargetAtomImpl implements TargetAtom {
  
      protected final DistinctVariableOnlyDataAtom atom;
      protected final ImmutableSubstitution<ImmutableTerm> substitution;
  
      protected TargetAtomImpl(DistinctVariableOnlyDataAtom atom, ImmutableSubstitution<ImmutableTerm> substitution) {
          this.atom = atom;
          this.substitution = substitution;
      }
  
      @Override
      public DistinctVariableOnlyDataAtom getProjectionAtom() {
          return atom;
      }
  
      @Override
      public ImmutableSubstitution<ImmutableTerm> getSubstitution() {
          return substitution;
      }
  
      @Override
      public ImmutableTerm getSubstitutedTerm(int index) {
          return substitution.applyToVariable(atom.getTerm(index));
      }
  
      @Override
      public ImmutableList<ImmutableTerm> getSubstitutedTerms() {
          return atom.getArguments().stream()
                  .map(substitution::applyToVariable)
                  .collect(ImmutableCollectors.toList());
      }
      
      @Override
      public Optional<IRI> getPredicateIRI() {
          return Optional.of(atom.getPredicate())
                  .filter(p -> p instanceof RDFAtomPredicate)
                  .map(p -> (RDFAtomPredicate) p)
                  .flatMap(p -> p.getPredicateIRI(getSubstitutedTerms()));
      }
  
      @Override
      public String toString() {
          return atom.toString() + " with " + substitution.toString();
      }
  
      @Override
      public boolean equals(Object other) {
          if (other instanceof TargetAtomImpl) {
              TargetAtomImpl targetAtom = (TargetAtomImpl)other;
              return this.atom.equals(targetAtom.atom) && this.substitution.equals(targetAtom.substitution);
          }
          return false;
      }
  }
  