<commit_before>package de.naoth.rc.dialogsFx.parameters;

import de.naoth.rc.RobotControl;
import de.naoth.rc.componentsFx.AlertDialog;
import de.naoth.rc.core.server.Command;
import de.naoth.rc.core.server.ResponseListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javafx.animation.FadeTransition;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.util.Duration;

/**
 * @author <NAME> <<EMAIL>>
 */
public class ParametersController
{
    /** The controlling instance representing the connection to the robot. */
    private RobotControl control;
    
    @FXML private TreeView<String> params;
    @FXML private TextArea values;
    @FXML private Label scheme;
    @FXML private Label notice;
    
    /** Some key shortcut definitions */
    private final KeyCombination shortcutUpdate = new KeyCodeCombination(KeyCode.F5);
    private final KeyCombination shortcutExport = new KeyCodeCombination(KeyCode.E, KeyCombination.CONTROL_DOWN);
    private final KeyCombination shortcutSaveValueEnter = new KeyCodeCombination(KeyCode.ENTER);
    private final KeyCombination shortcutSaveValuesCtrlS = new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN);
    
    private final Command cmdScheme = new Command("Cognition:representation:print").addArg("PlayerInfo");
    private final Command cmdCognitionParams = new Command("Cognition:ParameterList:list");
    private final Command cmdMotionParams = new Command("Motion:ParameterList:list");
    
    private static final Pattern KEY_VALUE_PATTERN = Pattern.compile("^(?<key>.+)=(?<value>.*)$", Pattern.MULTILINE);
    private final ParameterResponseHandler responseHandler = new ParameterResponseHandler();
    
    private final FadeTransition fadeOut = new FadeTransition(Duration.millis(2000));
    
    final private String parameterSavePathKey = "parameter_save_path";
    final private String defaultConfigPath = "../NaoTHSoccer/Config/scheme";
    
    /**
     * Default constructor for the FXML loader.
     */
    public ParametersController() {}
    
    /**
     * Constructor for custom initialization.
     */
    public ParametersController(RobotControl control) {
        setRobotControl(control);
    }
    
    /**
     * Gets called, after the FXML file was loaded.
     */
    @FXML
    private void initialize() 
    {
        params.setRoot(new TreeItem<>());
        params.getRoot().setExpanded(true);
        params.getSelectionModel().selectedItemProperty().addListener((o) -> { retrieveValues(); });
        // set the options for the fade-out animation
        fadeOut.setNode(notice);
        fadeOut.setFromValue(1.0);
        fadeOut.setToValue(0.0);
        fadeOut.setCycleCount(1);
        fadeOut.setAutoReverse(false);
    }
    
    /**
     * Sets the controlling instance of the robot.
     * @param control 
     */
    public void setRobotControl(RobotControl control) {
        this.control = control;
    }
    
    /**
     * Is called, when the update button is clicked.
     */
    @FXML
    private void fxUpdateParams() {
        if (control != null && control.checkConnected()) {
            control.getMessageServer().executeCommand(responseHandler, cmdScheme);
            control.getMessageServer().executeCommand(responseHandler, cmdCognitionParams);
            control.getMessageServer().executeCommand(responseHandler, cmdMotionParams);
        }
    }
    
    /**
     * Is called, when key event is triggered on the values textarea.
     * 
     * @param k the triggered key event
     */
    @FXML
    private void fxValuesShortcuts(KeyEvent k) {
        if (shortcutSaveValueEnter.match(k) || shortcutSaveValuesCtrlS.match(k)) {
            TreeItem<String> selected = params.getSelectionModel().getSelectedItem();
            if (selected != null && control != null && control.checkConnected()) {
                // prepare the command
                Command cmd = new Command(selected.getParent().getValue() + ":ParameterList:set").addArg("<name>", selected.getValue());
                parseText().forEach((o, v) -> { cmd.addArg(o, v); });
                // ... and send
                control.getMessageServer().executeCommand(responseHandler, cmd);
                // disable until we get response
                values.setEditable(false);
                // make sure we're in sync with the robot
                retrieveValues();
            }
        } else if (shortcutUpdate.match(k)) {
            // F5 is consumed by the textarea and does not bubble to the parent node,
            // so we must handle it here
            fxUpdateParams();
        }
    }
    
    /**
     * Is called, when key event is triggered.
     * The parameter update and the export is handled.
     * 
     * @param k the triggered key event
     */
    @FXML
    private void fxDialogShortcuts(KeyEvent k) {
        if (shortcutUpdate.match(k)) {
            fxUpdateParams();
        } else if (shortcutExport.match(k)) {
            fxExport();
        }
    }
    
    /**
     * Is called, when the export button is pressed.
     */
    @FXML
    private void fxExport() {
        TreeItem<String> selected = params.getSelectionModel().getSelectedItem();
        // check if we got a valid selection; ignore Cognition/Motion entries, which doesn't have a "valid" parent
        if (selected == null || selected.getParent().getValue() == null) {
            AlertDialog.showError("Error", "You have to choose a parameter configuration!");
        } else {
            String parameterPath = control.getConfig().getProperty(parameterSavePathKey, defaultConfigPath);
            // configure the filechooser ...
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("Save configuration ("+selected.getValue()+")");
            fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("Config files (*.cfg)", "*.cfg"));
            fileChooser.setInitialDirectory(new File(parameterPath));
            fileChooser.setInitialFileName(selected.getValue() + ".cfg");
            
            File selectedFile = fileChooser.showSaveDialog(params.getScene().getWindow());
            if(selectedFile != null) {
                // if selected file has a file extension - use this, otherwise append ".cfg" to the filename
                File f = (selectedFile.getName().lastIndexOf(".") == -1) ? new File(selectedFile+".cfg") : selectedFile;

                try {
                    new FileWriter(f).close(); // trigger exception (if couldn't write)

                    // create file and write parameter configuration to this file
                    writeParameterConfig(selected.getValue(), f);
                } catch (IOException ex) {
                    Logger.getLogger(ParametersController.class.getName()).log(Level.SEVERE, null, ex);
                    AlertDialog.showError("Not writeable", "Selected file is not writeable!");
                }
                
                // save the path for later
                control.getConfig().setProperty(parameterSavePathKey, selectedFile.getParent());
            }
        }
    }
    
    /**
     * Is called, when the export all menu item is pressed.
     */
    @FXML
    private void fxExportAll() {
        // make sure, we're connected!
        if (control != null && control.checkConnected()) {
            // update ui after connecting ...
            fxUpdateParams();
            // configure filechooser ...
            DirectoryChooser directoryChooser = new DirectoryChooser();
            directoryChooser.setTitle("Save configuration (All)");
            // show save dialog
            File directory = directoryChooser.showDialog(params.getScene().getWindow());<commit_msg>small rename<commit_after>package de.naoth.rc.dialogsFx.parameters;

import de.naoth.rc.RobotControl;
import de.naoth.rc.componentsFx.AlertDialog;
import de.naoth.rc.core.server.Command;
import de.naoth.rc.core.server.ResponseListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javafx.animation.FadeTransition;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.util.Duration;

/**
 * @author <NAME> <<EMAIL>>
 */
public class ParametersController
{
    /** The controlling instance representing the connection to the robot. */
    private RobotControl control;
    
    @FXML private TreeView<String> params;
    @FXML private TextArea values;
    @FXML private Label scheme;
    @FXML private Label notice;
    
    /** Some key shortcut definitions */
    private final KeyCombination shortcutUpdate = new KeyCodeCombination(KeyCode.F5);
    private final KeyCombination shortcutExport = new KeyCodeCombination(KeyCode.E, KeyCombination.CONTROL_DOWN);
    private final KeyCombination shortcutSaveValueEnter = new KeyCodeCombination(KeyCode.ENTER);
    private final KeyCombination shortcutSaveValuesCtrlS = new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN);
    
    private final Command cmdScheme = new Command("Cognition:representation:print").addArg("PlayerInfo");
    private final Command cmdCognitionParams = new Command("Cognition:ParameterList:list");
    private final Command cmdMotionParams = new Command("Motion:ParameterList:list");
    
    private static final Pattern KEY_VALUE_PATTERN = Pattern.compile("^(?<key>.+)=(?<value>.*)$", Pattern.MULTILINE);
    private final ParameterResponseHandler responseHandler = new ParameterResponseHandler();
    
    /** The animation for the save notice */
    private final FadeTransition fadeOut = new FadeTransition(Duration.millis(2000));
    
    static final private String CONFIG_PATH_PARAMS = "parameter_save_path";
    static final private String CONFIG_PATH_DEFAULT = "../NaoTHSoccer/Config/scheme";
    
    /**
     * Default constructor for the FXML loader.
     */
    public ParametersController() {}
    
    /**
     * Constructor for custom initialization.
     */
    public ParametersController(RobotControl control) {
        setRobotControl(control);
    }
    
    /**
     * Gets called, after the FXML file was loaded.
     */
    @FXML
    private void initialize() 
    {
        params.setRoot(new TreeItem<>());
        params.getRoot().setExpanded(true);
        params.getSelectionModel().selectedItemProperty().addListener((o) -> { retrieveValues(); });
        // set the options for the fade-out animation
        fadeOut.setNode(notice);
        fadeOut.setFromValue(1.0);
        fadeOut.setToValue(0.0);
        fadeOut.setCycleCount(1);
        fadeOut.setAutoReverse(false);
    }
    
    /**
     * Sets the controlling instance of the robot.
     * @param control 
     */
    public void setRobotControl(RobotControl control) {
        this.control = control;
    }
    
    /**
     * Is called, when the update button is clicked.
     */
    @FXML
    private void fxUpdateParams() {
        if (control != null && control.checkConnected()) {
            control.getMessageServer().executeCommand(responseHandler, cmdScheme);
            control.getMessageServer().executeCommand(responseHandler, cmdCognitionParams);
            control.getMessageServer().executeCommand(responseHandler, cmdMotionParams);
        }
    }
    
    /**
     * Is called, when key event is triggered on the values textarea.
     * 
     * @param k the triggered key event
     */
    @FXML
    private void fxValuesShortcuts(KeyEvent k) {
        if (shortcutSaveValueEnter.match(k) || shortcutSaveValuesCtrlS.match(k)) {
            TreeItem<String> selected = params.getSelectionModel().getSelectedItem();
            if (selected != null && control != null && control.checkConnected()) {
                // prepare the command
                Command cmd = new Command(selected.getParent().getValue() + ":ParameterList:set").addArg("<name>", selected.getValue());
                parseText().forEach((o, v) -> { cmd.addArg(o, v); });
                // ... and send
                control.getMessageServer().executeCommand(responseHandler, cmd);
                // disable until we get response
                values.setEditable(false);
                // make sure we're in sync with the robot
                retrieveValues();
            }
        } else if (shortcutUpdate.match(k)) {
            // F5 is consumed by the textarea and does not bubble to the parent node,
            // so we must handle it here
            fxUpdateParams();
        }
    }
    
    /**
     * Is called, when key event is triggered.
     * The parameter update and the export is handled.
     * 
     * @param k the triggered key event
     */
    @FXML
    private void fxDialogShortcuts(KeyEvent k) {
        if (shortcutUpdate.match(k)) {
            fxUpdateParams();
        } else if (shortcutExport.match(k)) {
            fxExport();
        }
    }
    
    /**
     * Is called, when the export button is pressed.
     */
    @FXML
    private void fxExport() {
        TreeItem<String> selected = params.getSelectionModel().getSelectedItem();
        // check if we got a valid selection; ignore Cognition/Motion entries, which doesn't have a "valid" parent
        if (selected == null || selected.getParent().getValue() == null) {
            AlertDialog.showError("Error", "You have to choose a parameter configuration!");
        } else {
            String parameterPath = control.getConfig().getProperty(CONFIG_PATH_PARAMS, CONFIG_PATH_DEFAULT);
            // configure the filechooser ...
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("Save configuration ("+selected.getValue()+")");
            fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("Config files (*.cfg)", "*.cfg"));
            fileChooser.setInitialDirectory(new File(parameterPath));
            fileChooser.setInitialFileName(selected.getValue() + ".cfg");
            
            File selectedFile = fileChooser.showSaveDialog(params.getScene().getWindow());
            if(selectedFile != null) {
                // if selected file has a file extension - use this, otherwise append ".cfg" to the filename
                File f = (selectedFile.getName().lastIndexOf(".") == -1) ? new File(selectedFile+".cfg") : selectedFile;

                try {
                    new FileWriter(f).close(); // trigger exception (if couldn't write)

                    // create file and write parameter configuration to this file
                    writeParameterConfig(selected.getValue(), f);
                } catch (IOException ex) {
                    Logger.getLogger(ParametersController.class.getName()).log(Level.SEVERE, null, ex);
                    AlertDialog.showError("Not writeable", "Selected file is not writeable!");
                }
                
                // save the path for later
                control.getConfig().setProperty(CONFIG_PATH_PARAMS, selectedFile.getParent());
            }
        }
    }
    
    /**
     * Is called, when the export all menu item is pressed.
     */
    @FXML
    private void fxExportAll() {
        // make sure, we're connected!
        if (control != null && control.checkConnected()) {
            // update ui after connecting ...
            fxUpdateParams();
            // configure filechooser ...
            DirectoryChooser directoryChooser = new DirectoryChooser();
            directoryChooser.setTitle("Save configuration (All)");
            // show save dialog
            File directory = directoryChooser.showDialog(params.getScene().getWindow());
{'fraction_non_alphanumeric': 0.1069759289553634, 'fraction_numerical': 0.0014021967749474175, 'mean_word_length': 2.6512372013651877, 'pattern_counts': {'":': 2, '<': 23, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7252063', 'n_tokens_mistral': 4571, 'n_tokens_neox': 4425, 'n_words': 1128}