content: package alien4cloud.deployment.matching.services.location;
  
  import org.alien4cloud.tosca.model.definitions.Interface;
  import org.alien4cloud.tosca.model.definitions.Operation;
  import org.alien4cloud.tosca.model.templates.AbstractInstantiableTemplate;
  import org.alien4cloud.tosca.model.templates.NodeTemplate;
  import org.alien4cloud.tosca.model.templates.RelationshipTemplate;
  import org.alien4cloud.tosca.model.types.AbstractInstantiableToscaType;
  import org.alien4cloud.tosca.model.types.ArtifactType;
  import org.alien4cloud.tosca.utils.ToscaTypeUtils;
  import org.apache.commons.collections4.MapUtils;
  import org.apache.commons.lang3.ArrayUtils;
  import org.springframework.stereotype.Component;
  
  import alien4cloud.model.orchestrators.ArtifactSupport;
  
  /**
   * LocationMatch Elector based on supported artifacts. Checks if the artifacts of a given {@link NodeTemplate} are supported by the location's orchestrator.
   *
   */
  @Component
  public class LocationMatchNodesArtifactsElector {
  
      /**
       * Perform matching of the given match context to ensure that a given node template's implementation artifact types are indeed suported by the ones of the
       * context location match.
       * 
       * @param matchContext
       * @return
       */
      public boolean isEligible(LocationMatchNodeFilter.NodeMatchContext matchContext) {
          boolean isEligible = true;
          if (matchContext.getTemplate() == null) {
              return isEligible;
          }
          // first check the node interfaces operations artifacts are supported
          isEligible = isEligible(matchContext.getTemplate(), matchContext);
          if (isEligible) {
              // then check relationships interfaces
              isEligible = areRelationshipsArtifactSupported(matchContext);
          }
  
          return isEligible;
      }
  
      private boolean isEligible(AbstractInstantiableTemplate template, LocationMatchNodeFilter.NodeMatchContext matchContext) {
          if (template == null) {
              return true;
          }
  
          ArtifactSupport artifactSupport = matchContext.getArtifactSupport();
  
          // if no supported artifact defined, then return true
          if (artifactSupport == null || ArrayUtils.isEmpty(artifactSupport.getTypes())) {
              return true;
          }
          String[] supportedArtifacts = artifactSupport.getTypes();
  
          AbstractInstantiableToscaType indexedArtifactToscaElement = matchContext.getElement(AbstractInstantiableToscaType.class, template.getType());
  
          if (MapUtils.isNotEmpty(indexedArtifactToscaElement.getInterfaces())) {
              for (Interface interfaz : indexedArtifactToscaElement.getInterfaces().values()) {
                  for (Operation operation : interfaz.getOperations().values()) {
                      if (operation.getImplementationArtifact() != null) {
                          String artifactTypeString = operation.getImplementationArtifact().getArtifactType();
  
                          ArtifactType artifactType = matchContext.getElement(ArtifactType.class, artifactTypeString);
  
                          // stop the checking once one artifactType is not supported
                          if (!isFromOneOfTypes(supportedArtifacts, artifactType)) {
                              return false;
                          }
                      }
                  }
              }
          }
  
          return true;
      }
  
      private boolean isFromOneOfTypes(String[] supportedArtifacts, ArtifactType artifactType) {
          for (String supportedArtifact : supportedArtifacts) {
              if (ToscaTypeUtils.isOfType(artifactType, supportedArtifact)) {
                  return true;
              }
          }
          return false;
      }
  
      private boolean areRelationshipsArtifactSupported(LocationMatchNodeFilter.NodeMatchContext matchContext) {
          if (MapUtils.isNotEmpty(matchContext.getTemplate().getRelationships())) {
              for (RelationshipTemplate relTemplate : matchContext.getTemplate().getRelationships().values()) {
                  if (!isEligible(relTemplate, matchContext)) {
                      return false;
                  }
              }
          }
  
          return true;
      }
  }
  