code: /**
   * This file is part of Eclipse Steady.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   * SPDX-License-Identifier: Apache-2.0
   * SPDX-FileCopyrightText: Copyright (c) 2018-2020 SAP SE or an SAP affiliate company and Eclipse Steady contributors
   */
  package org.eclipse.steady.java.sign;
  
  import java.util.Collection;
  import java.util.Enumeration;
  import java.util.HashSet;
  import java.util.Set;
  
  import javax.validation.constraints.NotNull;
  
  import org.apache.logging.log4j.Logger;
  
  import ch.uzh.ifi.seal.changedistiller.model.classifiers.ChangeType;
  import ch.uzh.ifi.seal.changedistiller.model.classifiers.EntityType;
  import ch.uzh.ifi.seal.changedistiller.model.classifiers.java.JavaEntityType;
  import ch.uzh.ifi.seal.changedistiller.model.entities.SourceCodeEntity;
  import ch.uzh.ifi.seal.changedistiller.treedifferencing.Node;
  
  /**
   * Implements different methods for comparing nodes (incl. their descendents).
   */
  public class ASTUtil {
  
    private static final Logger log = org.apache.logging.log4j.LogManager.getLogger();
  
    public static enum NODE_COMPARE_MODE {
      ENTITY_TYPE,
      VALUE
    };
  
    /**
     * Returns true if the nodes are equal with regard to parameter mode.
     *
     * @param _mode a {@link org.eclipse.steady.java.sign.ASTUtil.NODE_COMPARE_MODE} object.
     * @param _left a {@link ch.uzh.ifi.seal.changedistiller.treedifferencing.Node} object.
     * @param _right a {@link ch.uzh.ifi.seal.changedistiller.treedifferencing.Node} object.
     * @return a boolean.
     * @throws java.lang.IllegalArgumentException if any.
     */
    public static final boolean isEqual(
        @NotNull Node _left, @NotNull Node _right, @NotNull NODE_COMPARE_MODE _mode)
        throws IllegalArgumentException {
      boolean is_equal = true;
      final Enumeration enum_left = _left.depthFirstEnumeration();
      final Enumeration enum_right = _right.depthFirstEnumeration();
      Node node_left = null, node_right = null;
  
      // Traverse left tree and compare one by one
      while (enum_left.hasMoreElements()) {
        node_left = (Node) enum_left.nextElement();
  
        // Compare the nodes
        if (enum_right.hasMoreElements()) {
          node_right = (Node) enum_right.nextElement();
  
          if (_mode.equals(NODE_COMPARE_MODE.ENTITY_TYPE)) {
            if (!node_left.getLabel().equals(node_right.getLabel())) {
              is_equal = false;
            }
          } else if (_mode.equals(NODE_COMPARE_MODE.VALUE)) {
            if (!node_left.getValue().equals(node_right.getValue())) {
              is_equal = false;
            }
          } else {
            throw new IllegalArgumentException("Illegal comparison mode: [" + _mode + "]");
          }
        }
        // Right tree has less elements
        else {
          is_equal = false;
        }
  
        // Stop comparison upon first difference
        if (!is_equal) break;
      }
  
      // Equal until now but right tree has more nodes?
      if (is_equal && enum_right.hasMoreElements()) {
        is_equal = false;
      }
  
      return is_equal;
    }
  
    /**
     * <p>intersectSourceCodeChanges.</p>
     *
     * @param _a a {@link java.util.Collection} object.
     * @param _b a {@link java.util.Collection} object.
     * @param _relaxed a boolean.
     * @return a {@link java.util.Set} object.
     */
    public static final Set<Object> intersectSourceCodeChanges(
        Collection _a, Collection _b, boolean _relaxed) {
      SourceCodeEntity.setIgnoreSourceRange(true);
      if (_relaxed) SourceCodeEntity.setUniqueNamePreprocessor(UniqueNameNormalizer.getInstance());
      else SourceCodeEntity.setUniqueNamePreprocessor(null);
  
      final Set<Object> intersection = new HashSet<Object>();
      outer:
      for (Object o1 : _b) {
        int i = 0;
        for (Object o2 : _a) {
          if (o1.equals(o2)) {
            ASTUtil.log.info("                                   Added change [" + o1 + "]");
            intersection.add(o1);
            continue outer;
          }
        }
      }
      SourceCodeEntity.setIgnoreSourceRange(false);
      return intersection;
    }
  
    /**
     * <p>intersectSourceCodeChanges.</p>
     *
     * @param _a a {@link java.util.Collection} object.
     * @param _b a {@link java.util.Collection} object.
     * @param _relaxed a boolean.
     * @param _cn ClassName
     * @return a {@link java.util.Set} object.
     */
    public static final Set<Object> intersectSourceCodeChanges(
        Collection _a, Collection _b, boolean _relaxed, String _cn) {
      UniqueNameNormalizer uniqueNN = UniqueNameNormalizer.getInstance();
      uniqueNN.setClassUnderAnalysisName(_cn);
      SourceCodeEntity.setIgnoreSourceRange(true);
      if (_relaxed) SourceCodeEntity.setUniqueNamePreprocessor(uniqueNN);
      else SourceCodeEntity.setUniqueNamePreprocessor(null);
  
      final Set<Object> intersection = new HashSet<Object>();
      outer:
      for (Object o1 : _b) {
        int i = 0;
        for (Object o2 : _a) {
          if (o1.equals(o2)) {
            ASTUtil.log.info("                                   Added change [" + o1 + "]");
            intersection.add(o1);
            continue outer;
          }
        }
      }
      SourceCodeEntity.setIgnoreSourceRange(false);
      return intersection;
    }
  
    /**
     *  Maps string representation of {@link ChangeType} to the corresponding enumeration value.
     *
     * @param changeType - String representation of changeType
     * @return instance of ChangeType corresponding to the SourceCodeChange EntityType
     */
    public static ChangeType getChangeType(String changeType) {
  
      ChangeType type = null;
  
      if (changeType.equals("ADDING_ATTRIBUTE_MODIFIABILITY")) {
        type = ChangeType.ADDING_ATTRIBUTE_MODIFIABILITY;
      } else if (changeType.equals("ADDING_CLASS_DERIVABILITY")) {
        type = ChangeType.ADDING_CLASS_DERIVABILITY;
      } else if (changeType.equals("ADDING_METHOD_OVERRIDABILITY")) {
        type = ChangeType.ADDING_METHOD_OVERRIDABILITY;
      } else if (changeType.equals("ADDITIONAL_CLASS")) {
        type = ChangeType.ADDITIONAL_CLASS;
      } else if (changeType.equals("ADDITIONAL_FUNCTIONALITY")) {
        type = ChangeType.ADDITIONAL_FUNCTIONALITY;
      } else if (changeType.equals("ADDITIONAL_OBJECT_STATE")) {
        type = ChangeType.ADDITIONAL_OBJECT_STATE;
      } else if (changeType.equals("ALTERNATIVE_PART_DELETE")) {
        type = ChangeType.ALTERNATIVE_PART_DELETE;
      } else if (changeType.equals("ALTERNATIVE_PART_INSERT")) {
        type = ChangeType.ALTERNATIVE_PART_INSERT;
      } else if (changeType.equals("ATTRIBUTE_RENAMING")) {
        type = ChangeType.ATTRIBUTE_RENAMING;
      } else if (changeType.equals("ATTRIBUTE_TYPE_CHANGE")) {
        type = ChangeType.ATTRIBUTE_TYPE_CHANGE;
      } else if (changeType.equals("CLASS_RENAMING")) {
        type = ChangeType.CLASS_RENAMING;
      } else if (changeType.equals("COMMENT_DELETE")) {
        type = ChangeType.COMMENT_DELETE;
      } else if (changeType.equals("COMMENT_INSERT")) {
        type = ChangeType.COMMENT_INSERT;
      } else if (changeType.equals("COMMENT_MOVE")) {
        type = ChangeType.COMMENT_MOVE;
      } else if (changeType.equals("COMMENT_UPDATE")) {
        type = ChangeType.COMMENT_UPDATE;
      } else if (changeType.equals("CONDITION_EXPRESSION_CHANGE")) {
        type = ChangeType.CONDITION_EXPRESSION_CHANGE;
      } else if (changeType.equals("DECREASING_ACCESSIBILITY_CHANGE")) {
        type = ChangeType.DECREASING_ACCESSIBILITY_CHANGE;
      } else if (changeType.equals("DOC_DELETE")) {
        type = ChangeType.DOC_DELETE;
      } else if (changeType.equals("DOC_INSERT")) {
        type = ChangeType.DOC_INSERT;
      } else if (changeType.equals("DOC_UPDATE")) {
        type = ChangeType.DOC_UPDATE;
      } else if (changeType.equals("INCREASING_ACCESSIBILITY_CHANGE")) {
        type = ChangeType.INCREASING_ACCESSIBILITY_CHANGE;
      } else if (changeType.equals("METHOD_RENAMING")) {
        type = ChangeType.METHOD_RENAMING;
      } else if (changeType.equals("PARAMETER_DELETE")) {
        type = ChangeType.PARAMETER_DELETE;
      } else if (changeType.equals("PARAMETER_INSERT")) {
        type = ChangeType.PARAMETER_INSERT;
      } else if (changeType.equals("PARAMETER_ORDERING_CHANGE")) {
        type = ChangeType.PARAMETER_ORDERING_CHANGE;
      } else if (changeType.equals("PARAMETER_RENAMING")) {
        type = ChangeType.PARAMETER_RENAMING;
      } else if (changeType.equals("PARAMETER_TYPE_CHANGE")) {
        type = ChangeType.PARAMETER_TYPE_CHANGE;
      } else if (changeType.equals("PARENT_CLASS_CHANGE")) {
        type = ChangeType.PARENT_CLASS_CHANGE;
      } else if (changeType.equals("PARENT_CLASS_DELETE")) {
        type = ChangeType.PARENT_CLASS_DELETE;
      } else if (changeType.equals("PARENT_CLASS_INSERT")) {
        type = ChangeType.PARENT_CLASS_INSERT;
      } else if (changeType.equals("PARENT_INTERFACE_CHANGE")) {
        type = ChangeType.PARENT_INTERFACE_CHANGE;
      } else if (changeType.equals("PARENT_INTERFACE_DELETE")) {
        type = ChangeType.PARENT_INTERFACE_DELETE;
      } else if (changeType.equals("PARENT_INTERFACE_INSERT")) {
        type = ChangeType.PARENT_INTERFACE_INSERT;
      } else if (changeType.equals("REMOVED_CLASS")) {
        type = ChangeType.REMOVED_CLASS;
      } else if (changeType.equals("REMOVED_FUNCTIONALITY")) {
        type = ChangeType.REMOVED_FUNCTIONALITY;
      } else if (changeType.equals("REMOVED_OBJECT_STATE")) {
        type = ChangeType.REMOVED_OBJECT_STATE;
      } else if (changeType.equals("REMOVING_ATTRIBUTE_MODIFIABILITY")) {
        type = ChangeType.REMOVING_ATTRIBUTE_MODIFIABILITY;
      } else if (changeType.equals("REMOVING_CLASS_DERIVABILITY")) {
        type = ChangeType.REMOVING_CLASS_DERIVABILITY;
      } else if (changeType.equals("REMOVING_METHOD_OVERRIDABILITY")) {
        type = ChangeType.REMOVING_METHOD_OVERRIDABILITY;
      } else if (changeType.equals("RETURN_TYPE_CHANGE")) {
        type = ChangeType.RETURN_TYPE_CHANGE;
      } else if (changeType.equals("RETURN_TYPE_DELETE")) {
        type = ChangeType.RETURN_TYPE_DELETE;
      } else if (changeType.equals("RETURN_TYPE_INSERT")) {
        type = ChangeType.RETURN_TYPE_INSERT;
      } else if (changeType.equals("STATEMENT_DELETE")) {
        type = ChangeType.STATEMENT_DELETE;
      } else if (changeType.equals("STATEMENT_INSERT")) {
        type = ChangeType.STATEMENT_INSERT;
      } else if (changeType.equals("STATEMENT_ORDERING_CHANGE")) {
        type = ChangeType.STATEMENT_ORDERING_CHANGE;
      } else if (changeType.equals("STATEMENT_PARENT_CHANGE")) {
        type = ChangeType.STATEMENT_PARENT_CHANGE;
      } else if (changeType.equals("STATEMENT_UPDATE")) {
        type = ChangeType.STATEMENT_UPDATE;
      } else if (changeType.equals("UNCLASSIFIED_CHANGE")) {
        type = ChangeType.UNCLASSIFIED_CHANGE;
      } else {
        // Default
        type = ChangeType.UNCLASSIFIED_CHANGE;
      }
  
      return type;
    }
  
    /**
     * Helper method for mapping the JaveEntityTypes  for source code entities to string name of EntityType in the JSON
     * TODO : It might be better to move this into a BaseClass, might also be used for deserializing SourceCodeChange
     *
     * @return Corresponding EntityType
     *
     * Number of SourceCodeEntityTypes
     * @param type a {@link java.lang.String} object.
     */
    public static EntityType getJavaEntityType(String type) {
      EntityType entityType = null;
  
      if (type.equals("METHOD")) {
        entityType = JavaEntityType.METHOD;
      } else if (type.equals("ARGUMENTS")) {
        entityType = JavaEntityType.ARGUMENTS;
      } else if (type.equals("ARRAY_ACCESS")) {
        entityType = JavaEntityType.ARRAY_ACCESS;
      } else if (type.equals("ARRAY_CREATION")) {
        entityType = JavaEntityType.ARRAY_CREATION;
      } else if (type.equals("ARRAY_INITIALIZER")) {
        entityType = JavaEntityType.ARRAY_INITIALIZER;
      } else if (type.equals("ARRAY_TYPE")) {
        entityType = JavaEntityType.ARRAY_TYPE;
      } else if (type.equals("ASSERT_STATEMENT")) {
        entityType = JavaEntityType.ASSERT_STATEMENT;
      } else if (type.equals("ASSIGNMENT")) {
        entityType = JavaEntityType.ASSIGNMENT;
      } else if (type.equals("FIELD")) {
        entityType = JavaEntityType.FIELD;
      } else if (type.equals("BLOCK")) {
        entityType = JavaEntityType.BLOCK;
      } else if (type.equals("BLOCK_COMMENT")) {
        entityType = JavaEntityType.BLOCK_COMMENT;
      } else if (type.equals("BODY")) {
        entityType = JavaEntityType.BODY;
      } else if (type.equals("BOOLEAN_LITERAL")) {
        entityType = JavaEntityType.BOOLEAN_LITERAL;
      } else if (type.equals("BREAK_STATEMENT")) {
        entityType = JavaEntityType.BREAK_STATEMENT;
      } else if (type.equals("CAST_EXPRESSION")) {
        entityType = JavaEntityType.CAST_EXPRESSION;
      } else if (type.equals("CATCH_CLAUSE")) {
        entityType = JavaEntityType.CATCH_CLAUSE;
      } else if (type.equals("CATCH_CLAUSES")) {
        entityType = JavaEntityType.CATCH_CLAUSES;
      } else if (type.equals("CHARACTER_LITERAL")) {
        entityType = JavaEntityType.CHARACTER_LITERAL;
      } else if (type.equals("CLASS")) {
        entityType = JavaEntityType.CLASS;
      } else if (type.equals("CLASS_INSTANCE_CREATION")) {
        entityType = JavaEntityType.CLASS_INSTANCE_CREATION;
      } else if (type.equals("COMPILATION_UNIT")) {
        entityType = JavaEntityType.COMPILATION_UNIT;
      } else if (type.equals("CONDITIONAL_EXPRESSION")) {
        entityType = JavaEntityType.CONDITIONAL_EXPRESSION;
      } else if (type.equals("CONSTRUCTOR_INVOCATION")) {
        entityType = JavaEntityType.CONSTRUCTOR_INVOCATION;
      } else if (type.equals("CONTINUE_STATEMENT")) {
        entityType = JavaEntityType.CONTINUE_STATEMENT;
      } else if (type.equals("DO_STATEMENT")) {
        entityType = JavaEntityType.DO_STATEMENT;
      } else if (type.equals("ELSE_STATEMENT")) {
        entityType = JavaEntityType.ELSE_STATEMENT;
      } else if (type.equals("EMPTY_STATEMENT")) {
        entityType = JavaEntityType.EMPTY_STATEMENT;
      } else if (type.equals("FOREACH_STATEMENT")) {
        entityType = JavaEntityType.FOREACH_STATEMENT;
      } else if (type.equals("FIELD_ACCESS")) {
        entityType = JavaEntityType.FIELD_ACCESS;
      } else if (type.equals("FIELD_DECLARATION")) {
        entityType = JavaEntityType.FIELD_DECLARATION;
      } else if (type.equals("FINALLY")) {
        entityType = JavaEntityType.FINALLY;
      } else if (type.equals("FOR_STATEMENT")) {
        entityType = JavaEntityType.FOR_STATEMENT;
      } else if (type.equals("IF_STATEMENT")) {
        entityType = JavaEntityType.IF_STATEMENT;
      } else if (type.equals("INFIX_EXPRESSION")) {
        entityType = JavaEntityType.INFIX_EXPRESSION;
      } else if (type.equals("INSTANCEOF_EXPRESSION")) {
        entityType = JavaEntityType.INSTANCEOF_EXPRESSION;
      } else if (type.equals("JAVADOC")) {
        entityType = JavaEntityType.JAVADOC;
      } else if (type.equals("LABELED_STATEMENT")) {
        entityType = JavaEntityType.LABELED_STATEMENT;
      } else if (type.equals("LINE_COMMENT")) {
        entityType = JavaEntityType.LINE_COMMENT;
      } else if (type.equals("METHOD_DECLARATION")) {
        entityType = JavaEntityType.METHOD_DECLARATION;
      } else if (type.equals("METHOD_INVOCATION")) {
        entityType = JavaEntityType.METHOD_INVOCATION;
      } else if (type.equals("MODIFIER")) {
        entityType = JavaEntityType.MODIFIER;
      } else if (type.equals("MODIFIERS")) {
        entityType = JavaEntityType.MODIFIERS;
      } else if (type.equals("NULL_LITERAL")) {
        entityType = JavaEntityType.NULL_LITERAL;
      } else if (type.equals("NUMBER_LITERAL")) {
        entityType = JavaEntityType.NUMBER_LITERAL;
      } else if (type.equals("PARAMETERIZED_TYPE")) {
        entityType = JavaEntityType.PARAMETERIZED_TYPE;
      } else if (type.equals("PARAMETERS")) {
        entityType = JavaEntityType.PARAMETERS;
      } else if (type.equals("PARAMETER")) {
        entityType = JavaEntityType.PARAMETER;
      } else if (type.equals("POSTFIX_EXPRESSION")) {
        entityType = JavaEntityType.POSTFIX_EXPRESSION;
      } else if (type.equals("PREFIX_EXPRESSION")) {
        entityType = JavaEntityType.PREFIX_EXPRESSION;
      } else if (type.equals("PRIMITIVE_TYPE")) {
        entityType = JavaEntityType.PRIMITIVE_TYPE;
      } else if (type.equals("QUALIFIED_NAME")) {
        entityType = JavaEntityType.QUALIFIED_NAME;
      } else if (type.equals("QUALIFIED_TYPE")) {
        entityType = JavaEntityType.QUALIFIED_TYPE;
      } else if (type.equals("RETURN_STATEMENT")) {
        entityType = JavaEntityType.RETURN_STATEMENT;
      } else if (type.equals("ROOT_NODE")) {
        entityType = JavaEntityType.ROOT_NODE;
      } else if (type.equals("SIMPLE_NAME")) {
        entityType = JavaEntityType.SIMPLE_NAME;
      } else if (type.equals(" SINGLE_TYPE")) {
        entityType = JavaEntityType.SINGLE_TYPE;
      } else if (type.equals("STRING_LITERAL")) {
        entityType = JavaEntityType.STRING_LITERAL;
      } else if (type.equals("SUPER_INTERFACE_TYPES")) {
        entityType = JavaEntityType.SUPER_INTERFACE_TYPES;
      } else if (type.equals("SWITCH_STATEMENT")) {
        entityType = JavaEntityType.SWITCH_STATEMENT;
      } else if (type.equals("SWITCH_STATEMENT")) {
        entityType = JavaEntityType.SWITCH_STATEMENT;
      } else if (type.equals("SYNCHRONIZED_STATEMENT")) {
        entityType = JavaEntityType.SYNCHRONIZED_STATEMENT;
      } else if (type.equals("THEN_STATEMENT")) {
        entityType = JavaEntityType.THEN_STATEMENT;
      } else if (type.equals("THROW")) {
        entityType = JavaEntityType.THROW;
      } else if (type.equals("THROW_STATEMENT")) {
        entityType = JavaEntityType.THROW_STATEMENT;
      } else if (type.equals("TRY_STATEMENT")) {
        entityType = JavaEntityType.TRY_STATEMENT;
      } else if (type.equals("TYPE_PARAMETERS")) {
        entityType = JavaEntityType.TYPE_PARAMETERS;
      } else if (type.equals("TYPE_DECLARATION")) {
        entityType = JavaEntityType.TYPE_DECLARATION;
      } else if (type.equals("TYPE_LITERAL")) {
        entityType = JavaEntityType.TYPE_LITERAL;
      } else if (type.equals("TYPE_PARAMETER")) {
        entityType = JavaEntityType.TYPE_PARAMETER;
      } else if (type.equals("VARIABLE_DECLARATION_STATEMENT")) {
        entityType = JavaEntityType.VARIABLE_DECLARATION_STATEMENT;
      } else if (type.equals("WHILE_STATEMENT")) {
        entityType = JavaEntityType.WHILE_STATEMENT;
      } else if (type.equals("WILDCARD_TYPE")) {
        entityType = JavaEntityType.WILDCARD_TYPE;
      } else if (type.equals("FOR_INIT")) {
        entityType = JavaEntityType.FOR_INIT;
      } else if (type.equals("FOR_INCR")) {
        entityType = JavaEntityType.FOR_INCR;
      } else {
        // Default Entity Type
        entityType = JavaEntityType.METHOD;
      }
  
      return entityType;
    }
  }
  