content: /*
   * Copyright 2018 Aurélien Gâteau <mail@agateau.com>
   *
   * This file is part of Pixel Wheels.
   *
   * Pixel Wheels 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 com.agateau.pixelwheels.screens.config;
  
  import static com.agateau.translations.Translator.tr;
  
  import com.agateau.pixelwheels.GameConfig;
  import com.agateau.pixelwheels.PwGame;
  import com.agateau.pixelwheels.PwRefreshHelper;
  import com.agateau.pixelwheels.gameinput.GamepadInputHandler;
  import com.agateau.pixelwheels.screens.PwStageScreen;
  import com.agateau.ui.GamepadInputMapper;
  import com.agateau.ui.VirtualKey;
  import com.agateau.ui.anchor.AnchorGroup;
  import com.agateau.ui.menu.ButtonMenuItem;
  import com.agateau.ui.menu.Menu;
  import com.agateau.ui.menu.MenuItem;
  import com.agateau.ui.menu.MenuItemListener;
  import com.agateau.ui.uibuilder.UiBuilder;
  import com.agateau.utils.FileUtils;
  import com.badlogic.gdx.scenes.scene2d.InputEvent;
  import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
  import com.badlogic.gdx.utils.Array;
  import java.util.Locale;
  
  /** Configure an input device */
  public class GamepadConfigScreen extends PwStageScreen {
      private final PwGame mGame;
      private final int mPlayerIdx;
      private final GamepadInputMapper mInputMapper;
      private final Array<GamepadButtonItemController> mButtonControllers = new Array<>();
  
      private GamepadButtonItemController mEditingController;
  
      private class GamepadButtonItemController implements GamepadInputMapper.Listener {
          private final ButtonMenuItem mMenuItem;
          private final VirtualKey mVirtualKey;
          private boolean mEditing = false;
  
          GamepadButtonItemController(ButtonMenuItem menuItem, VirtualKey virtualKey) {
              mMenuItem = menuItem;
              mVirtualKey = virtualKey;
              mMenuItem.addListener(
                      new MenuItemListener() {
                          @Override
                          public void triggered() {
                              startEditing(GamepadButtonItemController.this);
                          }
                      });
              updateText();
          }
  
          void setEditing(boolean editing) {
              mEditing = editing;
              updateText();
          }
  
          private void updateText() {
              String text;
              if (mEditing) {
                  text = "...";
              } else {
                  text =
                          String.format(
                                  Locale.US,
                                  "%d",
                                  mInputMapper.getButtonCodeForVirtualKey(mVirtualKey));
              }
              mMenuItem.setText(text);
          }
  
          @Override
          public boolean onButtonPressed(int buttonCode, boolean pressed) {
              mInputMapper.setButtonCodeForVirtualKey(mVirtualKey, buttonCode);
              stopEditing();
              return true;
          }
      }
  
      GamepadConfigScreen(PwGame game, int playerIdx) {
          super(game.getAssets().ui);
          mGame = game;
          mPlayerIdx = playerIdx;
          GamepadInputHandler handler =
                  (GamepadInputHandler) mGame.getConfig().getPlayerInputHandler(mPlayerIdx);
          mInputMapper = (GamepadInputMapper) handler.getInputMapper();
          new PwRefreshHelper(mGame, getStage()) {
              @Override
              protected void refresh() {
                  mGame.replaceScreen(new GamepadConfigScreen(mGame, mPlayerIdx));
              }
          };
          setupUi();
      }
  
      private void setupUi() {
          UiBuilder builder = new UiBuilder(mGame.getAssets().atlas, mGame.getAssets().ui.skin);
          builder.registerMenuItemFactory(
                  "KeyMenuItem",
                  (menu, element) -> {
                      String label1 = tr(element.getAttribute("label1", ""));
                      String label2 = tr(element.getAttribute("label2", ""));
                      String keyStr = element.getAttribute("key", "");
                      if (keyStr.equals("")) {
                          return ConfigUiUtils.createTwoColumnTitle(menu, label1, label2);
                      }
                      VirtualKey key = VirtualKey.valueOf(keyStr);
                      return createButton(menu, label1, label2, key);
                  });
  
          AnchorGroup root =
                  (AnchorGroup) builder.build(FileUtils.assets("screens/gamepadconfig.gdxui"));
          root.setFillParent(true);
          getStage().addActor(root);
  
          Menu menu = builder.getActor("menu");
          menu.addBackButton()
                  .addListener(
                          new ClickListener() {
                              @Override
                              public void clicked(InputEvent event, float x, float y) {
                                  onBackPressed();
                              }
                          });
      }
  
      private MenuItem createButton(Menu menu, String text1, String text2, VirtualKey virtualKey) {
          ButtonMenuItem buttonItem = new ButtonMenuItem(menu, "");
          ConfigUiUtils.createTwoColumnRow(menu, text1, text2, buttonItem);
  
          GamepadButtonItemController controller =
                  new GamepadButtonItemController(buttonItem, virtualKey);
          mButtonControllers.add(controller);
  
          return buttonItem;
      }
  
      private void startEditing(GamepadButtonItemController controller) {
          stopEditing();
          mEditingController = controller;
          mEditingController.setEditing(true);
          mInputMapper.setListener(mEditingController);
      }
  
      private void stopEditing() {
          if (mEditingController != null) {
              mEditingController.setEditing(false);
              mInputMapper.setListener(null);
          }
      }
  
      @Override
      public void onBackPressed() {
          stopEditing();
          saveConfig();
          mGame.popScreen();
      }
  
      private void saveConfig() {
          GameConfig config = mGame.getConfig();
          config.savePlayerInputHandlerConfig(mPlayerIdx);
      }
  }
  