//! ## SetupActivity
//!
//! `setup_activity` is the module which implements the Setup activity, which is the activity to
//! work on termscp configuration

/**
 * 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::{components, Context, Id, IdCommon, IdTheme, SetupActivity, Theme, ViewLayout};

// Ext
use tuirealm::props::Color;
use tuirealm::tui::layout::{Constraint, Direction, Layout};
use tuirealm::{State, StateValue};

impl SetupActivity {
    // -- view

    /// ### init_theme
    ///
    /// Initialize thene view
    pub(super) fn init_theme(&mut self) {
        // Init view (and mount commons)
        self.new_app(ViewLayout::Theme);
        // Mount titles
        self.load_titles();
        // Load styles
        self.load_styles();
        // Active first field
        assert!(self.app.active(&Id::Theme(IdTheme::AuthProtocol)).is_ok());
    }

    pub(super) fn view_theme(&mut self) {
        let mut ctx: Context = self.context.take().unwrap();
        let _ = ctx.terminal().draw(|f| {
            // Prepare main chunks
            let chunks = Layout::default()
                .direction(Direction::Vertical)
                .margin(1)
                .constraints(
                    [
                        Constraint::Length(3),  // Current tab
                        Constraint::Length(22), // Main body
                        Constraint::Length(3),  // Help footer
                    ]
                    .as_ref(),
                )
                .split(f.size());
            // Render common widget
            self.app.view(&Id::Common(IdCommon::Header), f, chunks[0]);
            self.app.view(&Id::Common(IdCommon::Footer), f, chunks[2]);
            // Make chunks
            let colors_layout = Layout::default()
                .direction(Direction::Horizontal)
                .constraints(
                    [
                        Constraint::Percentage(25),
                        Constraint::Percentage(25),
                        Constraint::Percentage(25),
                        Constraint::Percentage(25),
                    ]
                    .as_ref(),
                )
                .split(chunks[1]);
            let auth_colors_layout = Layout::default()
                .direction(Direction::Vertical)
                .constraints(
                    [
                        Constraint::Length(1), // Title
                        Constraint::Length(3), // Protocol
                        Constraint::Length(3), // Addr
                        Constraint::Length(3), // Port
                        Constraint::Length(3), // Username
                        Constraint::Length(3), // Password
                        Constraint::Length(3), // Bookmarks
                        Constraint::Length(3), // Recents
                    ]
                    .as_ref(),
                )
                .split(colors_layout[0]);
            self.app
                .view(&Id::Theme(IdTheme::AuthTitle), f, auth_colors_layout[0]);
            self.app
                .view(&Id::Theme(IdTheme::AuthProtocol), f, auth_colors_layout[1]);
            self.app
                .view(&Id::Theme(IdTheme::AuthAddress), f, auth_colors_layout[2]);
            self.app
                .view(&Id::Theme(IdTheme::AuthPort), f, auth_colors_layout[3]);
            self.app
                .view(&Id::Theme(IdTheme::AuthUsername), f, auth_colors_layout[4]);
            self.app
                .view(&Id::Theme(IdTheme::AuthPassword), f, auth_colors_layout[5]);
            self.app
                .view(&Id::Theme(IdTheme::AuthBookmarks), f, auth_colors_layout[6]);
            self.app.view(
                &Id::Theme(IdTheme::AuthRecentHosts),
                f,
                auth_colors_layout[7],
            );
            let misc_colors_layout = Layout::default()
                .direction(Direction::Vertical)
                .constraints(
                    [
                        Constraint::Length(1), // Title
                        Constraint::Length(3), // Error
                        Constraint::Length(3), // Info
                        Constraint::Length(3), // Input
                        Constraint::Length(3), // Keys
                        Constraint::Length(3), // Quit
                        Constraint::Length(3), // Save
                        Constraint::Length(3), // Warn
                    ]
                    .as_ref(),
                )
                .split(colors_layout[1]);
            self.app
                .view(&Id::Theme(IdTheme::MiscTitle), f, misc_colors_layout[0]);
            self.app
                .view(&Id::Theme(IdTheme::MiscError), f, misc_colors_layout[1]);
            self.app
                .view(&Id::Theme(IdTheme::MiscInfo), f, misc_colors_layout[2]);
            self.app
                .view(&Id::Theme(IdTheme::MiscInput), f, misc_colors_layout[3]);
            self.app
                .view(&Id::Theme(IdTheme::MiscKeys), f, misc_colors_layout[4]);
            self.app
                .view(&Id::Theme(IdTheme::MiscQuit), f, misc_colors_layout[5]);
            self.app
                .view(&Id::Theme(IdTheme::MiscSave), f, misc_colors_layout[6]);
            self.app
                .view(&Id::Theme(IdTheme::MiscWarn), f, misc_colors_layout[7]);

            let transfer_colors_layout_col1 = Layout::default()
                .direction(Direction::Vertical)
                .constraints(
                    [
                        Constraint::Length(1), // Title
                        Constraint::Length(3), // local explorer bg
                        Constraint::Length(3), // local explorer fg
                        Constraint::Length(3), // local explorer hg
                        Constraint::Length(3), // remote explorer bg
                        Constraint::Length(3), // remote explorer fg
                        Constraint::Length(3), // remote explorer hg
                        Constraint::Length(3), // empty
                    ]
                    .as_ref(),
                )
                .split(colors_layout[2]);
            self.app.view(
                &Id::Theme(IdTheme::TransferTitle),
                f,
                transfer_colors_layout_col1[0],
            );
            self.app.view(
                &Id::Theme(IdTheme::ExplorerLocalBg),
                f,
                transfer_colors_layout_col1[1],
            );
            self.app.view(
                &Id::Theme(IdTheme::ExplorerLocalFg),
                f,
                transfer_colors_layout_col1[2],
            );
            self.app.view(
                &Id::Theme(IdTheme::ExplorerLocalHg),
                f,
                transfer_colors_layout_col1[3],
            );
            self.app.view(
                &Id::Theme(IdTheme::ExplorerRemoteBg),
                f,
                transfer_colors_layout_col1[4],
            );
            self.app.view(
                &Id::Theme(IdTheme::ExplorerRemoteFg),
                f,
                transfer_colors_layout_col1[5],
            );
            self.app.view(
                &Id::Theme(IdTheme::ExplorerRemoteHg),
                f,
                transfer_colors_layout_col1[6],
            );
            let transfer_colors_layout_col2 = Layout::default()
                .direction(Direction::Vertical)
                .constraints(
                    [
                        Constraint::Length(1), // Title
                        Constraint::Length(3), // Full prog bar
                        Constraint::Length(3), // Partial prog bar
                        Constraint::Length(3), // log bg
                        Constraint::Length(3), // log window
                        Constraint::Length(3), // status sorting
                        Constraint::Length(3), // status hidden
                        Constraint::Length(3), // sync browsing
                    ]
                    .as_ref(),
                )
                .split(colors_layout[3]);
            self.app.view(
                &Id::Theme(IdTheme::TransferTitle2),
                f,
                transfer_colors_layout_col2[0],
            );
            self.app.view(
                &Id::Theme(IdTheme::ProgBarFull),
                f,
                transfer_colors_layout_col2[1],
            );
            self.app.view(
                &Id::Theme(IdTheme::ProgBarPartial),
                f,
                transfer_colors_layout_col2[2],
            );
            self.app.view(
                &Id::Theme(IdTheme::LogBg),
                f,
                transfer_colors_layout_col2[3],
            );
            self.app.view(
                &Id::Theme(IdTheme::LogWindow),
                f,
                transfer_colors_layout_col2[4],
            );
            self.app.view(
                &Id::Theme(IdTheme::StatusSorting),
                f,
                transfer_colors_layout_col2[5],
            );
            self.app.view(
                &Id::Theme(IdTheme::StatusHidden),
                f,
                transfer_colors_layout_col2[6],
            );
            self.app.view(
                &Id::Theme(IdTheme::StatusSync),
                f,
                transfer_colors_layout_col2[7],
            );
            // Popups
            self.view_popups(&mut f);
        });
        // Put context back to context
        self.context = Some(ctx);
    }

    fn load_titles(&mut self) {
        assert!(self
            .app
            .remount(
                &Id::Theme(IdTheme::AuthTitle),
                Box::new(components::AuthTitle::default()),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                &Id::Theme(IdTheme::MiscTitle),
                Box::new(components::MiscTitle::default()),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                &Id::Theme(IdTheme::TransferTitle),
                Box::new(components::TransferTitle::default()),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                &Id::Theme(IdTheme::TransferTitle2),
                Box::new(components::TransferTitle2::default()),
                vec![]
            )
            .is_ok());
    }

    /// ### load_styles
    ///
    /// Load values from theme into input fields
    pub(crate) fn load_styles(&mut self) {
        let theme: Theme = self.theme().clone();
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::AuthAddress),
                Box::new(components::AuthAddress::new(theme.auth_address)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::AuthBookmarks),
                Box::new(components::AuthBookmarks::new(theme.auth_bookmarks)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::AuthPassword),
                Box::new(components::AuthPassword::new(theme.auth_password)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::AuthPort),
                Box::new(components::AuthPort::new(theme.auth_port)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::AuthProtocol),
                Box::new(components::AuthProtocol::new(theme.auth_protocol)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::AuthRecentHosts),
                Box::new(components::AuthRecentHosts::new(theme.auth_recents)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::AuthUsername),
                Box::new(components::AuthUsername::new(theme.auth_username)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::ExplorerLocalBg),
                Box::new(components::ExplorerLocalBg::new(theme.misc_error_dialog)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::ExplorerLocalFg),
                Box::new(components::ExplorerLocalFg::new(theme.misc_info_dialog)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::ExplorerLocalHg),
                Box::new(components::ExplorerLocalHg::new(theme.misc_input_dialog)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::ExplorerRemoteBg),
                Box::new(components::ExplorerRemoteBg::new(theme.misc_keys)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::ExplorerRemoteFg),
                Box::new(components::ExplorerRemoteFg::new(theme.misc_quit_dialog)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::ExplorerRemoteHg),
                Box::new(components::ExplorerRemoteHg::new(theme.misc_save_dialog)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::LogBg),
                Box::new(components::LogBg::new(theme.misc_warn_dialog)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::LogWindow),
                Box::new(components::LogWindow::new(
                    theme.transfer_local_explorer_background
                )),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::MiscError),
                Box::new(components::MiscError::new(
                    theme.transfer_local_explorer_foreground
                )),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::MiscInfo),
                Box::new(components::MiscInfo::new(
                    theme.transfer_local_explorer_highlighted
                )),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::MiscInput),
                Box::new(components::MiscInput::new(
                    theme.transfer_remote_explorer_background
                )),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::MiscKeys),
                Box::new(components::MiscKeys::new(
                    theme.transfer_remote_explorer_foreground
                )),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::MiscQuit),
                Box::new(components::MiscQuit::new(
                    theme.transfer_remote_explorer_highlighted
                )),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::MiscSave),
                Box::new(components::MiscSave::new(theme.transfer_progress_bar_full)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::MiscWarn),
                Box::new(components::MiscWarn::new(
                    theme.transfer_progress_bar_partial
                )),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::ProgBarFull),
                Box::new(components::ProgBarFull::new(theme.transfer_log_background)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::ProgBarPartial),
                Box::new(components::ProgBarPartial::new(theme.transfer_log_window)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::StatusHidden),
                Box::new(components::StatusHidden::new(theme.transfer_status_sorting)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::StatusSorting),
                Box::new(components::StatusSorting::new(theme.transfer_status_hidden)),
                vec![]
            )
            .is_ok());
        assert!(self
            .app
            .remount(
                Id::Theme(IdTheme::StatusSync),
                Box::new(components::StatusSync::new(
                    theme.transfer_status_sync_browsing
                )),
                vec![]
            )
            .is_ok());
    }

    /// ### collect_styles
    ///
    /// Collect values from input and put them into the theme.
    /// If a component has an invalid color, returns Err(component_id)
    pub(crate) fn collect_styles(&mut self) -> Result<(), &'static str> {
        // auth
        let auth_address = self
            .get_color(&Id::Theme(IdTheme::AuthAddress))
            .map_err(|_| &Id::Theme(IdTheme::AuthAddress))?;
        let auth_bookmarks = self
            .get_color(&Id::Theme(IdTheme::AuthBookmarks))
            .map_err(|_| &Id::Theme(IdTheme::AuthBookmarks))?;
        let auth_password = self
            .get_color(&Id::Theme(IdTheme::AuthPassword))
            .map_err(|_| &Id::Theme(IdTheme::AuthPassword))?;
        let auth_port = self
            .get_color(&Id::Theme(IdTheme::AuthPort))
            .map_err(|_| &Id::Theme(IdTheme::AuthPort))?;
        let auth_protocol = self
            .get_color(&Id::Theme(IdTheme::AuthProtocol))
            .map_err(|_| &Id::Theme(IdTheme::AuthProtocol))?;
        let auth_recents = self
            .get_color(&Id::Theme(IdTheme::AuthRecentHosts))
            .map_err(|_| &Id::Theme(IdTheme::AuthRecentHosts))?;
        let auth_username = self
            .get_color(&Id::Theme(IdTheme::AuthUsername))
            .map_err(|_| &Id::Theme(IdTheme::AuthUsername))?;
        // misc
        let misc_error_dialog = self
            .get_color(&Id::Theme(IdTheme::MiscError))
            .map_err(|_| &Id::Theme(IdTheme::MiscError))?;
        let misc_info_dialog = self
            .get_color(&Id::Theme(IdTheme::MiscInfo))
            .map_err(|_| &Id::Theme(IdTheme::MiscInfo))?;
        let misc_input_dialog = self
            .get_color(&Id::Theme(IdTheme::MiscInput))
            .map_err(|_| &Id::Theme(IdTheme::MiscInput))?;
        let misc_keys = self
            .get_color(&Id::Theme(IdTheme::MiscKeys))
            .map_err(|_| &Id::Theme(IdTheme::MiscKeys))?;
        let misc_quit_dialog = self
            .get_color(&Id::Theme(IdTheme::MiscQuit))
            .map_err(|_| &Id::Theme(IdTheme::MiscQuit))?;
        let misc_save_dialog = self
            .get_color(&Id::Theme(IdTheme::MiscSave))
            .map_err(|_| &Id::Theme(IdTheme::MiscSave))?;
        let misc_warn_dialog = self
            .get_color(&Id::Theme(IdTheme::MiscWarn))
            .map_err(|_| &Id::Theme(IdTheme::MiscWarn))?;
        // transfer
        let transfer_local_explorer_background = self
            .get_color(&Id::Theme(IdTheme::ExplorerLocalBg))
            .map_err(|_| &Id::Theme(IdTheme::ExplorerLocalBg))?;
        let transfer_local_explorer_foreground = self
            .get_color(&Id::Theme(IdTheme::ExplorerLocalFg))
            .map_err(|_| &Id::Theme(IdTheme::ExplorerLocalFg))?;
        let transfer_local_explorer_highlighted = self
            .get_color(&Id::Theme(IdTheme::ExplorerLocalHg))
            .map_err(|_| &Id::Theme(IdTheme::ExplorerLocalHg))?;
        let transfer_remote_explorer_background = self
            .get_color(&Id::Theme(IdTheme::ExplorerRemoteBg))
            .map_err(|_| &Id::Theme(IdTheme::ExplorerRemoteBg))?;
        let transfer_remote_explorer_foreground = self
            .get_color(&Id::Theme(IdTheme::ExplorerRemoteFg))
            .map_err(|_| &Id::Theme(IdTheme::ExplorerRemoteFg))?;
        let transfer_remote_explorer_highlighted = self
            .get_color(&Id::Theme(IdTheme::ExplorerRemoteHg))
            .map_err(|_| &Id::Theme(IdTheme::ExplorerRemoteHg))?;
        let transfer_log_background = self
            .get_color(&Id::Theme(IdTheme::LogBg))
            .map_err(|_| &Id::Theme(IdTheme::LogBg))?;
        let transfer_log_window = self
            .get_color(&Id::Theme(IdTheme::LogWindow))
            .map_err(|_| &Id::Theme(IdTheme::LogWindow))?;
        let transfer_progress_bar_full = self
            .get_color(&Id::Theme(IdTheme::ProgBarFull))
            .map_err(|_| &Id::Theme(IdTheme::ProgBarFull))?;
        let transfer_progress_bar_partial = self
            .get_color(&Id::Theme(IdTheme::ProgBarPartial))
            .map_err(|_| &Id::Theme(IdTheme::ProgBarPartial))?;
        let transfer_status_hidden = self
            .get_color(&Id::Theme(IdTheme::StatusHidden))
            .map_err(|_| &Id::Theme(IdTheme::StatusHidden))?;
        let transfer_status_sorting = self
            .get_color(&Id::Theme(IdTheme::StatusSorting))
            .map_err(|_| &Id::Theme(IdTheme::StatusSorting))?;
        let transfer_status_sync_browsing = self
            .get_color(&Id::Theme(IdTheme::StatusSync))
            .map_err(|_| &Id::Theme(IdTheme::StatusSync))?;
        // Update theme
        let mut theme: &mut Theme = self.theme_mut();
        theme.auth_address = auth_address;
        theme.auth_bookmarks = auth_bookmarks;
        theme.auth_password = auth_password;
        theme.auth_port = auth_port;
        theme.auth_protocol = auth_protocol;
        theme.auth_recents = auth_recents;
        theme.auth_username = auth_username;
        theme.misc_error_dialog = misc_error_dialog;
        theme.misc_info_dialog = misc_info_dialog;
        theme.misc_input_dialog = misc_input_dialog;
        theme.misc_keys = misc_keys;
        theme.misc_quit_dialog = misc_quit_dialog;
        theme.misc_save_dialog = misc_save_dialog;
        theme.misc_warn_dialog = misc_warn_dialog;
        theme.transfer_local_explorer_background = transfer_local_explorer_background;
        theme.transfer_local_explorer_foreground = transfer_local_explorer_foreground;
        theme.transfer_local_explorer_highlighted = transfer_local_explorer_highlighted;
        theme.transfer_remote_explorer_background = transfer_remote_explorer_background;
        theme.transfer_remote_explorer_foreground = transfer_remote_explorer_foreground;
        theme.transfer_remote_explorer_highlighted = transfer_remote_explorer_highlighted;
        theme.transfer_log_background = transfer_log_background;
        theme.transfer_log_window = transfer_log_window;
        theme.transfer_progress_bar_full = transfer_progress_bar_full;
        theme.transfer_progress_bar_partial = transfer_progress_bar_partial;
        theme.transfer_status_hidden = transfer_status_hidden;
        theme.transfer_status_sorting = transfer_status_sorting;
        theme.transfer_status_sync_browsing = transfer_status_sync_browsing;
        Ok(())
    }

    /// ### get_color
    ///
    /// Get color from component
    fn get_color(&self, component: &Id) -> Result<Color, ()> {
        match self.app.state(component) {
            Ok(State::One(StateValue::Str(color))) => {
                match crate::utils::parser::parse_color(color.as_str()) {
                    Some(c) => Ok(c),
                    None => Err(()),
                }
            }
            _ => Err(()),
        }
    }
}
