"""Defines the graphical user interface based on interactive widgets."""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/01_view.ipynb.

# %% auto 0
__all__ = ['change_widget_state', 'UserInfoPanel', 'NWBMetadataPanel', 'SourceDataPanel', 'AnalysisSettingsPanel', 'MainScreen',
           'WidgetsInterface']

# %% ../nbs/01_view.ipynb 3
import ipywidgets as w
from ipyfilechooser import FileChooser
from datetime import datetime
from dataclasses import dataclass, fields
from typing import Any
from pathlib import Path

# %% ../nbs/01_view.ipynb 4
from .datamodels import Config

# %% ../nbs/01_view.ipynb 5
def change_widget_state(widget: w.Widget,
                        value: Any | None = None,
                        description: str | None = None,
                        disabled: bool | None = None,
                        visibility: str | None = None,
                        tooltip: str | None = None,
                        button_style: str | None = None) -> w.Widget:
    if value is not None:
        widget.value = value
    if description is not None:
        widget.description = description
    if disabled is not None:
        widget.disabled = disabled
    if visibility is not None:
        widget.layout.visibility = visibility
    if tooltip is not None:
        widget.tooltip = tooltip
    if button_style is not None:
        widget.button_style = button_style
    return widget

# %% ../nbs/01_view.ipynb 6
class UserInfoPanel:

    def __init__(self) -> None:
        # Initialize basic parameters and configs:
        self.user_timezone = datetime.now().astimezone().tzinfo
        self.logs_message_count = 0
        self.progress_in_percent = 0.0 # still required?

        self.vertical_spacer = w.HTML(value = '', layout = w.Layout(height = '15px'))
        self.latest_logs = w.Label(
            value = ' ... the latest logs message will be displayed here ... ',
            style = {'font_style': 'italic', 'text_color': 'gray', 'font_family': 'monospace', 'text_align': 'center'},
            layout = w.Layout(width = 'initial')
        )
        self.progress_bar = w.FloatProgress(
            description = 'Progress',
            style = {'description_width': 'initial'},
            layout = w.Layout(width = '20%')
        )
        self.detailed_logs_output = w.Output(
            layout = w.Layout(
                max_height = '200px',
                y_overflow='scroll'
            )
        )
        self.max_log_lines_in_output = int(self.detailed_logs_output.layout.max_height.replace('px', '')) / 15
        self.detailed_logs_accordion = w.Accordion(
            children = [self.detailed_logs_output],
            titles = ('Detailed logs', ),
            selected_index = None,
            layout = w.Layout(width = '95%')
        )


    @property
    def widget(self) -> w.VBox:
        info = w.HTML(
            value="<p style='font-size:16px; font-weight:bold; text-align:center;'>Info</p>",
            layout = w.Layout(width = '40px')
        )
        info_overview_box = w.HBox(
            [
                info,
                self.latest_logs,
                self.progress_bar
            ],
            layout = w.Layout(
                justify_content = 'space-between',
                align_items = 'center',
                width = '95%'
            )
        )
        widget = w.VBox(
            [
                info_overview_box,
                self.detailed_logs_accordion,
                self.vertical_spacer
            ],
            layout = w.Layout(align_items = 'center')
        )
        widget.add_class('box-info-panel')
        return widget


    def add_new_logs(self, message: str) -> None:
        current_time = datetime.now(self.user_timezone)
        # Update latest logs:
        time_prefix_latest_logs = current_time.strftime('%H-%M-%S')
        if len(message) > 125:
            self.latest_logs.value = f'{time_prefix_latest_logs}: {message[:85]}...(find full message in detailed logs)'
        else:
            self.latest_logs.value = f'{time_prefix_latest_logs}: {message}'
        # Update detailed logs:
        time_prefix_detailed_logs = current_time.strftime('%d-%m-%y %H:%M:%S.%f')
        self.logs_message_count += 1
        # Check if title has already been changed:
        if self.detailed_logs_accordion.get_title(0) == 'Detailed logs':
            # If not, check if max lines have been reached with this new message and adjust title accordingly:
            if self.logs_message_count >= self.max_log_lines_in_output:
                self.detailed_logs_accordion.set_title(0, 'Detailed logs - please scroll down to see latest logs')
        with self.detailed_logs_output:
            print(f'{time_prefix_detailed_logs}: {message}')


    def update_progress_bar(self, progress_in_percent: float) -> None:
        if progress_in_percent == 100.0:
            self.progress_bar.bar_style = 'success'
        else:
            self.progress_bar.bar_style = ''
        self.progress_bar.value = progress_in_percent

