public void convertEnums(
      List<Enum> enums,
      Signatures signatures,
      DeclarationsHolder out,
      Identifier libraryClassName) {
    if (enums != null) {
      // out.println("public static class ENUMS {");
      for (com.ochafik.lang.jnaerator.parser.Enum e : enums) {
        if (e.findParentOfType(Struct.class) != null) continue;

        convertEnum(e, signatures, out, libraryClassName);
      }
      // out.println("}");
    }
  }
  protected List<EnumItemResult> getEnumValuesAndCommentsByName(
      Enum e, Signatures signatures, Identifier libraryClassName) {
    List<EnumItemResult> ret = new ArrayList<EnumItemResult>();
    Integer lastAdditiveValue = null;
    Expression lastRefValue = null;
    boolean failedOnceForThisEnum = false;
    for (com.ochafik.lang.jnaerator.parser.Enum.EnumItem item : e.getItems()) {
      EnumItemResult res = new EnumItemResult();
      res.originalItem = item;
      try {
        if (item.getArguments().isEmpty()) {
          // no explicit value
          if (lastRefValue == null) {
            if (lastAdditiveValue != null) {
              lastAdditiveValue++;
              res.unconvertedValue = expr(lastAdditiveValue);
            } else {
              if (item == e.getItems().get(0)) {
                lastAdditiveValue = 0;
                res.unconvertedValue = expr(lastAdditiveValue);
              } else res.unconvertedValue = null;
            }
          } else {
            // has a last reference value
            if (lastAdditiveValue != null) lastAdditiveValue++;
            else lastAdditiveValue = 1;

            res.unconvertedValue =
                expr(lastRefValue.clone(), Expression.BinaryOperator.Plus, expr(lastAdditiveValue));
          }
        } else {
          // has an explicit value
          failedOnceForThisEnum = false; // reset skipping
          lastAdditiveValue = null;
          lastRefValue = item.getArguments().get(0);
          res.unconvertedValue = lastRefValue;
          if (lastRefValue instanceof Expression.Constant) {
            try {
              lastAdditiveValue = ((Expression.Constant) lastRefValue).asInteger();
              lastRefValue = null;
            } catch (Exception ex) {
            }
          }
        }

        res.convertedValue =
            result
                .typeConverter
                .convertExpressionToJava(res.unconvertedValue, libraryClassName, true)
                .getFirst();
      } catch (Exception ex) {
        failedOnceForThisEnum = true;
        res.exceptionMessage = ex.toString();
      }
      failedOnceForThisEnum = failedOnceForThisEnum || res.errorElement != null;
      if (failedOnceForThisEnum) res.errorElement = skipDeclaration(item);

      ret.add(res);
    }
    return ret;
  }
  @Override
  public void visitEnum(Enum e) {
    super.visitEnum(e);
    if (e.getTag() == null) {
      // Hack to infer the enum name from the next typedef NSUInteger
      // NSSomethingThatLooksLikeTheEnumsIdentifiers
      Element nextDeclaration = e.getNextSibling();
      if (nextDeclaration != null && (nextDeclaration instanceof TypeDef)) {
        TypeDef typeDef = (TypeDef) nextDeclaration;
        TypeRef type = typeDef.getValueType();
        if (type instanceof TypeRef.SimpleTypeRef) {
          String simpleTypeStr = ((TypeRef.SimpleTypeRef) type).getName().toString();
          if (simpleTypeStr.equals("NSUInteger")
              || simpleTypeStr.equals("NSInteger")
              || simpleTypeStr.equals("CFIndex")) {
            Declarator bestPlainStorage = null;
            for (Declarator st : typeDef.getDeclarators()) {
              if (st instanceof DirectDeclarator) {
                String name = st.resolveName();
                boolean niceName = StringUtils.trimUnderscores(name).equals(name);
                ;
                if (bestPlainStorage == null || niceName) {
                  bestPlainStorage = st;
                  if (niceName) break;
                }
              }
            }
            if (bestPlainStorage != null) {
              String name = bestPlainStorage.resolveName();
              System.err.println("Automatic struct name matching : " + name);
              e.setTag(ident(name));
            }
          }
        }
      }
    }

    Identifier name = e.getTag();
    String lib = getLibrary(e);
    if (name == null) getList(enumsByLibrary, lib).add(e);
    else {
      Enum oldEnum = enumsByName.get(name);

      if (oldEnum == null
          || oldEnum.isForwardDeclaration()
          || (!(oldEnum.getParentElement() instanceof TypeDef)
              && oldEnum.getParentElement() instanceof TypeDef)) {
        enumsByName.put(name, e);

        // if (e.getTag() != null) {
        //	enumsByName.put(e.getTag(), e);
        // }
        getList(enumsByLibrary, lib).add(e);

        Identifier identifier = getTaggedTypeIdentifierInJava(e);
        if (identifier != null) {
          enumsFullNames.add(identifier);
        }
      }
    }
  }