content: package org.aksw.rdfunit.model.impl.shacl;
  
  import java.util.Set;
  import java.util.function.Function;
  import lombok.EqualsAndHashCode;
  import lombok.Getter;
  import lombok.NonNull;
  import lombok.ToString;
  import org.aksw.rdfunit.enums.ShapeTargetType;
  import org.aksw.rdfunit.model.interfaces.shacl.ShapeTarget;
  import org.apache.jena.ext.com.google.common.collect.ImmutableSet;
  import org.apache.jena.query.ParameterizedSparqlString;
  import org.apache.jena.rdf.model.RDFNode;
  import org.apache.jena.rdf.model.Resource;
  
  @ToString(exclude = "generatePattern")
  @EqualsAndHashCode(of = {"targetType", "node"})
  public class ShapeTargetCore implements ShapeTarget {
  
    @Getter
    private final ShapeTargetType targetType;
    @Getter
    private final RDFNode node;
    private final Function<RDFNode, String> generatePattern;
  
    private ShapeTargetCore(ShapeTargetType targetType, RDFNode node,
        Function<RDFNode, String> generatePattern) {
      this.targetType = targetType;
      this.node = node;
      this.generatePattern = generatePattern;
    }
  
    public static ShapeTarget create(@NonNull ShapeTargetType targetType, @NonNull RDFNode node) {
      switch (targetType) {
        case ClassTarget:
          return new ShapeTargetCore(targetType, node, ShapeTargetCore::classTargetPattern);
        case NodeTarget:
          return new ShapeTargetCore(targetType, node, ShapeTargetCore::nodeTargetPattern);
        case ObjectsOfTarget:
          return new ShapeTargetCore(targetType, node, ShapeTargetCore::objectsOfTargetPattern);
        case SubjectsOfTarget:
          return new ShapeTargetCore(targetType, node, ShapeTargetCore::subjectsOfTargetPattern);
        default:
          throw new IllegalArgumentException("Something wrong with the input");
      }
    }
  
    private static String classTargetPattern(RDFNode node) {
      return getBindedSparql(
          " ?this <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>/<http://www.w3.org/2000/01/rdf-schema#subClassOf>* ?target . ",
          node);
    }
  
    private static String nodeTargetPattern(RDFNode node) {
      return getBindedSparql(" BIND (?target AS ?this) . ", node);
    }
  
    private static String objectsOfTargetPattern(RDFNode node) {
      return getBindedSparql(" [] ?target ?this .", node);
    }
  
    private static String subjectsOfTargetPattern(RDFNode node) {
      return getBindedSparql("?this ?target [] .", node);
    }
  
    static String getBindedSparql(String sparql, RDFNode node) {
      ParameterizedSparqlString parameterizedSparqlString = new ParameterizedSparqlString(
          "ASK{" + sparql + "}");
      parameterizedSparqlString.setParam("target", node);
      String queryPattern = parameterizedSparqlString
          .toString()
          .trim()
          .replace("ASK{", "");
      // remove last '}'
      return queryPattern.substring(0, queryPattern.length() - 1);
    }
  
    @Override
    public String getPattern() {
      return generatePattern.apply(node);
    }
  
    @Override
    public Set<Resource> getRelatedOntologyResources() {
      if (node.isURIResource() && !targetType.equals(ShapeTargetType.NodeTarget)) {
        return ImmutableSet.of(node.asResource());
      } else {
        return ImmutableSet.of();
      }
  
    }
  
  }
  