content: /**
   * erlyberly, erlang trace debugger
   * Copyright (C) 2016 Andy Till
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program. If not, see <http://www.gnu.org/licenses/>.
   */
  package erlyberly;
  
  import java.util.ArrayList;
  
  import javafx.application.Platform;
  import javafx.scene.Scene;
  import javafx.scene.control.Control;
  import javafx.scene.input.KeyCode;
  import javafx.scene.input.KeyCodeCombination;
  import javafx.scene.input.KeyCombination;
  
  public class FilterFocusManager {
  
      private static final KeyCodeCombination REFRESH_MODULES_SHORTCUT = new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN);
  
      private static final ArrayList<Control> FILTERS = new ArrayList<>();
  
      private static int lastFocusedIndex = -1;
  
      private FilterFocusManager() {}
  
      public static void init(Scene scene) {
          FILTERS.add(null);
          FILTERS.add(null);
          FILTERS.add(null);
  
          Platform.runLater(() -> {
              scene.getAccelerators().put(REFRESH_MODULES_SHORTCUT, () -> { nextFilter(); });
          });
      }
  
      private static void nextFilter() {
          if(FILTERS.isEmpty())
              return;
  
          Control control = findNextFilter();
  
          requestFocus(control);
      }
  
      private static Control findNextFilter() {
          // if we know about a filter control that was focused last but does not currently
          // have focus then return to it. The filter must be visible and attached to the scene.
          if(lastFocusedIndex != -1) {
              Control lastFocused = FILTERS.get(lastFocusedIndex);
              if(!lastFocused.isFocused() && lastFocused.isVisible() && lastFocused.getScene() != null) {
                  return lastFocused;
              }
          }
  
          int focused = findCurrentFilter();
  
          if(focused == -1) {
              focused = 0;
          }
          // iterate the filters until we find one that is part of the scene or we run out of filters
          int iterations = 0;
          while(iterations < FILTERS.size()) {
              iterations++;
              focused++;
              if(focused >= FILTERS.size()) {
                  focused = 0;
              }
              boolean isFocusable = FILTERS.get(focused).getScene() != null;
              if(isFocusable)
                  break;
          }
          return FILTERS.get(focused);
      }
  
      private static int findCurrentFilter() {
          int focused = -1;
          for (int i = 0; i < FILTERS.size(); i++) {
              Control control = FILTERS.get(i);
              if(control != null && control.isFocused()) {
                  focused = i;
                  break;
              }
          }
          return focused;
      }
  
     private static void requestFocus(Control control) {
         if(control != null)
             Platform.runLater(() -> { control.requestFocus(); });
      }
  
     public static void addFilter(Control control, int order) {
          assert control != null;
          assert order >= 0;
          assert Platform.isFxApplicationThread();
  
          FILTERS.set(order, control);
  
          control.focusedProperty().addListener((o, oldFocus, newFocus) -> {
              lastFocusedIndex = order;
          });
      }
  }
  