/*
 * Copyright 2013-2016 consulo.io
 *
 * 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.
 */
package consulo.psi.tree;

import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.ReflectionUtil;
import consulo.logging.Logger;
import org.jetbrains.annotations.NonNls;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import java.lang.reflect.Constructor;

/**
 * @author VISTALL
 * @since 13:28/29.08.13
 */
public class ElementTypeAsPsiFactory extends IElementType implements IElementTypeAsPsiFactory {
  public static final Logger LOGGER = Logger.getInstance(ElementTypeAsPsiFactory.class);

  private Constructor<? extends PsiElement> myConstructor;

  public ElementTypeAsPsiFactory(@Nonnull @NonNls String debugName, @Nullable Language language, @Nonnull Class<? extends PsiElement> clazz) {
    this(debugName, language, true, clazz);
  }

  public ElementTypeAsPsiFactory(@Nonnull @NonNls String debugName,
                                 @Nullable Language language,
                                 boolean register,
                                 @Nonnull Class<? extends PsiElement> clazz) {
    super(debugName, language, register);

    try {
      myConstructor = clazz.getConstructor(ASTNode.class);
    }
    catch (NoSuchMethodException e) {
      ElementTypeAsPsiFactory
              .LOGGER.error("Cant find constructor for " + clazz.getName() + " with argument: " + ASTNode.class.getName() + ", or it not public.", e);
    }
  }

  @Override
  @Nonnull
  public PsiElement createElement(@Nonnull ASTNode astNode) {
    if (myConstructor == null) {
      return PsiUtilCore.NULL_PSI_ELEMENT;
    }
    return ReflectionUtil.createInstance(myConstructor, astNode);
  }
}

@@ -865,64 +865,67 @@
 ulo.
-logging.Logger;%0Aimport org.jetbrains.annotations.NonNls;
+annotation.DeprecationInfo;%0Aimport consulo.logging.Logger;%0A
 %0Aimp
@@ -988,17 +988,16 @@
 llable;%0A
-%0A
 import j
@@ -1025,16 +1025,52 @@
 tructor;
+%0Aimport java.util.function.Function;
 %0A%0A/**%0A *
@@ -1214,21 +1214,22 @@
 ry %7B%0A  p
-ublic
+rivate
  static 
@@ -1244,19 +1244,16 @@
 gger LOG
-GER
  = Logge
@@ -1305,65 +1305,179 @@
 %0A%0A  
-private Constructor%3C? extends PsiElement%3E myConstructor;%0A
+@Nonnull%0A  private final Function%3CASTNode, ? extends PsiElement%3E myFactory;%0A%0A  @Deprecated(forRemoval = true)%0A  @DeprecationInfo(%22Use constructor with Function parameter%22)
 %0A  p
@@ -1511,32 +1511,24 @@
 ry(@Nonnull 
-@NonNls 
 String debug
@@ -1657,16 +1657,111 @@
 );%0A  %7D%0A%0A
+  @Deprecated(forRemoval = true)%0A  @DeprecationInfo(%22Use constructor with Function parameter%22)%0A
   public
@@ -1798,16 +1798,8 @@
 ull 
-@NonNls 
 Stri
@@ -1815,154 +1815,55 @@
 ame,
-%0A                                 @Nullable Language language,%0A                                 boolean register,%0A                                
+ @Nullable Language language, boolean register,
  @No
@@ -1948,16 +1948,67 @@
 ster);%0A%0A
+    Function%3CASTNode, PsiElement%3E function = null;%0A
     try 
@@ -2015,18 +2015,16 @@
 %7B%0A      
-my
 Construc
@@ -2026,16 +2026,50 @@
 structor
+%3C? extends PsiElement%3E constructor
  = clazz
@@ -2100,16 +2100,87 @@
 class);%0A
+      function = it -%3E ReflectionUtil.createInstance(constructor, it);%0A
     %7D%0A  
@@ -2225,53 +2225,11 @@
     
-ElementTypeAsPsiFactory%0A              .LOGGER
+LOG
 .err
@@ -2364,35 +2364,127 @@
   %7D%0A
+%0A
   
-%7D%0A%0A  @Override%0A  @Nonnull
+  if (function == null) %7B%0A      function = it -%3E PsiUtilCore.NULL_PSI_ELEMENT;%0A    %7D%0A%0A    myFactory = function;%0A  %7D%0A
 %0A  p
@@ -2493,203 +2493,549 @@
 lic 
-Psi
 Element
- createElement(@Nonnull ASTNode astNode) %7B%0A    if (myConstructor == null) %7B%0A      return PsiUtilCore.NULL_PSI_ELEMENT;%0A    %7D%0A    return ReflectionUtil.createInstance(myConstructor, astN
+TypeAsPsiFactory(@Nonnull String debugName, @Nullable Language language, @Nonnull Function%3CASTNode, ? extends PsiElement%3E factory) %7B%0A    this(debugName, language, true, factory);%0A  %7D%0A%0A  public ElementTypeAsPsiFactory(@Nonnull String debugName, @Nullable Language language, boolean register, @Nonnull Function%3CASTNode, ? extends PsiElement%3E factory) %7B%0A    super(debugName, language, register);%0A%0A    myFactory = factory;%0A  %7D%0A%0A  @Override%0A  @Nonnull%0A  public PsiElement createElement(@Nonnull ASTNode node) %7B%0A    return myFactory.apply(n
 ode)

introduce factory constructors without reflection