/*
 * Copyright 2000-2013 JetBrains s.r.o.
 * Copyright 2014-2014 AS3Boyan
 * Copyright 2014-2014 Elias Ku
 * Copyright 2020 Eric Bishton
 *
 * 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 com.intellij.plugins.haxe.ide.generation;

import com.intellij.plugins.haxe.HaxeBundle;
import com.intellij.plugins.haxe.HaxeComponentType;
import com.intellij.plugins.haxe.lang.psi.HaxeClass;
import com.intellij.plugins.haxe.lang.psi.HaxeMethod;
import com.intellij.plugins.haxe.lang.psi.HaxeNamedComponent;
import com.intellij.plugins.haxe.util.HaxeResolveUtil;
import com.intellij.psi.util.PsiTreeUtil;

import java.util.List;

/**
 * @author: Fedor.Korotkov
 */
public class HaxeImplementMethodHandler extends BaseHaxeGenerateHandler {
  @Override
  protected String getTitle() {
    return HaxeBundle.message("haxe.implement.method");
  }

  @Override
  void collectCandidates(HaxeClass haxeClass, List<HaxeNamedComponent> candidates) {
    for (HaxeNamedComponent haxeNamedComponent : HaxeResolveUtil.findNamedSubComponents(null, haxeClass)) {
      final boolean prototype = haxeNamedComponent instanceof HaxeMethod;
      final HaxeClass parentClass = PsiTreeUtil.getParentOfType(haxeNamedComponent, HaxeClass.class, true);
      final boolean interfaceField = HaxeComponentType.typeOf(haxeNamedComponent) == HaxeComponentType.FIELD &&
                                     HaxeComponentType.typeOf(parentClass) == HaxeComponentType.INTERFACE;
      if (!prototype && !interfaceField) continue;

      candidates.add(haxeNamedComponent);
    }
  }

  @Override
  protected BaseCreateMethodsFix createFix(HaxeClass haxeClass) {
    return new OverrideImplementMethodFix(haxeClass, false);
  }
}

@@ -1104,16 +1104,72 @@
 eUtil;%0A%0A
+import java.util.ArrayList;%0Aimport java.util.Hashtable;%0A
 import j
@@ -1503,13 +1503,258 @@
     
-for (
+// Properties and variables are also part of interface declarations that must be implemented,%0A    // so they can/should show up in this list.%0A%0A    // Get all of the names and sort them into lists of class methods and interface declarations.%0A    List%3C
 Haxe
@@ -1767,22 +1767,19 @@
 omponent
- haxeN
+%3E n
 amedComp
@@ -1787,10 +1787,11 @@
 nent
- :
+s =
  Hax
@@ -1826,16 +1826,23 @@
 ponents(
+false, 
 null, ha
@@ -1853,85 +1853,211 @@
 ass)
-) %7B
+;
 %0A    
-  final boolean prototype = haxeNamedComponent instanceof HaxeMethod;
+List%3CHaxeNamedComponent%3E interfaceMethods = new ArrayList%3C%3E();%0A    Hashtable%3CString, HaxeNamedComponent%3E classMethods = new Hashtable%3C%3E();%0A    for (HaxeNamedComponent component : namedComponents) %7B
 %0A   
@@ -2117,26 +2117,17 @@
 tOfType(
-haxeNamedC
+c
 omponent
@@ -2162,39 +2162,12 @@
     
-final boolean interfaceField = 
+if (
 Haxe
@@ -2187,34 +2187,27 @@
 .typeOf(
-haxeNamedComponent
+parentClass
 ) == Hax
@@ -2225,54 +2225,92 @@
 ype.
-FIELD &&%0A                                     
+CLASS) %7B%0A        classMethods.put(component.getName(), component);%0A      %7D else if (
 Haxe
@@ -2377,68 +2377,279 @@
 FACE
-;%0A
+) %7B%0A  
       i
-f (!prototype && !interfaceField) 
+nterfaceMethods.add(component);%0A      %7D%0A    %7D%0A%0A    // Walk the interface names and make sure that a method implementation exists.%0A    for (HaxeNamedComponent component : interfaceMethods) %7B%0A      if (!classMethods.
 cont
+a
 in
-ue;%0A%0A
+sKey(component.getName())) %7B%0A 
       
+ 
 cand
@@ -2663,18 +2663,9 @@
 add(
-haxeNamedC
+c
 ompo
@@ -2667,24 +2667,32 @@
 component);%0A
+      %7D%0A
     %7D%0A  %7D%0A%0A 
@@ -2734,16 +2734,36 @@
 thodsFix
+%3CHaxeNamedComponent%3E
  createF

Rewrite the algorithm used to find unimplemented interface methods when using "implement missing methods" feature (as opposed to a fixer created by the semantic annotator).