//! ## FileTransferActivity
//!
//! `filetransfer_activiy` is the module which implements the Filetransfer activity, which is the main activity afterall

/**
 * MIT License
 *
 * termscp - Copyright (c) 2021 Christian Visintin
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
// locals
use super::{
    actions::SelectedEntry, browser::FileExplorerTab, FileTransferActivity, LogLevel, TransferOpts,
    COMPONENT_EXPLORER_FIND, COMPONENT_EXPLORER_LOCAL, COMPONENT_EXPLORER_REMOTE,
    COMPONENT_INPUT_COPY, COMPONENT_INPUT_EXEC, COMPONENT_INPUT_FIND, COMPONENT_INPUT_GOTO,
    COMPONENT_INPUT_MKDIR, COMPONENT_INPUT_NEWFILE, COMPONENT_INPUT_OPEN_WITH,
    COMPONENT_INPUT_RENAME, COMPONENT_INPUT_SAVEAS, COMPONENT_LIST_FILEINFO,
    COMPONENT_LIST_REPLACING_FILES, COMPONENT_LOG_BOX, COMPONENT_PROGRESS_BAR_FULL,
    COMPONENT_PROGRESS_BAR_PARTIAL, COMPONENT_RADIO_DELETE, COMPONENT_RADIO_DISCONNECT,
    COMPONENT_RADIO_QUIT, COMPONENT_RADIO_REPLACE, COMPONENT_RADIO_SORTING, COMPONENT_TEXT_ERROR,
    COMPONENT_TEXT_FATAL, COMPONENT_TEXT_HELP,
};
use crate::fs::explorer::FileSorting;
use crate::fs::FsEntry;
use crate::ui::components::{file_list::FileListPropsBuilder, logbox::LogboxPropsBuilder};
use crate::ui::keymap::*;
use crate::utils::fmt::fmt_path_elide_ex;
// externals
use tui_realm_stdlib::ProgressBarPropsBuilder;
use tuirealm::{
    props::{Alignment, PropsBuilder, TableBuilder, TextSpan},
    tui::style::Color,
    Msg, Payload, Update, Value,
};

impl Update for FileTransferActivity {
    // -- update

    /// ### update
    ///
    /// Update auth activity model based on msg
    /// The function exits when returns None
    fn update(&mut self, msg: Option<(String, Msg)>) -> Option<(String, Msg)> {
        let ref_msg: Option<(&str, &Msg)> = msg.as_ref().map(|(s, msg)| (s.as_str(), msg));
        // Match msg
        match ref_msg {
            None => None, // Exit after None
            Some(msg) => match msg {
                // -- local tab
                (COMPONENT_EXPLORER_LOCAL, key) if key == &MSG_KEY_RIGHT => {
                    // Change tab
                    self.view.active(COMPONENT_EXPLORER_REMOTE);
                    self.browser.change_tab(FileExplorerTab::Remote);
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key) if key == &MSG_KEY_BACKSPACE => {
                    // Go to previous directory
                    self.action_go_to_previous_local_dir(false);
                    if self.browser.sync_browsing {
                        let _ = self.update_remote_filelist();
                    }
                    // Reload file list component
                    self.update_local_filelist()
                }
                (COMPONENT_EXPLORER_LOCAL, Msg::OnSubmit(Payload::One(Value::Usize(idx)))) => {
                    // Match selected file
                    let mut entry: Option<FsEntry> = None;
                    if let Some(e) = self.local().get(*idx) {
                        entry = Some(e.clone());
                    }
                    if let Some(entry) = entry {
                        if self.action_submit_local(entry) {
                            // Update file list if sync
                            if self.browser.sync_browsing {
                                let _ = self.update_remote_filelist();
                            }
                            self.update_local_filelist()
                        } else {
                            None
                        }
                    } else {
                        None
                    }
                }
                (COMPONENT_EXPLORER_LOCAL, key) if key == &MSG_KEY_SPACE => {
                    self.action_local_send();
                    self.update_remote_filelist()
                }
                (COMPONENT_EXPLORER_LOCAL, key) if key == &MSG_KEY_CHAR_A => {
                    // Toggle hidden files
                    self.local_mut().toggle_hidden_files();
                    // Update status bar
                    self.refresh_local_status_bar();
                    // Reload file list component
                    self.update_local_filelist()
                }
                (COMPONENT_EXPLORER_LOCAL, key) if key == &MSG_KEY_CHAR_I => {
                    if let SelectedEntry::One(file) = self.get_local_selected_entries() {
                        self.mount_file_info(&file);
                    }
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key) if key == &MSG_KEY_CHAR_L => {
                    // Reload directory
                    self.reload_local_dir();
                    // Reload file list component
                    self.update_local_filelist()
                }
                (COMPONENT_EXPLORER_LOCAL, key) if key == &MSG_KEY_CHAR_O => {
                    self.action_edit_local_file();
                    // Reload file list component
                    self.update_local_filelist()
                }
                (COMPONENT_EXPLORER_LOCAL, key) if key == &MSG_KEY_CHAR_U => {
                    self.action_go_to_local_upper_dir(false);
                    if self.browser.sync_browsing {
                        let _ = self.update_remote_filelist();
                    }
                    // Reload file list component
                    self.update_local_filelist()
                }
                // -- remote tab
                (COMPONENT_EXPLORER_REMOTE, key) if key == &MSG_KEY_LEFT => {
                    // Change tab
                    self.view.active(COMPONENT_EXPLORER_LOCAL);
                    self.browser.change_tab(FileExplorerTab::Local);
                    None
                }
                (COMPONENT_EXPLORER_REMOTE, Msg::OnSubmit(Payload::One(Value::Usize(idx)))) => {
                    // Match selected file
                    let mut entry: Option<FsEntry> = None;
                    if let Some(e) = self.remote().get(*idx) {
                        entry = Some(e.clone());
                    }
                    if let Some(entry) = entry {
                        if self.action_submit_remote(entry) {
                            // Update file list if sync
                            if self.browser.sync_browsing {
                                let _ = self.update_local_filelist();
                            }
                            self.update_remote_filelist()
                        } else {
                            None
                        }
                    } else {
                        None
                    }
                }
                (COMPONENT_EXPLORER_REMOTE, key) if key == &MSG_KEY_SPACE => {
                    self.action_remote_recv();
                    self.update_local_filelist()
                }
                (COMPONENT_EXPLORER_REMOTE, key) if key == &MSG_KEY_BACKSPACE => {
                    // Go to previous directory
                    self.action_go_to_previous_remote_dir(false);
                    // If sync is enabled update local too
                    if self.browser.sync_browsing {
                        let _ = self.update_local_filelist();
                    }
                    // Reload file list component
                    self.update_remote_filelist()
                }
                (COMPONENT_EXPLORER_REMOTE, key) if key == &MSG_KEY_CHAR_A => {
                    // Toggle hidden files
                    self.remote_mut().toggle_hidden_files();
                    // Update status bar
                    self.refresh_remote_status_bar();
                    // Reload file list component
                    self.update_remote_filelist()
                }
                (COMPONENT_EXPLORER_REMOTE, key) if key == &MSG_KEY_CHAR_I => {
                    if let SelectedEntry::One(file) = self.get_remote_selected_entries() {
                        self.mount_file_info(&file);
                    }
                    None
                }
                (COMPONENT_EXPLORER_REMOTE, key) if key == &MSG_KEY_CHAR_L => {
                    // Reload directory
                    self.reload_remote_dir();
                    // Reload file list component
                    self.update_remote_filelist()
                }
                (COMPONENT_EXPLORER_REMOTE, key) if key == &MSG_KEY_CHAR_O => {
                    // Edit file
                    self.action_edit_remote_file();
                    // Reload file list component
                    self.update_remote_filelist()
                }
                (COMPONENT_EXPLORER_REMOTE, key) if key == &MSG_KEY_CHAR_U => {
                    self.action_go_to_remote_upper_dir(false);
                    if self.browser.sync_browsing {
                        let _ = self.update_local_filelist();
                    }
                    // Reload file list component
                    self.update_remote_filelist()
                }
                // -- common explorer keys
                (COMPONENT_EXPLORER_LOCAL, key) | (COMPONENT_EXPLORER_REMOTE, key)
                    if key == &MSG_KEY_CHAR_B =>
                {
                    // Show sorting file
                    self.mount_file_sorting();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key) | (COMPONENT_EXPLORER_REMOTE, key)
                    if key == &MSG_KEY_CHAR_C =>
                {
                    self.mount_copy();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key) | (COMPONENT_EXPLORER_REMOTE, key)
                    if key == &MSG_KEY_CHAR_D =>
                {
                    self.mount_mkdir();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key) | (COMPONENT_EXPLORER_REMOTE, key)
                    if key == &MSG_KEY_CHAR_F =>
                {
                    self.mount_find_input();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key) | (COMPONENT_EXPLORER_REMOTE, key)
                    if key == &MSG_KEY_CHAR_G =>
                {
                    self.mount_goto();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key) | (COMPONENT_EXPLORER_REMOTE, key)
                    if key == &MSG_KEY_CHAR_H =>
                {
                    self.mount_help();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key) | (COMPONENT_EXPLORER_REMOTE, key)
                    if key == &MSG_KEY_CHAR_N =>
                {
                    self.mount_newfile();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key)
                | (COMPONENT_EXPLORER_REMOTE, key)
                | (COMPONENT_LOG_BOX, key)
                    if key == &MSG_KEY_CHAR_Q =>
                {
                    self.mount_quit();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key) | (COMPONENT_EXPLORER_REMOTE, key)
                    if key == &MSG_KEY_CHAR_R =>
                {
                    // Mount rename
                    self.mount_rename();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key)
                | (COMPONENT_EXPLORER_REMOTE, key)
                | (COMPONENT_EXPLORER_FIND, key)
                    if key == &MSG_KEY_CHAR_S =>
                {
                    // Mount save as
                    self.mount_saveas();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key)
                | (COMPONENT_EXPLORER_REMOTE, key)
                | (COMPONENT_EXPLORER_FIND, key)
                    if key == &MSG_KEY_CHAR_V =>
                {
                    // View
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.action_open_local(),
                        FileExplorerTab::Remote => self.action_open_remote(),
                        FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => {
                            self.action_find_open()
                        }
                    }
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key)
                | (COMPONENT_EXPLORER_REMOTE, key)
                | (COMPONENT_EXPLORER_FIND, key)
                    if key == &MSG_KEY_CHAR_W =>
                {
                    // Open with
                    self.mount_openwith();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key) | (COMPONENT_EXPLORER_REMOTE, key)
                    if key == &MSG_KEY_CHAR_X =>
                {
                    // Mount exec
                    self.mount_exec();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key) | (COMPONENT_EXPLORER_REMOTE, key)
                    if key == &MSG_KEY_CHAR_Y =>
                {
                    // Toggle browser sync
                    self.browser.toggle_sync_browsing();
                    // Update status bar
                    self.refresh_remote_status_bar();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key)
                | (COMPONENT_EXPLORER_REMOTE, key)
                | (COMPONENT_LOG_BOX, key)
                    if key == &MSG_KEY_ESC =>
                {
                    self.mount_disconnect();
                    None
                }
                (COMPONENT_EXPLORER_LOCAL, key)
                | (COMPONENT_EXPLORER_REMOTE, key)
                | (COMPONENT_EXPLORER_FIND, key)
                    if key == &MSG_KEY_CHAR_E || key == &MSG_KEY_DEL =>
                {
                    self.mount_radio_delete();
                    None
                }
                // -- find result explorer
                (COMPONENT_EXPLORER_FIND, key) if key == &MSG_KEY_ESC => {
                    // Umount find
                    self.umount_find();
                    // Finalize find
                    self.finalize_find();
                    None
                }
                (COMPONENT_EXPLORER_FIND, Msg::OnSubmit(_)) => {
                    // Find changedir
                    self.action_find_changedir();
                    // Umount find
                    self.umount_find();
                    // Finalize find
                    self.finalize_find();
                    // Reload files
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.update_local_filelist(),
                        FileExplorerTab::Remote => self.update_remote_filelist(),
                        _ => None,
                    }
                }
                (COMPONENT_EXPLORER_FIND, key) if key == &MSG_KEY_SPACE => {
                    // Get entry
                    self.action_find_transfer(TransferOpts::default());
                    // Reload files
                    match self.browser.tab() {
                        // NOTE: swapped by purpose
                        FileExplorerTab::FindLocal => self.update_remote_filelist(),
                        FileExplorerTab::FindRemote => self.update_local_filelist(),
                        _ => None,
                    }
                }
                // -- switch to log
                (COMPONENT_EXPLORER_LOCAL, key) | (COMPONENT_EXPLORER_REMOTE, key)
                    if key == &MSG_KEY_TAB =>
                {
                    self.view.active(COMPONENT_LOG_BOX); // Active log box
                    None
                }
                // -- Log box
                (COMPONENT_LOG_BOX, key) if key == &MSG_KEY_TAB => {
                    self.view.blur(); // Blur log box
                    None
                }
                // -- copy popup
                (COMPONENT_INPUT_COPY, key) if key == &MSG_KEY_ESC => {
                    self.umount_copy();
                    None
                }
                (COMPONENT_INPUT_COPY, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
                    // Copy file
                    self.umount_copy();
                    self.mount_blocking_wait("Copying file(s)…");
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.action_local_copy(input.to_string()),
                        FileExplorerTab::Remote => self.action_remote_copy(input.to_string()),
                        _ => panic!("Found tab doesn't support COPY"),
                    }
                    self.umount_wait();
                    // Reload files
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.update_local_filelist(),
                        FileExplorerTab::Remote => self.update_remote_filelist(),
                        _ => None,
                    }
                }
                (COMPONENT_INPUT_COPY, _) => None,
                // -- exec popup
                (COMPONENT_INPUT_EXEC, key) if key == &MSG_KEY_ESC => {
                    self.umount_exec();
                    None
                }
                (COMPONENT_INPUT_EXEC, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
                    // Exex command
                    self.umount_exec();
                    self.mount_blocking_wait(format!("Executing '{}'…", input).as_str());
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.action_local_exec(input.to_string()),
                        FileExplorerTab::Remote => self.action_remote_exec(input.to_string()),
                        _ => panic!("Found tab doesn't support EXEC"),
                    }
                    self.umount_wait();
                    // Reload files
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.update_local_filelist(),
                        FileExplorerTab::Remote => self.update_remote_filelist(),
                        _ => None,
                    }
                }
                (COMPONENT_INPUT_EXEC, _) => None,
                // -- find popup
                (COMPONENT_INPUT_FIND, key) if key == &MSG_KEY_ESC => {
                    self.umount_find_input();
                    None
                }
                (COMPONENT_INPUT_FIND, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
                    self.umount_find_input();
                    // Find
                    let res: Result<Vec<FsEntry>, String> = match self.browser.tab() {
                        FileExplorerTab::Local => self.action_local_find(input.to_string()),
                        FileExplorerTab::Remote => self.action_remote_find(input.to_string()),
                        _ => panic!("Trying to search for files, while already in a find result"),
                    };
                    // Match result
                    match res {
                        Err(err) => {
                            // Mount error
                            self.mount_error(err.as_str());
                        }
                        Ok(files) => {
                            // Create explorer and load files
                            self.browser.set_found(files);
                            // Mount result widget
                            self.mount_find(input);
                            self.update_find_list();
                            // Initialize tab
                            self.browser.change_tab(match self.browser.tab() {
                                FileExplorerTab::Local => FileExplorerTab::FindLocal,
                                FileExplorerTab::Remote => FileExplorerTab::FindRemote,
                                _ => FileExplorerTab::FindLocal,
                            });
                        }
                    }
                    None
                }
                // -- goto popup
                (COMPONENT_INPUT_GOTO, key) if key == &MSG_KEY_ESC => {
                    self.umount_goto();
                    None
                }
                (COMPONENT_INPUT_GOTO, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
                    match self.browser.tab() {
                        FileExplorerTab::Local => {
                            self.action_change_local_dir(input.to_string(), false)
                        }
                        FileExplorerTab::Remote => {
                            self.action_change_remote_dir(input.to_string(), false)
                        }
                        _ => panic!("Found tab doesn't support GOTO"),
                    }
                    // Umount
                    self.umount_goto();
                    // Reload files if sync
                    if self.browser.sync_browsing {
                        match self.browser.tab() {
                            FileExplorerTab::Remote => self.update_local_filelist(),
                            FileExplorerTab::Local => self.update_remote_filelist(),
                            _ => None,
                        };
                    }
                    // Reload files
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.update_local_filelist(),
                        FileExplorerTab::Remote => self.update_remote_filelist(),
                        _ => None,
                    }
                }
                (COMPONENT_INPUT_GOTO, _) => None,
                // -- make directory
                (COMPONENT_INPUT_MKDIR, key) if key == &MSG_KEY_ESC => {
                    self.umount_mkdir();
                    None
                }
                (COMPONENT_INPUT_MKDIR, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.action_local_mkdir(input.to_string()),
                        FileExplorerTab::Remote => self.action_remote_mkdir(input.to_string()),
                        _ => panic!("Found tab doesn't support MKDIR"),
                    }
                    self.umount_mkdir();
                    // Reload files
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.update_local_filelist(),
                        FileExplorerTab::Remote => self.update_remote_filelist(),
                        _ => None,
                    }
                }
                (COMPONENT_INPUT_MKDIR, _) => None,
                // -- new file
                (COMPONENT_INPUT_NEWFILE, key) if key == &MSG_KEY_ESC => {
                    self.umount_newfile();
                    None
                }
                (COMPONENT_INPUT_NEWFILE, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.action_local_newfile(input.to_string()),
                        FileExplorerTab::Remote => self.action_remote_newfile(input.to_string()),
                        _ => panic!("Found tab doesn't support NEWFILE"),
                    }
                    self.umount_newfile();
                    // Reload files
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.update_local_filelist(),
                        FileExplorerTab::Remote => self.update_remote_filelist(),
                        _ => None,
                    }
                }
                (COMPONENT_INPUT_NEWFILE, _) => None,
                // -- open with
                (COMPONENT_INPUT_OPEN_WITH, key) if key == &MSG_KEY_ESC => {
                    self.umount_openwith();
                    None
                }
                (COMPONENT_INPUT_OPEN_WITH, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.action_local_open_with(input),
                        FileExplorerTab::Remote => self.action_remote_open_with(input),
                        FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => {
                            self.action_find_open_with(input)
                        }
                    }
                    self.umount_openwith();
                    None
                }
                (COMPONENT_INPUT_OPEN_WITH, _) => None,
                // -- rename
                (COMPONENT_INPUT_RENAME, key) if key == &MSG_KEY_ESC => {
                    self.umount_rename();
                    None
                }
                (COMPONENT_INPUT_RENAME, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
                    self.umount_rename();
                    self.mount_blocking_wait("Moving file(s)…");
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.action_local_rename(input.to_string()),
                        FileExplorerTab::Remote => self.action_remote_rename(input.to_string()),
                        _ => panic!("Found tab doesn't support RENAME"),
                    }
                    self.umount_wait();
                    // Reload files
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.update_local_filelist(),
                        FileExplorerTab::Remote => self.update_remote_filelist(),
                        _ => None,
                    }
                }
                (COMPONENT_INPUT_RENAME, _) => None,
                // -- save as
                (COMPONENT_INPUT_SAVEAS, key) if key == &MSG_KEY_ESC => {
                    self.umount_saveas();
                    None
                }
                (COMPONENT_INPUT_SAVEAS, Msg::OnSubmit(Payload::One(Value::Str(input)))) => {
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.action_local_saveas(input.to_string()),
                        FileExplorerTab::Remote => self.action_remote_saveas(input.to_string()),
                        FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => {
                            // Get entry
                            self.action_find_transfer(TransferOpts::default().save_as(Some(input)));
                        }
                    }
                    self.umount_saveas();
                    // Reload files
                    match self.browser.tab() {
                        // NOTE: Swapped is intentional
                        FileExplorerTab::Local => self.update_remote_filelist(),
                        FileExplorerTab::Remote => self.update_local_filelist(),
                        FileExplorerTab::FindLocal => self.update_remote_filelist(),
                        FileExplorerTab::FindRemote => self.update_local_filelist(),
                    }
                }
                (COMPONENT_INPUT_SAVEAS, _) => None,
                // -- fileinfo
                (COMPONENT_LIST_FILEINFO, key) | (COMPONENT_LIST_FILEINFO, key)
                    if key == &MSG_KEY_ENTER || key == &MSG_KEY_ESC =>
                {
                    self.umount_file_info();
                    None
                }
                (COMPONENT_LIST_FILEINFO, _) => None,
                // -- delete
                (COMPONENT_RADIO_DELETE, key)
                    if key == &MSG_KEY_ESC
                        || key == &Msg::OnSubmit(Payload::One(Value::Usize(1))) =>
                {
                    self.umount_radio_delete();
                    None
                }
                (COMPONENT_RADIO_DELETE, Msg::OnSubmit(Payload::One(Value::Usize(0)))) => {
                    // Choice is 'YES'
                    self.umount_radio_delete();
                    self.mount_blocking_wait("Removing file(s)…");
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.action_local_delete(),
                        FileExplorerTab::Remote => self.action_remote_delete(),
                        FileExplorerTab::FindLocal | FileExplorerTab::FindRemote => {
                            // Get entry
                            self.action_find_delete();
                            // Delete entries
                            match self.view.get_state(COMPONENT_EXPLORER_FIND) {
                                Some(Payload::One(Value::Usize(idx))) => {
                                    // Reload entries
                                    self.found_mut().unwrap().del_entry(idx);
                                }
                                Some(Payload::Vec(values)) => {
                                    values
                                        .iter()
                                        .map(|x| match x {
                                            Value::Usize(v) => *v,
                                            _ => 0,
                                        })
                                        .for_each(|x| self.found_mut().unwrap().del_entry(x));
                                }
                                _ => {}
                            }
                            self.update_find_list();
                        }
                    }
                    self.umount_wait();
                    // Reload files
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.update_local_filelist(),
                        FileExplorerTab::Remote => self.update_remote_filelist(),
                        FileExplorerTab::FindLocal => self.update_local_filelist(),
                        FileExplorerTab::FindRemote => self.update_remote_filelist(),
                    }
                }
                (COMPONENT_RADIO_DELETE, _) => None,
                // -- replace
                (COMPONENT_RADIO_REPLACE, key)
                    if key == &MSG_KEY_ESC
                        || key == &Msg::OnSubmit(Payload::One(Value::Usize(1))) =>
                {
                    self.umount_radio_replace();
                    None
                }
                (COMPONENT_RADIO_REPLACE, key) if key == &MSG_KEY_TAB => {
                    if self.is_radio_replace_extended() {
                        self.view.active(COMPONENT_LIST_REPLACING_FILES);
                    }
                    None
                }
                (COMPONENT_RADIO_REPLACE, Msg::OnSubmit(Payload::One(Value::Usize(0)))) => {
                    // Choice is 'YES'
                    self.umount_radio_replace();
                    self.action_finalize_pending_transfer();
                    None
                }
                (COMPONENT_RADIO_REPLACE, _) => None,
                (COMPONENT_LIST_REPLACING_FILES, key) if key == &MSG_KEY_TAB => {
                    self.view.active(COMPONENT_RADIO_REPLACE);
                    None
                }
                (COMPONENT_LIST_REPLACING_FILES, key) if key == &MSG_KEY_ESC => {
                    self.umount_radio_replace();
                    None
                }
                (COMPONENT_LIST_REPLACING_FILES, _) => None,
                // -- disconnect
                (COMPONENT_RADIO_DISCONNECT, key)
                    if key == &MSG_KEY_ESC
                        || key == &Msg::OnSubmit(Payload::One(Value::Usize(1))) =>
                {
                    self.umount_disconnect();
                    None
                }
                (COMPONENT_RADIO_DISCONNECT, Msg::OnSubmit(Payload::One(Value::Usize(0)))) => {
                    self.disconnect();
                    self.umount_disconnect();
                    None
                }
                (COMPONENT_RADIO_DISCONNECT, _) => None,
                // -- quit
                (COMPONENT_RADIO_QUIT, key)
                    if key == &MSG_KEY_ESC
                        || key == &Msg::OnSubmit(Payload::One(Value::Usize(1))) =>
                {
                    self.umount_quit();
                    None
                }
                (COMPONENT_RADIO_QUIT, Msg::OnSubmit(Payload::One(Value::Usize(0)))) => {
                    self.disconnect_and_quit();
                    self.umount_quit();
                    None
                }
                (COMPONENT_RADIO_QUIT, _) => None,
                // -- sorting
                (COMPONENT_RADIO_SORTING, key) if key == &MSG_KEY_ESC => {
                    self.umount_file_sorting();
                    None
                }
                (COMPONENT_RADIO_SORTING, Msg::OnSubmit(_)) => {
                    self.umount_file_sorting();
                    None
                }
                (COMPONENT_RADIO_SORTING, Msg::OnChange(Payload::One(Value::Usize(mode)))) => {
                    // Get sorting mode
                    let sorting: FileSorting = match mode {
                        1 => FileSorting::ModifyTime,
                        2 => FileSorting::CreationTime,
                        3 => FileSorting::Size,
                        _ => FileSorting::Name,
                    };
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.local_mut().sort_by(sorting),
                        FileExplorerTab::Remote => self.remote_mut().sort_by(sorting),
                        _ => panic!("Found result doesn't support SORTING"),
                    }
                    // Update status bar
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.refresh_local_status_bar(),
                        FileExplorerTab::Remote => self.refresh_remote_status_bar(),
                        _ => panic!("Found result doesn't support SORTING"),
                    };
                    // Reload files
                    match self.browser.tab() {
                        FileExplorerTab::Local => self.update_local_filelist(),
                        FileExplorerTab::Remote => self.update_remote_filelist(),
                        _ => None,
                    }
                }
                (COMPONENT_RADIO_SORTING, _) => None,
                // -- error
                (COMPONENT_TEXT_ERROR, key) | (COMPONENT_TEXT_ERROR, key)
                    if key == &MSG_KEY_ESC || key == &MSG_KEY_ENTER =>
                {
                    self.umount_error();
                    None
                }
                (COMPONENT_TEXT_ERROR, _) => None,
                // -- fatal
                (COMPONENT_TEXT_FATAL, key) | (COMPONENT_TEXT_FATAL, key)
                    if key == &MSG_KEY_ESC || key == &MSG_KEY_ENTER =>
                {
                    self.exit_reason = Some(super::ExitReason::Disconnect);
                    None
                }
                (COMPONENT_TEXT_FATAL, _) => None,
                // -- help
                (COMPONENT_TEXT_HELP, key) | (COMPONENT_TEXT_HELP, key)
                    if key == &MSG_KEY_ESC || key == &MSG_KEY_ENTER =>
                {
                    self.umount_help();
                    None
                }
                (COMPONENT_TEXT_HELP, _) => None,
                // -- progress bar
                (COMPONENT_PROGRESS_BAR_PARTIAL, key) if key == &MSG_KEY_CTRL_C => {
                    // Set transfer aborted to True
                    self.transfer.abort();
                    None
                }
                (COMPONENT_PROGRESS_BAR_PARTIAL, _) => None,
                // -- fallback
                (_, _) => None, // Nothing to do
            },
        }
    }
}

impl FileTransferActivity {
    /// ### update_local_filelist
    ///
    /// Update local file list
    pub(super) fn update_local_filelist(&mut self) -> Option<(String, Msg)> {
        match self.view.get_props(super::COMPONENT_EXPLORER_LOCAL) {
            Some(props) => {
                // Get width
                let width: usize = self
                    .context()
                    .store()
                    .get_unsigned(super::STORAGE_EXPLORER_WIDTH)
                    .unwrap_or(256);
                let hostname: String = match hostname::get() {
                    Ok(h) => {
                        let hostname: String = h.as_os_str().to_string_lossy().to_string();
                        let tokens: Vec<&str> = hostname.split('.').collect();
                        String::from(*tokens.get(0).unwrap_or(&"localhost"))
                    }
                    Err(_) => String::from("localhost"),
                };
                let hostname: String = format!(
                    "{}:{} ",
                    hostname,
                    fmt_path_elide_ex(self.local().wrkdir.as_path(), width, hostname.len() + 3) // 3 because of '/…/'
                );
                let files: Vec<String> = self
                    .local()
                    .iter_files()
                    .map(|x: &FsEntry| self.local().fmt_file(x))
                    .collect();
                // Update
                let props = FileListPropsBuilder::from(props)
                    .with_files(files)
                    .with_title(hostname, Alignment::Left)
                    .build();
                // Update
                self.view.update(super::COMPONENT_EXPLORER_LOCAL, props)
            }
            None => None,
        }
    }

    /// ### update_remote_filelist
    ///
    /// Update remote file list
    pub(super) fn update_remote_filelist(&mut self) -> Option<(String, Msg)> {
        match self.view.get_props(super::COMPONENT_EXPLORER_REMOTE) {
            Some(props) => {
                // Get width
                let width: usize = self
                    .context()
                    .store()
                    .get_unsigned(super::STORAGE_EXPLORER_WIDTH)
                    .unwrap_or(256);
                let hostname = self.get_remote_hostname();
                let hostname: String = format!(
                    "{}:{} ",
                    hostname,
                    fmt_path_elide_ex(
                        self.remote().wrkdir.as_path(),
                        width,
                        hostname.len() + 3 // 3 because of '/…/'
                    )
                );
                let files: Vec<String> = self
                    .remote()
                    .iter_files()
                    .map(|x: &FsEntry| self.remote().fmt_file(x))
                    .collect();
                // Update
                let props = FileListPropsBuilder::from(props)
                    .with_files(files)
                    .with_title(hostname, Alignment::Left)
                    .build();
                self.view.update(super::COMPONENT_EXPLORER_REMOTE, props)
            }
            None => None,
        }
    }

    /// ### update_logbox
    ///
    /// Update log box
    pub(super) fn update_logbox(&mut self) -> Option<(String, Msg)> {
        match self.view.get_props(super::COMPONENT_LOG_BOX) {
            Some(props) => {
                // Make log entries
                let mut table: TableBuilder = TableBuilder::default();
                for (idx, record) in self.log_records.iter().enumerate() {
                    // Add row if not first row
                    if idx > 0 {
                        table.add_row();
                    }
                    let fg = match record.level {
                        LogLevel::Error => Color::Red,
                        LogLevel::Warn => Color::Yellow,
                        LogLevel::Info => Color::Green,
                    };
                    table
                        .add_col(TextSpan::from(format!(
                            "{}",
                            record.time.format("%Y-%m-%dT%H:%M:%S%Z")
                        )))
                        .add_col(TextSpan::from(" ["))
                        .add_col(
                            TextSpan::new(
                                format!(
                                    "{:5}",
                                    match record.level {
                                        LogLevel::Error => "ERROR",
                                        LogLevel::Warn => "WARN",
                                        LogLevel::Info => "INFO",
                                    }
                                )
                                .as_str(),
                            )
                            .fg(fg),
                        )
                        .add_col(TextSpan::from("]: "))
                        .add_col(TextSpan::from(record.msg.as_ref()));
                }
                let table = table.build();
                let props = LogboxPropsBuilder::from(props).with_log(table).build();
                self.view.update(super::COMPONENT_LOG_BOX, props)
            }
            None => None,
        }
    }

    pub(super) fn update_progress_bar(&mut self, filename: String) -> Option<(String, Msg)> {
        if let Some(props) = self.view.get_props(COMPONENT_PROGRESS_BAR_FULL) {
            let props = ProgressBarPropsBuilder::from(props)
                .with_label(self.transfer.full.to_string())
                .with_progress(self.transfer.full.calc_progress())
                .build();
            let _ = self.view.update(COMPONENT_PROGRESS_BAR_FULL, props);
        }
        match self.view.get_props(COMPONENT_PROGRESS_BAR_PARTIAL) {
            Some(props) => {
                let props = ProgressBarPropsBuilder::from(props)
                    .with_title(filename, Alignment::Center)
                    .with_label(self.transfer.partial.to_string())
                    .with_progress(self.transfer.partial.calc_progress())
                    .build();
                self.view.update(COMPONENT_PROGRESS_BAR_PARTIAL, props)
            }
            None => None,
        }
    }

    /// ### finalize_find
    ///
    /// Finalize find process
    fn finalize_find(&mut self) {
        // Set found to none
        self.browser.del_found();
        // Restore tab
        self.browser.change_tab(match self.browser.tab() {
            FileExplorerTab::FindLocal => FileExplorerTab::Local,
            FileExplorerTab::FindRemote => FileExplorerTab::Remote,
            _ => FileExplorerTab::Local,
        });
    }

    fn update_find_list(&mut self) -> Option<(String, Msg)> {
        match self.view.get_props(COMPONENT_EXPLORER_FIND) {
            None => None,
            Some(props) => {
                // Prepare files
                let files: Vec<String> = self
                    .found()
                    .unwrap()
                    .iter_files()
                    .map(|x: &FsEntry| self.found().unwrap().fmt_file(x))
                    .collect();
                let props = FileListPropsBuilder::from(props).with_files(files).build();
                self.view.update(COMPONENT_EXPLORER_FIND, props)
            }
        }
    }
}