# %% ../nbs/01_view.ipynb 7
class NWBMetadataPanel:
    @dataclass
    class NWBMetadata:
        experiment_description: w.Text = None
        experimenter: w.Text = None
        lab: w.Text = None
        institution: w.Text = None
        notes: w.Textarea = None
        model_number: w.Text = None
        manufacturer: w.Text = None
        description: w.Textarea = None
        location: w.Text = None
        calcium_indicator: w.Text = None
        excitation_wavelength: w.BoundedFloatText = None
        emission_wavelength: w.BoundedFloatText = None
        imaging_description: w.Textarea = None

        @property
        def current_metadata(self) -> dict[str, Any]:
            return {
                'experiment_description': self.experiment_description.value,
                'experimenter': self.experimenter.value,
                'lab': self.lab.value,
                'institution': self.institution.value,
                'notes': self.notes.value,
                'model_number': self.model_number.value,
                'manufacturer': self.manufacturer.value,
                'description': self.description.value,
                'location': self.location.value,
                'calcium_indicator': self.calcium_indicator.value,
                'excitation_wavelength': self.excitation_wavelength.value,
                'emission_wavelength': self.emission_wavelength.value,
                'imaging_description': self.imaging_description.value,
            }

    def __init__(self) -> None:
        self.metadata = self.NWBMetadata()
        self.metadata.experiment_description = w.Text()
        self.metadata.experimenter = w.Text()
        self.metadata.lab = w.Text()
        self.metadata.institution = w.Text()
        self.metadata.notes = w.Textarea()
        self.metadata.model_number = w.Text()
        self.metadata.manufacturer = w.Text()
        self.metadata.description = w.Textarea()
        self.metadata.location = w.Text()
        self.metadata.calcium_indicator = w.Text()
        self.metadata.excitation_wavelength = w.BoundedFloatText(min=0.0, max=1400.0)
        self.metadata.emission_wavelength = w.BoundedFloatText()
        self.metadata.imaging_description = w.Textarea()
        self.general_section = w.VBox(
            [
                w.HTML(
                    value="<p style='font-size:16px; font-weight:bold; text-align:center;'>General</p>"
                ),
                w.HBox(
                    [
                        w.Label(
                            'Experiment description: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.experiment_description,
                    ],
                ),
                w.HBox(
                    [
                        w.Label(
                            'Experimenter: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.experimenter,
                    ]
                ),
                w.HBox(
                    [
                        w.Label(
                            'Lab: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.lab,
                    ]
                ),
                w.HBox(
                    [
                        w.Label(
                            'Institution: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.institution,
                    ]
                ),
                w.HBox(
                    [
                        w.Label(
                            'Additional notes: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.notes,
                    ]
                ),
            ],
            layout=w.Layout(
                justify_content='flex-start',
                align_items='flex-start',
                width='100%'
            )
        )
        self.microscope_section = w.VBox(
            [
                w.HTML(
                    value="<p style='font-size:16px; font-weight:bold; text-align:center;'>Microscope</p>"
                ),
                w.HBox(
                    [
                        w.Label(
                            'Model number: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.model_number,
                    ],
                ),
                w.HBox(
                    [
                        w.Label(
                            'Manufacturer: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.manufacturer,
                    ]
                ),
                w.HBox(
                    [
                        w.Label(
                            'Description: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.description,
                    ]
                ),
            ],
            layout=w.Layout(
                justify_content='flex-start',
                align_items='flex-start',
                width='100%'
            )
        )
        self.imaging_section = w.VBox(
            [
                w.HTML(
                    value="<p style='font-size:16px; font-weight:bold; text-align:center;'>Imaging</p>"
                ),
                w.HBox(
                    [
                        w.Label(
                            'Location: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.location,
                    ],
                ),
                w.HBox(
                    [
                        w.Label(
                            'Calcium indicator: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.calcium_indicator,
                    ]
                ),
                w.HBox(
                    [
                        w.Label(
                            'Excitation wavelength: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.excitation_wavelength,
                    ]
                ),
                w.HBox(
                    [
                        w.Label(
                            'Emission wavelength: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.emission_wavelength,
                    ]
                ),
                w.HBox(
                    [
                        w.Label(
                            'Additional notes: ',
                            layout=w.Layout(width='150px')
                        ),
                        self.metadata.imaging_description,
                    ]
                ),
            ],
            layout=w.Layout(
                justify_content='flex-start',
                align_items='flex-start',
                width='100%'
            )
        )

    @property
    def widget(self) -> w.VBox:
        metadata_sections = w.HBox(
            [
                self.general_section,
                self.microscope_section,
                self.imaging_section,
            ],
            layout=w.Layout(width='100%')
        )
        nwb_metadata_accordion = w.Accordion(
            children=[metadata_sections],
            titles=('NWB Metadata',),
            selected_index=None,
            layout=w.Layout(width='95%')
        )
        info = w.HTML(
            value="<p style='font-size:16px; font-weight:bold; text-align:center;'>NWB Metadata</p>",
            layout=w.Layout(width='95%')
        )
        widget = w.VBox(
            [
                info,
                nwb_metadata_accordion,
                w.HTML(value='', layout=w.Layout(height='15px'))
            ],
            layout=w.Layout(
                align_items='center',
                border_bottom='1px solid',
            )
        )
        widget.add_class('box-info-panel')
        return widget

# %% ../nbs/01_view.ipynb 8
class SourceDataPanel:

    @dataclass
    class SourceDataSettings:
        batch_mode: w.Checkbox = None
        focus_area_enabled: w.Checkbox = None
        roi_mode: w.Dropdown = None
        data_source_path: FileChooser = None

        @property
        def current_values(self) -> dict[str, Any]:
            return {
                'batch_mode': self.batch_mode.value,
                'focus_area_enabled': self.focus_area_enabled.value,
                'roi_mode': self.roi_mode.value,
                'data_source_path': self.data_source_path.value
            }

    
    def __init__(self) -> None:
        self.vertical_spacer = w.HTML(value = '', layout = w.Layout(height = '5px'))
        self.settings = self.SourceDataSettings()
        self.load_source_data_button = w.Button(
            description = 'Load Data',
            disabled = True,
            tooltip = 'Please first select which source data to load!',
            layout = w.Layout(width = '12%', height = '55px')
        )

    @property
    def widget(self) -> w.HBox:
        # Create and configure all elements:
        self.settings.batch_mode = w.Checkbox(
            description = 'Enable batch processing',
            value = False,
            indent = False
        )
        self.settings.focus_area_enabled = w.Checkbox(
            description = 'Limit analysis to focus area',
            value = False,
            indent = False
        )
        self.settings.roi_mode = w.Dropdown(
            options = [
                ('Use adjustable grid to create ROIs (congruent squares)', 'grid'),
                ('Load predefined ROIs from source data', 'file')
            ],
            description = 'ROIs:',
            value = 'grid',
            style = {'description_width': 'initial'},
            layout = {'width': 'initial'}
        )
        self.settings.data_source_path = FileChooser(
            title = 'Please select the recording file:',
            layout = w.Layout(width = '50%')
        )
        self.settings.data_source_path.rows = 8

        # Enable event handling:
        self.settings.batch_mode.observe(self._change_batch_mode_config)
        self.settings.focus_area_enabled.observe(self._change_focus_area_config)
        self.settings.roi_mode.observe(self._change_roi_mode_config)

        io_source_data_info = w.HTML(
            value="<p style='font-size:16px; font-weight:bold; text-align:center;'>General Settings</p>"
        )
        processing_modes_box = w.VBox(
            [
                self.settings.roi_mode,
                w.HBox(
                    [
                        self.settings.batch_mode,
                        self.settings.focus_area_enabled
                    ]
                )
            ],
            layout = {'width': '33%'}
        )
        # Arrange elements:
        source_data_settings_box = w.HBox(
            [
                processing_modes_box,
                self.settings.data_source_path,
                self.load_source_data_button
            ],
            layout = w.Layout(width = '100%', justify_content = 'space-between')
        )
        general_settings_box = w.VBox(
            [
                io_source_data_info,
                source_data_settings_box,
                self.vertical_spacer
            ],
            layout = w.Layout(width = '95%', align_items = 'center')
        )
        general_settings_box.add_class('box-general-settings')
        # Return the complete widget:
        return w.HBox([general_settings_box], layout = w.Layout(width = '100%', justify_content = 'center'))


    def _change_data_source_path_configs(self, show_dirs_only: bool, title: str, reset: bool) -> None:
        if reset:
            self.settings.data_source_path.reset()
            change_widget_state(self.load_source_data_button,
                                disabled = True,
                                tooltip = 'Please select which source data to load!')
        self.settings.data_source_path.show_only_dirs = show_dirs_only
        self.settings.data_source_path.title = title
        
    
    def _change_roi_mode_config(self, change) -> None:
        if change['name'] == 'value':
            if change['new'] == 'file':
                show_only_dirs = True
                if self.settings.batch_mode.value:
                    title = 'Please select the parent directory that contains subdirectories with the individual source data:'
                elif self.settings.focus_area_enabled.value:
                    title = 'Please select the directory that contains the recording, all ROI files, and a directory with focus area ROI(s):'
                else:
                    title = 'Please select the directory that contains the recording and all ROI files:'
            else:
                if self.settings.batch_mode.value:
                    title = 'Please select the parent directory that contains subdirectories with the individual source data:'
                    show_only_dirs = True
                elif self.settings.focus_area_enabled.value:
                    title = 'Please select the directory that contains the recording and a directory with focus area ROI(s):'
                    show_only_dirs = True
                else:
                    title = 'Please select the recording file:'
                    show_only_dirs = False
            reset = self.settings.data_source_path.show_only_dirs != show_only_dirs
            self._change_data_source_path_configs(show_only_dirs, title, reset)
           

    def _change_focus_area_config(self, change) -> None:
        if change['name'] == 'value':
            roi_mode = self.settings.roi_mode.value
            fake_change = {'name': 'value', 'new': roi_mode}
            self._change_roi_mode_config(fake_change)
           

    def _change_batch_mode_config(self, change) -> None:
        if change['name'] == 'value':
            roi_mode = self.settings.roi_mode.value
            fake_change = {'name': 'value', 'new': roi_mode}
            self._change_roi_mode_config(fake_change)

# %% ../nbs/01_view.ipynb 9
class AnalysisSettingsPanel:

    @dataclass
    class AnalysisSettings:
        grid_size: w.IntSlider = None
        signal_to_noise_ratio: w.BoundedFloatText = None
        noise_window_size: w.BoundedIntText = None
        mean_signal_threshold: w.BoundedFloatText = None
        min_peak_count: w.BoundedIntText = None
        baseline_estimation_method: w.Dropdown = None
        include_variance: w.Checkbox = None
        variance_window_size: w.BoundedIntText = None
        use_frame_range: w.Checkbox = None
        frame_interval_to_analyze: w.IntRangeSlider = None
        customize_octave_filtering: w.Checkbox = None
        min_octave_span: w.BoundedFloatText = None
        save_overview_png: w.Checkbox = None
        save_summary_results: w.Checkbox = None
        save_single_trace_results: w.Checkbox = None
        export_to_nwb: w.Checkbox = None

        def __iter__(self):
            for field in fields(self):
                yield getattr(self, field.name)

        @property
        def current_values(self) -> dict[str, Any]:
            return {
                'grid_size': self.grid_size.value,
                'signal_to_noise_ratio': self.signal_to_noise_ratio.value,
                'noise_window_size': self.noise_window_size.value,
                'mean_signal_threshold': self.mean_signal_threshold.value,
                'min_peak_count': self.min_peak_count.value,
                'baseline_estimation_method': self.baseline_estimation_method.value,
                'include_variance': self.include_variance.value,
                'variance_window_size': self.variance_window_size.value,
                'use_frame_range': self.use_frame_range.value,
                'start_frame_idx': self.frame_interval_to_analyze.value[0],
                'end_frame_idx': self.frame_interval_to_analyze.value[1],
                'customize_octave_filtering': self.customize_octave_filtering.value,
                'min_octave_span': self.min_octave_span.value,
                'save_overview_png': self.save_overview_png.value,
                'save_summary_results': self.save_summary_results.value,
                'save_single_trace_results': self.save_single_trace_results.value,
                'export_to_nwb': self.export_to_nwb.value
            }

    def __init__(self) -> None:
        self.settings = self.AnalysisSettings()
        self.vertical_spacer = w.HTML(value = '', layout = w.Layout(height = '5px'))
        self.run_analysis_button = w.Button(
            description='Run Analysis',
            disabled=True,
            tooltip='You have to load some data first, before you can run the analysis!',
            button_style='',
            icon='rocket',
            layout=w.Layout(width='90%')
        )
        self.preview_window_size_button = w.Button(
            description = 'Preview',
            disabled = True,
            tooltip = 'Preview grid size. Does not start analysis',
            layout = w.Layout(width = '20%')
        )

    @property
    def widget(self) -> w.VBox:
        width_percentage_core_widgets = '95%'
        description_width = '35px'

        # Create and configure all elements:
        analysis_settings_info = w.HTML(
            value="<p style='font-size:16px; font-weight:bold; text-align:center;'>Analysis Settings</p>",
            layout = w.Layout(width = '99%')
        )

        # Create widgets for user settings:
        self.settings.grid_size = w.IntSlider(
            description = 'Grid size:',
            value = 10,
            min = 1,
            max = 128,
            step = 1,
            disabled = True,
            layout = w.Layout(width = '80%'),
            style = {'description_width': 'initial'}
        )
        self.settings.signal_to_noise_ratio = w.BoundedFloatText(
            description = 'SNR: ',
            tooltip = 'Signal to noise ratio',
            value = 3.0,
            min = 0.1,
            max = 100.0,
            step = 0.05,
            disabled = True,
            layout = w.Layout(width = width_percentage_core_widgets),
            style = {'description_width': description_width}
        )
        self.settings.noise_window_size = w.BoundedIntText(
            description = 'NWS: ',
            tooltip = 'Noise window size',
            value = 200,
            min = 10,
            max = 1000,
            step = 1,
            disabled = True,
            layout = w.Layout(width = width_percentage_core_widgets),
            style = {'description_width': description_width}
        )
        self.settings.mean_signal_threshold = w.BoundedFloatText(
            description = 'SAT: ',
            tooltip = 'Signal average threshold',
            value = 10.0,
            min = 0.0,
            max = 255.0,
            step = 0.5,
            disabled = True,
            layout = w.Layout(width = width_percentage_core_widgets),
            style = {'description_width': description_width}
        )
        self.settings.min_peak_count = w.BoundedIntText(
            description = 'MAC: ',
            tooltip = 'Minimum activity counts',
            value = 2,
            min = 0,
            max = 100,
            step = 1,
            disabled = True,
            layout = w.Layout(width = width_percentage_core_widgets),
            style = {'description_width': description_width}
        )
        self.settings.baseline_estimation_method = w.Dropdown(
            description='Baseline estimation method: ',
            value='asls',
            options=[
                ("Asymmetric Least Squares", "asls"),
                ("Fully Automatic Baseline Correction", "fabc"),
                ("Peaked Signal's Asymmetric Least Squares Algorithm", "psalsa"),
                ("Standard Deviation Distribution", "std_distribution")
            ],
            disabled=True,
            layout=w.Layout(width='99%'),
            style={'description_width': 'initial'}
        )
        self.settings.include_variance = w.Checkbox(
            description = 'include variance',
            value = False,
            indent = False,
            disabled = True,
            layout = w.Layout(width = '35%'),
            style = {'description_width': 'initial'}
        )
        self.settings.variance_window_size = w.BoundedIntText(
            description='Variance:',
            disabled=True,
            value=15,
            min=5,
            max=200,
            step=5,
            style={'description_width': 'initial'},
            layout=w.Layout(width='65%', visibility='hidden')
        )
        self.settings.use_frame_range = w.Checkbox(
            description = 'analyze interval',
            indent = False,
            value = False,
            disabled = True,
            layout = w.Layout(width = '35%'),
            style = {'description_width': 'initial'}
        )
        self.settings.frame_interval_to_analyze = w.IntRangeSlider(
            description = 'Frames:',
            disabled = True,
            value = (0, 500),
            min = 0,
            max = 500,
            step = 1,
            style = {'description_width': 'initial'},
            layout = w.Layout(width = '65%', visibility = 'hidden')
        )
        self.settings.customize_octave_filtering = w.Checkbox(
            description = 'configure octaves',
            value = False,
            disabled = True,
            indent = False,
            layout = w.Layout(width = '35%'),
            style = {'description_width': 'initial'}
        )
        self.settings.min_octave_span = w.BoundedFloatText(
            description = 'Min. octaves:',
            tooltip = 'Minimum octaves a ridge needs to span',
            disabled = True,
            value = 1.0,
            min = 0.1,
            max = 30.0,
            step = 0.05,
            style = {'description_width': 'initial'},
            layout = w.Layout(width = '65%', visibility = 'hidden')
        )
        self.settings.save_overview_png = w.Checkbox(
            description = 'Save overview plot',
            value = True,
            disabled = True,
            style = {'description_width': 'initial'}
        )
        self.settings.save_summary_results = w.Checkbox(
            description = 'Save summary results',
            value = True,
            disabled = True,
            style = {'description_width': 'initial'}
        )
        self.settings.save_single_trace_results = w.Checkbox(
            description = 'Save single trace results',
            value = False,
            disabled = True,
            style = {'description_width': 'initial'}
        )
        self.settings.export_to_nwb = w.Checkbox(
            description = 'Export results to NWB',
            value = True,
            disabled = True,
            style = {'description_width': 'initial'}
        )

        # Enable event handling:
        self.settings.include_variance.observe(self._include_variance_config_changed)
        self.settings.use_frame_range.observe(self._limit_analysis_to_interval_changed)
        self.settings.customize_octave_filtering.observe(self._configure_octaves_changed)

        # Arrange elements:
        vbox_core_settings_left = w.VBox(
            [
                self.settings.signal_to_noise_ratio,
                self.vertical_spacer,
                self.settings.mean_signal_threshold
            ],
            layout = w.Layout(width = '50%', align_items = 'flex-start')
        )
        vbox_core_settings_right = w.VBox(
            [
                self.settings.noise_window_size,
                self.vertical_spacer,
                self.settings.min_peak_count
            ],
            layout = w.Layout(width = '50%', align_items = 'flex-end')
        )
        hbox_grid_window_size_settings = w.HBox(
            [
                self.settings.grid_size,
                self.preview_window_size_button
            ],
            layout = w.Layout(width = '100%', justify_content = 'flex-start')
        )
        hbox_core_setting_vboxes = w.HBox(
            [
                vbox_core_settings_left,
                vbox_core_settings_right
            ],
            layout = w.Layout(width = '100%')
        )
        vbox_all_core_settings = w.VBox(
            [
                hbox_grid_window_size_settings,
                self.vertical_spacer,
                hbox_core_setting_vboxes,
                self.vertical_spacer,
                self.settings.baseline_estimation_method
            ],
            layout = w.Layout(width = '90%')
        )
        dashed_separator_line = w.HTML(
            value = "<hr style='border: none; border-bottom: 1px dashed;'>",
            layout = w.Layout(width = '95%')
        )
        optional_info = w.Label(
            value = 'Optional Settings:',
            style = {'text_align': 'left', 'font_weight': 'bold'},
            layout = w.Layout(width = '90%')
        )
        optional_variance_widgets = w.HBox(
            [
                self.settings.include_variance,
                self.settings.variance_window_size
            ],
            layout = w.Layout(width = '100%', align_items = 'flex-start')
        )
        optional_interval_widgets = w.HBox(
            [
                self.settings.use_frame_range,
                self.settings.frame_interval_to_analyze
            ],
            layout = w.Layout(width = '100%', align_items = 'flex-start')
        )
        optional_octave_widgets = w.HBox(
            [
                self.settings.customize_octave_filtering,
                self.settings.min_octave_span
            ],
            layout = w.Layout(width = '100%', align_items = 'flex-start')
        )

        optional_settings = w.VBox(
            [
                optional_variance_widgets,
                self.vertical_spacer,
                optional_interval_widgets,
                self.vertical_spacer,
                optional_octave_widgets
            ],
            layout = w.Layout(width = '90%',
                              align_items = 'flex-start',
                              align_content = 'flex-start',
                              justify_content = 'flex-start')
        )
        results_info = w.Label(
            value = 'Results Settings:',
            style = {'text_align': 'left','font_weight': 'bold'},
            layout = w.Layout(width = '90%')
        )
        results_settings = w.VBox(
            [
                w.HBox(
                    [
                        self.settings.save_overview_png,
                        self.settings.save_summary_results
                    ], layout = w.Layout(width = '100%', align_items = 'flex-start')),
                w.HBox(
                    [
                        self.settings.save_single_trace_results,
                        self.settings.export_to_nwb
                    ], layout = w.Layout(width = '100%', align_items = 'flex-start'))
            ], layout = w.Layout(
                width = '90%',
                align_items = 'flex-start',
                align_content = 'flex-start',
                justify_content = 'center'
            )
        )

        run_analysis_box = w.VBox(
            [self.run_analysis_button],
            layout = w.Layout(width = '100%', align_items = 'center', justify_content = 'center', margin = '10px 0px 0px 0px')
        )
        analysis_settings_box = w.VBox([analysis_settings_info,
                                        vbox_all_core_settings,
                                        self.vertical_spacer,
                                        dashed_separator_line,
                                        optional_info,
                                        optional_settings,
                                        self.vertical_spacer,
                                        dashed_separator_line,
                                        results_info,
                                        results_settings,
                                        self.vertical_spacer,
                                        dashed_separator_line,
                                        run_analysis_box,
                                        self.vertical_spacer],
                                       layout = w.Layout(height = '612px', width = '33%', align_items = 'center', border_top = '1px solid', border_bottom = '1px solid'))
        analysis_settings_box.add_class('box-analysis-settings')
        return analysis_settings_box

    def enable_analysis_settings(self, enable_all_widgets: bool, roi_mode: str) -> None:
        if enable_all_widgets:
            change_widget_state(self.run_analysis_button,
                                disabled=False,
                                button_style='success',
                                tooltip='Click here to start the analysis with all currently specified settings!')
        else:
            change_widget_state(self.run_analysis_button,
                                disabled=True,
                                button_style='')
        for field in self.settings:
            field.disabled = not enable_all_widgets
        self.preview_window_size_button.disabled = not enable_all_widgets

        if roi_mode == 'file':
            self.preview_window_size_button.disabled = True
            self.settings.grid_size.disabled = True


    def _include_variance_config_changed(self, change) -> None:
        if change['name'] == 'value':
            if change['new']:
                self.settings.variance_window_size.layout.visibility = 'visible'
            else:
                self.settings.variance_window_size.layout.visibility = 'hidden'


    def _limit_analysis_to_interval_changed(self, change) -> None:
        if change['name'] == 'value':
            if change['new']:
                self.settings.frame_interval_to_analyze.layout.visibility = 'visible'
            else:
                self.settings.frame_interval_to_analyze.layout.visibility = 'hidden'


    def _configure_octaves_changed(self, change) -> None:
        if change['name'] == 'value':
            if change['new']:
                self.settings.min_octave_span.layout.visibility = 'visible'
            else:
                self.settings.min_octave_span.layout.visibility = 'hidden'

# %% ../nbs/01_view.ipynb 10
class MainScreen:

    def __init__(self) -> None:
        self.logo_path = 'https://raw.githubusercontent.com/jpits30/NeuronActivityTool/master/Logo.png'
        self.output = w.Output()
        self.widget = w.VBox(
            [],
            layout = w.Layout(
                height = '612px',
                width = '67%',
                justify_content = 'center',
                align_items = 'center',
                border_top = '1px solid',
                border_left = '1px solid',
                border_bottom = '1px solid'
            )
        )
        self.widget.add_class('box-main-screen')
        self.current_screen = None

    @property
    def welcome_screen(self) -> w.VBox:
        welcome = w.HTML(
            value="<p style='font-size:32px; font-weight:bold; text-align:center;'>Welcome to</p>",
            layout = w.Layout(width = '99%')
        )
        logo = w.HTML(
            value=f'<img src="{self.logo_path}" width="256" height="256">'
        )
        start_instructions = w.HTML(
            value="<p style='font-size:20px; font-weight:bold; text-align:center;'>Please start by selecting data of a recording to analyze</p>",
            layout = w.Layout(width = '99%')
        )
        return w.VBox([welcome, logo, start_instructions])

    @property
    def output_screen(self) -> w.VBox:
        return w.VBox([self.output])


    def show_welcome_screen(self) -> None:
        self.widget.children = self.welcome_screen.children
        self.current_screen = 'welcome'


    def show_output_screen(self, clear_output: bool = True) -> None:
        if clear_output:
            self.output.clear_output()
        self.widget.children = self.output_screen.children
        self.current_screen = 'output'

# %% ../nbs/01_view.ipynb 11
class WidgetsInterface:

    def __init__(self) -> None:
        self.user_info_panel = UserInfoPanel()
        self.source_data_panel = SourceDataPanel()
        self.analysis_settings_panel = AnalysisSettingsPanel()
        self.main_screen = MainScreen()
        self.nwb_metadata_panel = NWBMetadataPanel()
        self.widget = w.VBox(
            [
                self.source_data_panel.widget,
                w.HBox(
                    [
                        self.analysis_settings_panel.widget,
                        self.main_screen.widget
                    ]
                ),
                self.nwb_metadata_panel.widget,
                self.user_info_panel.widget,
            ],
            layout = w.Layout(align_items = 'stretch', border = '1px solid')
        )
        self.widget.add_class('box-na3-gui')
        self.main_screen.show_welcome_screen()
        self.source_data_panel.settings.batch_mode.observe(self._enable_window_size_widgets)
        self.source_data_panel.settings.focus_area_enabled.observe(self._enable_window_size_widgets)
        self.source_data_panel.settings.roi_mode.observe(self._enable_window_size_widgets)
        self.source_data_panel.settings.data_source_path.register_callback(self._data_source_path_chosen)

    def export_user_settings(self) -> Config:
        """
        Collects all settings from the source data panel and analysis settings panel
        and returns them as a Config object.
        """
        source_data_settings = self.source_data_panel.settings.current_values
        analysis_settings = self.analysis_settings_panel.settings.current_values
        combined_settings = source_data_settings | analysis_settings
        return Config(**combined_settings)

    def export_nwb_metadata(self) -> dict[str, Any]:
        return self.nwb_metadata_panel.metadata.current_metadata

    @property
    def grid_size(self) -> int:
        """
        Returns the grid size value from the analysis settings panel.
        """
        return self.analysis_settings_panel.settings.grid_size.value

    @property
    def data_source_path(self) -> str:
        """
        Returns the data source path from the source data panel.
        """
        return self.source_data_panel.settings.data_source_path.value


    def _data_source_path_chosen(self, file_chooser_obj = None) -> None:
        self.enable_analysis(False)
        if file_chooser_obj.value is not None:
            enable_loading = False
            source_data_path = Path(file_chooser_obj.value)
            if self.source_data_panel.settings.roi_mode.value == 'file':
                if source_data_path.is_dir():
                    enable_loading = True
            else:
                if (self.source_data_panel.settings.batch_mode.value
                        or self.source_data_panel.settings.focus_area_enabled.value):
                    if source_data_path.is_dir():
                        enable_loading = True
                else:
                    if source_data_path.is_file():
                        enable_loading = True
            if enable_loading:
                change_widget_state(self.source_data_panel.load_source_data_button,
                                    disabled = False,
                                    tooltip = 'Click to load the selected source data')
            else:
                change_widget_state(self.source_data_panel.load_source_data_button,
                                    disabled = True,
                                    tooltip = 'Please select which source data to load!')

    def _enable_window_size_widgets(self, change) -> None:
        self.enable_analysis(False)


    def update_infos(self, logs_message: str | None = None, progress_in_percent: float | None = None) -> None:
        if logs_message is not None:
            self.user_info_panel.add_new_logs(logs_message)
        if progress_in_percent is not None:
            self.user_info_panel.update_progress_bar(progress_in_percent)


    def adjust_widgets_to_loaded_data(self, total_frames: int) -> None:
        self.analysis_settings_panel.settings.frame_interval_to_analyze.max = total_frames + 1
        self.analysis_settings_panel.settings.frame_interval_to_analyze.value = (1, total_frames + 1)


    def enable_analysis(self, enable: bool = True) -> None:
        roi_mode = self.source_data_panel.settings.roi_mode.value
        self.analysis_settings_panel.enable_analysis_settings(enable, roi_mode)
