// Copyright 2000-2019 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.ui;

import com.intellij.util.ArrayUtil;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.NotNull;

import java.awt.*;
import java.util.List;

/**
 * Policy which defines explicit focus component cycle.
 */
public class ListFocusTraversalPolicy extends ContainerOrderFocusTraversalPolicy {

  private final Component[] myComponents;
  private final TObjectIntHashMap<Component> myComponentToIndex;

  public ListFocusTraversalPolicy(@NotNull List<? extends Component> components) {
    myComponents = components.toArray(new Component[0]);
    myComponentToIndex = indexMap(myComponents);
  }

  @Override
  public Component getFirstComponent(Container aContainer) {
    return ArrayUtil.getFirstElement(myComponents);
  }

  @Override
  public Component getLastComponent(Container aContainer) {
    return ArrayUtil.getLastElement(myComponents);
  }

  @Override
  protected boolean accept(Component aComponent) {
    return super.accept(aComponent) && aComponent.isShowing();
  }

  @Override
  public Component getComponentAfter(Container aContainer, Component aComponent) {
    if (!myComponentToIndex.containsKey(aComponent)) {
      return null;
    }
    for (int index = myComponentToIndex.get(aComponent) + 1; index < myComponents.length; index++) {
      Component result = myComponents[index];
      if (accept(result)) {
        return result;
      }
    }
    return null;
  }

  @Override
  public Component getComponentBefore(Container aContainer, Component aComponent) {
    if (!myComponentToIndex.containsKey(aComponent)) {
      return null;
    }
    for (int index = myComponentToIndex.get(aComponent) - 1; index >= 0; index--) {
      Component result = myComponents[index];
      if (accept(result)) {
        return result;
      }
    }
    return null;
  }

  @NotNull
  private static <X> TObjectIntHashMap<X> indexMap(@NotNull X[] array) {
    TObjectIntHashMap<X> map = new TObjectIntHashMap<>(array.length);
    for (X x : array) {
      if (!map.contains(x)) {
        map.put(x, map.size());
      }
    }
    map.compact();
    return map;
  }
}

@@ -164,44 +164,8 @@
 i;%0A%0A
-import com.intellij.util.ArrayUtil;%0A
 impo
@@ -238,16 +238,81 @@
 otNull;%0A
+import org.jetbrains.annotations.Nullable;%0A%0Aimport javax.swing.*;
 %0Aimport 
@@ -461,22 +461,14 @@
 nds 
-ContainerOrder
+Layout
 Focu
@@ -781,32 +781,163 @@
 mponents);%0A  %7D%0A%0A
+  @Override%0A  protected boolean accept(Component aComponent) %7B%0A    return super.accept(aComponent) && aComponent.isShowing();%0A  %7D%0A%0A
   @Override%0A  pu
@@ -1008,36 +1008,15 @@
 urn 
-ArrayUtil.getFirstElement(my
+getNext
 Comp
@@ -1012,33 +1012,34 @@
 getNextComponent
-s
+(0
 );%0A  %7D%0A%0A  @Overr
@@ -1117,29 +1117,25 @@
 urn 
-ArrayUtil.getLastElem
+getPreviousCompon
 ent(
@@ -1138,32 +1138,43 @@
 ent(myComponents
+.length - 1
 );%0A  %7D%0A%0A  @Overr
@@ -1184,42 +1184,128 @@
 %0A  p
-rotected boolean accept(Component 
+ublic Component getComponentAfter(Container aContainer, Component aComponent) %7B%0A    if (!myComponentToIndex.containsKey(
 aCom
@@ -1315,36 +1315,55 @@
 ent)
+)
  %7B%0A    
+  
 return 
-super.accept(a
+null;%0A    %7D%0A    return getNext
 Comp
@@ -1359,38 +1359,35 @@
 getNextComponent
-) && a
+(my
 Component.isShow
@@ -1375,35 +1375,51 @@
 (myComponent
-.isShowing(
+ToIndex.get(aComponent) + 1
 );%0A  %7D%0A%0A  @O
@@ -1449,37 +1449,38 @@
 ent getComponent
-After
+Before
 (Container aCont
@@ -1594,33 +1594,44 @@
   %7D%0A    
-for (int index = 
+return getPreviousComponent(
 myCompon
@@ -1657,19 +1657,125 @@
 ponent) 
-+
+-
  1
+);%0A  %7D%0A%0A  @Nullable%0A  private Component getNextComponent(int startIndex) %7B%0A    for (int index = startIndex
 ; index 
@@ -1927,46 +1927,213 @@
     
-return null;%0A  %7D%0A%0A  @Override%0A  public
+for (int index = 0; index %3C startIndex; index++) %7B%0A      Component result = myComponents%5Bindex%5D;%0A      if (accept(result)) %7B%0A        return result;%0A      %7D%0A    %7D%0A    return null;%0A  %7D%0A%0A  @Nullable%0A  private
  Com
@@ -2134,32 +2134,40 @@
 te Component get
+Previous
 ComponentBefore(
@@ -2163,70 +2163,108 @@
 nent
-Before(Container aContainer, Component aComponent) %7B%0A    if (!
+(int startIndex) %7B%0A    for (int index = startIndex; index %3E= 0; index--) %7B%0A      Component result = 
 myCo
@@ -2274,43 +2274,48 @@
 nent
-ToI
+s%5Bi
 ndex
-.containsKey(aComponen
+%5D;%0A      if (accept(resul
 t)) %7B%0A
+  
     
@@ -2315,37 +2315,47 @@
 %0A        return 
-null;
+result;%0A      %7D
 %0A    %7D%0A    for (
@@ -2377,39 +2377,24 @@
 omponent
-ToIndex.get(aComponent)
+s.length
  - 1; in
@@ -2390,35 +2390,43 @@
 gth - 1; index %3E
-= 0
+ startIndex
 ; index--) %7B%0A   

fix ListFocusTraversalPolicy (IDEA-119140)