/**
   * Set feature attributes using the specified values. When setting the value type, this function
   * also sets the checkboxes underneath "Attribute" node appropriately. Ideally, this should be
   * done using choice propagation, as there is a feature group constraint underneath the
   * "Attribute" node. However, because we use lazy construction of configurator, enabling choice
   * propagation is in efficient when creating so many configurations of metameta and meta features.
   * So we select and eliminate the type features in the properties view manually.
   *
   * @param feature
   * @param name
   * @param id
   * @param state
   * @param valueType
   * @param value
   * @param min
   * @param max
   */
  public static void setFeatureAttributes(
      Feature feature,
      String name,
      String id,
      ConfigState state,
      ValueType valueType,
      Object value,
      Object defaultValue,
      int min,
      int max) {
    feature.setName(name);
    feature.setId(id);
    feature.setState(state);
    feature.setValueType(valueType);

    if (valueType != ValueType.NONE_LITERAL) {
      TypedValue typedValue = null;
      if (value != null) {
        typedValue = FmpFactory.eINSTANCE.createTypedValue();
        if (value instanceof Integer) typedValue.setIntegerValue((Integer) value);
        else if (value instanceof Float) typedValue.setFloatValue((Float) value);
        else if (value instanceof String) typedValue.setStringValue((String) value);
        else if (value instanceof Feature) typedValue.setFeatureValue((Feature) value);

        feature.setTypedValue(typedValue);
      }
      TypedValue defaultTypedValue = null;
      if (defaultValue != null) {
        defaultTypedValue = FmpFactory.eINSTANCE.createTypedValue();
        if (defaultValue instanceof Integer)
          defaultTypedValue.setIntegerValue((Integer) defaultValue);
        else if (defaultValue instanceof Float)
          defaultTypedValue.setFloatValue((Float) defaultValue);
        else if (defaultValue instanceof String)
          defaultTypedValue.setStringValue((String) defaultValue);
        else if (defaultValue instanceof Feature)
          defaultTypedValue.setFeatureValue((Feature) defaultValue);

        feature.setDefaultValue(defaultTypedValue);
      }

      if (feature.getProperties() != null) {
        int typeIndex = -1;
        if (valueType == ValueType.INTEGER_LITERAL) typeIndex = 0;
        else if (valueType == ValueType.FLOAT_LITERAL) typeIndex = 1;
        else if (valueType == ValueType.STRING_LITERAL) typeIndex = 2;
        else if (valueType == ValueType.FEATURE_LITERAL) typeIndex = 3;

        Feature attributeNode =
            (Feature)
                ModelNavigation.INSTANCE.getNodes(feature.getProperties(), "Attribute").get(0);
        attributeNode.setState(ConfigState.USER_SELECTED_LITERAL);

        for (int i = 0; i < 4; i++) {
          Feature typeNode =
              (Feature) ((FeatureGroup) attributeNode.getChildren().get(0)).getChildren().get(i);
          ConfigState typeSelectionState =
              (i == typeIndex)
                  ? ConfigState.USER_SELECTED_LITERAL
                  : ConfigState.MACHINE_ELIMINATED_LITERAL;

          // set the state of the type node ("Integer", "String", or whatever)
          typeNode.setState(typeSelectionState);

          // if the type is eliminated, then eliminate all of its children as well
          if (typeSelectionState == ConfigState.MACHINE_ELIMINATED_LITERAL) {
            ((Feature) typeNode.getChildren().get(0)).setState(typeSelectionState);
            ((Feature) typeNode.getChildren().get(1)).setState(typeSelectionState);
          }
          // otherwise, select the Value node if there is a value
          // and default value node if there is a default value
          else {
            if (typedValue != null)
              ((Feature) typeNode.getChildren().get(0)).setState(typeSelectionState);
            if (defaultTypedValue != null)
              ((Feature) typeNode.getChildren().get(1)).setState(typeSelectionState);
          }
        }
      }
    }
    feature.setMin(min);
    feature.setMax(max);
  }