// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi.util;

import com.intellij.core.JavaPsiBundle;
import com.intellij.psi.*;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;

import java.util.Locale;

/**
 * Represents a kind of element that appears in Java source code.
 * The main purpose of this enum is to be able to display localized element name in UI
 */
public enum JavaElementKind {
  ABSTRACT_METHOD,
  ANNOTATION,
  CLASS,
  CONSTANT,
  CONSTRUCTOR,
  ENUM,
  ENUM_CONSTANT,
  EXPRESSION,
  FIELD,
  INITIALIZER,
  INTERFACE,
  LOCAL_VARIABLE,
  METHOD,
  MODULE,
  PACKAGE,
  PARAMETER,
  PATTERN_VARIABLE,
  RECORD,
  RECORD_COMPONENT,
  STATEMENT,
  UNKNOWN,
  VARIABLE;

  /**
   * @return human-readable name of the item having the subject role in the sentence (nominative case)
   */
  @Nls
  public @NotNull String subject() {
    return JavaPsiBundle.message("element." + name().toLowerCase(Locale.ROOT), 0);
  }

  /**
   * @return human-readable name of the item having the object role in the sentence (accusative case)
   */
  @Nls
  public @NotNull String object() {
    return JavaPsiBundle.message("element." + name().toLowerCase(Locale.ROOT), 1);
  }

  public static JavaElementKind fromElement(@NotNull PsiElement element) {
    if (element instanceof PsiClass) {
      PsiClass psiClass = (PsiClass)element;
      if (psiClass.isEnum()) {
        return ENUM;
      }
      if (psiClass.isRecord()) {
        return RECORD;
      }
      if (psiClass.isAnnotationType()) {
        return ANNOTATION;
      }
      if (psiClass.isInterface()) {
        return INTERFACE;
      }
      return CLASS;
    }
    if (element instanceof PsiMethod) {
      if (((PsiMethod)element).isConstructor()) {
        return CONSTRUCTOR;
      }
      if (((PsiMethod)element).hasModifierProperty(PsiModifier.ABSTRACT)) {
        return ABSTRACT_METHOD;
      }
      return METHOD;
    }
    if (element instanceof PsiField) {
      PsiField field = (PsiField)element;
      if (field instanceof PsiEnumConstant) {
        return ENUM_CONSTANT;
      }
      if (field.hasModifierProperty(PsiModifier.STATIC) && field.hasModifierProperty(PsiModifier.FINAL)) {
        return CONSTANT;
      }
      return FIELD;
    }
    if (element instanceof PsiRecordComponent) {
      return RECORD_COMPONENT;
    }
    if (element instanceof PsiLocalVariable) {
      return LOCAL_VARIABLE;
    }
    if (element instanceof PsiPatternVariable) {
      return PATTERN_VARIABLE;
    }
    if (element instanceof PsiParameter) {
      return PARAMETER;
    }
    if (element instanceof PsiVariable) {
      return VARIABLE;
    }
    if (element instanceof PsiPackage) {
      return PACKAGE;
    }
    if (element instanceof PsiJavaModule) {
      return MODULE;
    }
    if (element instanceof PsiClassInitializer) {
      return INITIALIZER;
    }
    if (element instanceof PsiStatement) {
      return STATEMENT;
    }
    if (element instanceof PsiExpression) {
      return EXPRESSION;
    }
    return UNKNOWN;
  }
}

@@ -312,16 +312,62 @@
 NotNull;
+%0Aimport org.jetbrains.annotations.PropertyKey;
 %0A%0Aimport
@@ -598,283 +598,955 @@
 THOD
-,%0A  ANNOTATION,%0A  CLASS,%0A  CONSTANT,%0A  CONSTRUCTOR,%0A  ENUM,%0A  ENUM_CONSTANT,%0A  EXPRESSION,%0A  FIELD,%0A  INITIALIZER,%0A  INTERFACE,%0A  LOCAL_VARIABLE,%0A  METHOD,%0A  MODULE,%0A  PACKAGE,%0A  PARAMETER,%0A  PATTERN_VARIABLE,%0A  RECORD,%0A  RECORD_COMPONENT,%0A  STATEMENT,%0A  UNKNOWN,%0A  VARIABLE;
+(%22element.abstract_method%22),%0A  ANNOTATION(%22element.annotation%22),%0A  CLASS(%22element.class%22),%0A  CONSTANT(%22element.constant%22),%0A  CONSTRUCTOR(%22element.constructor%22),%0A  ENUM(%22element.enum%22),%0A  ENUM_CONSTANT(%22element.enum_constant%22),%0A  EXPRESSION(%22element.expression%22),%0A  FIELD(%22element.field%22),%0A  INITIALIZER(%22element.initializer%22),%0A  INTERFACE(%22element.interface%22),%0A  LOCAL_VARIABLE(%22element.local_variable%22),%0A  METHOD(%22element.method%22),%0A  MODULE(%22element.module%22),%0A  PACKAGE(%22element.package%22),%0A  PARAMETER(%22element.parameter%22),%0A  PATTERN_VARIABLE(%22element.pattern_variable%22),%0A  RECORD(%22element.record%22),%0A  RECORD_COMPONENT(%22element.record_component%22),%0A  STATEMENT(%22element.statement%22),%0A  UNKNOWN(%22element.unknown%22),%0A  VARIABLE(%22element.variable%22);%0A  %0A  private final @PropertyKey(resourceBundle = JavaPsiBundle.BUNDLE) String propertyKey;%0A%0A  JavaElementKind(@PropertyKey(resourceBundle = JavaPsiBundle.BUNDLE) String key) %7B%0A    propertyKey = key;%0A  %7D
 %0A%0A  
@@ -1739,52 +1739,19 @@
 age(
-%22element.%22 + name().toLowerCase(Locale.ROOT)
+propertyKey
 , 0)
@@ -1951,52 +1951,19 @@
 age(
-%22element.%22 + name().toLowerCase(Locale.ROOT)
+propertyKey
 , 1)

use explicit property keys