classdef auswertungs_app < matlab.apps.AppBase

    % Properties that correspond to app components
    properties (Access = public)
        UIFigure                matlab.ui.Figure
        UITable                 matlab.ui.control.Table
        QueryButton             matlab.ui.control.Button
        EqualizerListBox        matlab.ui.control.ListBox
        EqualizerListBoxLabel   matlab.ui.control.Label
        BitrateListBox          matlab.ui.control.ListBox
        BitrateListBox_2Label   matlab.ui.control.Label
        FormatListBox           matlab.ui.control.ListBox
        FormatListBox_2Label    matlab.ui.control.Label
        FiberLenListBox         matlab.ui.control.ListBox
        FiberLenListBox_2Label  matlab.ui.control.Label
        WavelengthListBox       matlab.ui.control.ListBox
        WavelengthListBoxLabel  matlab.ui.control.Label
        CodingListBox           matlab.ui.control.ListBox
        CodingListBoxLabel      matlab.ui.control.Label
        DatabaseDropDown        matlab.ui.control.DropDown
        DatabaseDropDownLabel   matlab.ui.control.Label
        ConnectDBButton         matlab.ui.control.Button
        basePathEditField       matlab.ui.control.EditField
        basePathEditFieldLabel  matlab.ui.control.Label
    end


    properties (Access = private)
        db % db class var
        % Define properties to store the colors

        rawDataTable
        avgDataTable    

        lblue    % Light blue
        dblue    % Dark blue
        lgreen   % Light green
        dgreen   % Dark green
        lred     % Light red
        dred     % Dark red
        lorange  % Light yellow
        dorange  % Dark yellow
        lpurple  % Light purple
        dpurple  % Dark purple
        lyellow  % Light orange
        dbrown  % Dark orange
    end

    methods (Access = private)

        % Store 12 colors in the app with descriptive names
        function LoadColors(app)
            % Get 12 colors from cbrewer2
            cols = cbrewer2('Paired', 12);

            % Assign descriptive names to each color
            app.lblue = cols(1, :);   % Light blue
            app.dblue = cols(2, :);   % Dark blue
            app.lgreen = cols(3, :);  % Light green
            app.dgreen = cols(4, :);  % Dark green
            app.lred = cols(5, :);    % Light red
            app.dred = cols(6, :);    % Dark red
            app.lorange = cols(7, :); % Light yellow
            app.dorange = cols(8, :); % Dark yellow
            app.lpurple = cols(9, :); % Light purple
            app.dpurple = cols(10, :); % Dark purple
            app.lyellow = cols(11, :); % Light orange
            app.dbrown = cols(12, :); % Dark orange
        end

        function refreshListBoxes(app)
            % Fetch and sort unique PAM level values, then populate PAMLevelListBox
            pamLevels = sort(app.db.distinctValues.Configurations.pam_level);
            app.FormatListBox.Items = cellstr(num2str(pamLevels));


            % Fetch and sort unique dB mode values, then populate DBModeListBox
            dbModes = sort(app.db.distinctValues.Configurations.db_mode);
            app.CodingListBox.Items = cellstr(db_mode(dbModes));


            % Fetch and sort unique fiber length values, then populate FiberLenListBox
            fiberLengths = sort(app.db.distinctValues.Configurations.fiber_length);
            app.FiberLenListBox.Items = cellstr(num2str(fiberLengths));


            % Fetch and sort unique bitrate values, then populate BitrateListBox
            bitrates = sort(app.db.distinctValues.Configurations.bitrate);
            app.BitrateListBox.Items = cellstr(num2str(bitrates));


            % Fetch and sort unique wavelength values, then populate WavelengthListBox
            wavelengths = sort(app.db.distinctValues.Configurations.wavelength);
            app.WavelengthListBox.Items = cellstr(num2str(wavelengths));

            % Fetch and sort unique EQ values, then populate WavelengthListBox
            equalizer = sort(app.db.distinctValues.Equalizer.eq_type);
            app.EqualizerListBox.Items = cellstr(equalizer_structure(equalizer));


        end


        function [success] = generateQuery(app)
            
            success = 0;

            % Create filterParams struct with default values
            filterParams = app.db.tables;
            filterParams.Configurations = struct( ...
                'bitrate',          [], ...
                'db_mode',          [], ...
                'fiber_length',     [], ...
                'interference_attenuation', [], ...
                'interference_path_length', [], ...
                'is_mpi',           [], ...
                'pam_level',        [], ...
                'precomp_amp',      [], ...
                'rop_attenuation',  [], ...
                'symbolrate',       [], ...
                'v_awg',            [], ...
                'v_bias',           [], ...
                'wavelength',       [] ...
                );

            % Fill in filterParams with user choices from respective listboxes
            if ~isempty(app.FormatListBox.Value)
                filterParams.Configurations.pam_level = str2double(app.FormatListBox.Value);
            end

            if ~isempty(app.CodingListBox.Value)
                filterParams.Configurations.db_mode = double(db_mode(app.CodingListBox.Value));
            end

            if ~isempty(app.FiberLenListBox.Value)
                filterParams.Configurations.fiber_length = str2double(app.FiberLenListBox.Value);
            end

            if ~isempty(app.BitrateListBox.Value)
                filterParams.Configurations.bitrate = str2double(app.BitrateListBox.Value);
            end

            if ~isempty(app.WavelengthListBox.Value)
                filterParams.Configurations.wavelength = str2double(app.WavelengthListBox.Value);
            end

            if ~isempty(app.WavelengthListBox.Value)
                filterParams.Equalizer.eq_type = equalizer_structure(app.EqualizerListBox.Value);
            end

            % Define the fields to be selected in the query
            selectedFields = {'Runs.run_id', 'BERs.ber_id', 'Equalizer.eq_id', 'Equalizer.eq_type', 'BERs.ber', ...
                'BERs.occurrence', 'Configurations.db_mode', 'Configurations.pam_level', ...
                'Configurations.bitrate', 'Configurations.symbolrate', 'Configurations.fiber_length', ...
                'Configurations.wavelength', 'Configurations.precomp_amp', ...
                'Measurements.power_rop', 'Measurements.power_laser', 'Measurements.power_pd_in'};
            
            try

            % Use the query method to get the data table
            [app.rawDataTable, ~] = app.db.queryDB(filterParams, selectedFields);

            catch e
                warning('Failed to get config:%s %s ',filterParams, e.message);
            end

            if isempty(app.rawDataTable)
                success = 2;
            else
                success = 1;
            end

        end

        function buildAvgTable(app)

            % Calculate the mean BER for each combination of 'run_id' and 'eq_type'
            groupedData = groupsummary(app.rawDataTable, {'run_id', 'eq_type'}, 'mean', {'ber', 'power_rop','power_pd_in'});

            % Extract unique rows from dataTable for each run_id with relevant configuration details
            uniqueConfigFields = {'run_id', 'pam_level', 'bitrate','symbolrate', 'fiber_length', 'wavelength', 'precomp_amp', 'db_mode'};
            [~, uniqueIdx] = unique(app.rawDataTable.run_id);  % Get unique run_id indices
            configDetails = app.rawDataTable(uniqueIdx, uniqueConfigFields);  % Extract unique configurations for each run_id

            % Prepare the join key for both groupedData and configDetails
            groupedDataTable = table(groupedData.run_id, groupedData.eq_type, groupedData.GroupCount, groupedData.mean_ber,groupedData.mean_power_rop,groupedData.mean_power_pd_in, ...
                'VariableNames', {'run_id', 'eq_type', 'GroupCount', 'mean_ber','mean_power_rop','mean_power_pd_in'});

            % Join groupedData with configDetails on the run_id field
            app.avgDataTable = join(groupedDataTable, configDetails, 'Keys', 'run_id');

        end

        function fillUITable(app)

            % Check if dataTable is empty
            if isempty(app.avgDataTable)
                warning('Data table is empty, no data to populate in UITable.');
                app.UITable.Data = {}; % Set UITable to empty
            else
                % Convert the data table to a format that can be displayed in UITable
                % UITable in App Designer can display cell arrays or tables
                app.UITable.Data = app.avgDataTable;

                % Update column names in UITable for better user understanding
                app.UITable.ColumnName = app.avgDataTable.Properties.VariableNames;
            end

        end
        

    end


    % Callbacks that handle component events
    methods (Access = private)

        % Code that executes after component creation
        function startupFcn(app)
            app.LoadColors();
        end

        % Drop down opening function: DatabaseDropDown
        function DatabaseDropDownOpening(app, event)
            % Get the base path from the edit field
            folderPath = char(app.basePathEditField.Value);

            % Validate that the folder exists
            if isfolder(folderPath)
                % Get all .db files in the folder
                dbFiles = dir(fullfile(folderPath, '*.db'));

                % Extract filenames from the structure array
                filenames = {dbFiles.name};

                % Update the dropdown with the filenames
                if ~isempty(filenames)
                    app.DatabaseDropDown.Items = filenames;
                else
                    % If no files are found, set a default message
                    app.DatabaseDropDown.Items = {'No .db files found'};
                end
            else
                % If folder doesn't exist, set an error message in the dropdown
                app.DatabaseDropDown.Items = {'Invalid folder path'};
            end
        end

        % Button pushed function: ConnectDBButton
        function ConnectDBButtonPushed(app, event)
            try
                % Attempt to create the database handler
                app.db = DBHandler("pathToDB", [app.basePathEditField.Value, filesep, app.DatabaseDropDown.Value]);

                % If successful, set button color to green
                app.ConnectDBButton.BackgroundColor = app.dgreen;  % RGB for green

                app.refreshListBoxes();

            catch ME
                % If an error occurs, set button color to red
                app.ConnectDBButton.BackgroundColor = app.dred;  % RGB for red

                % Display or log error message (optional)
                disp(['Failed to connect to database: ', ME.message]);
            end
        end

        % Button pushed function: QueryButton
        function QueryButtonPushed(app, event)
            
            success = app.generateQuery();

            if success == 0
                app.QueryButton.BackgroundColor = app.dred;  % RGB for red

            elseif success == 2
                app.QueryButton.BackgroundColor = app.lorange;  % RGB for red

            elseif success == 1
                app.buildAvgTable();

                app.fillUITable();
                app.QueryButton.BackgroundColor = app.dgreen;  % RGB for red
            end


            
        end
    end

    % Component initialization
    methods (Access = private)

        % Create UIFigure and components
        function createComponents(app)

            % Create UIFigure and hide until all components are created
            app.UIFigure = uifigure('Visible', 'off');
            app.UIFigure.Color = [1 1 1];
            app.UIFigure.Position = [100 100 850 698];
            app.UIFigure.Name = 'MATLAB App';

            % Create basePathEditFieldLabel
            app.basePathEditFieldLabel = uilabel(app.UIFigure);
            app.basePathEditFieldLabel.HorizontalAlignment = 'right';
            app.basePathEditFieldLabel.Position = [10 14 56 22];
            app.basePathEditFieldLabel.Text = 'basePath';

            % Create basePathEditField
            app.basePathEditField = uieditfield(app.UIFigure, 'text');
            app.basePathEditField.Position = [81 14 390 22];
            app.basePathEditField.Value = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\';

            % Create ConnectDBButton
            app.ConnectDBButton = uibutton(app.UIFigure, 'push');
            app.ConnectDBButton.ButtonPushedFcn = createCallbackFcn(app, @ConnectDBButtonPushed, true);
            app.ConnectDBButton.Position = [734 14 100 22];
            app.ConnectDBButton.Text = 'Connect DB';

            % Create DatabaseDropDownLabel
            app.DatabaseDropDownLabel = uilabel(app.UIFigure);
            app.DatabaseDropDownLabel.HorizontalAlignment = 'right';
            app.DatabaseDropDownLabel.Position = [510 14 56 22];
            app.DatabaseDropDownLabel.Text = 'Database';

            % Create DatabaseDropDown
            app.DatabaseDropDown = uidropdown(app.UIFigure);
            app.DatabaseDropDown.Items = {};
            app.DatabaseDropDown.DropDownOpeningFcn = createCallbackFcn(app, @DatabaseDropDownOpening, true);
            app.DatabaseDropDown.Position = [581 14 138 22];
            app.DatabaseDropDown.Value = {};

            % Create CodingListBoxLabel
            app.CodingListBoxLabel = uilabel(app.UIFigure);
            app.CodingListBoxLabel.HorizontalAlignment = 'right';
            app.CodingListBoxLabel.Position = [36 534 43 22];
            app.CodingListBoxLabel.Text = 'Coding';

            % Create CodingListBox
            app.CodingListBox = uilistbox(app.UIFigure);
            app.CodingListBox.Items = {};
            app.CodingListBox.Position = [23 454 99 71];
            app.CodingListBox.Value = {};

            % Create WavelengthListBoxLabel
            app.WavelengthListBoxLabel = uilabel(app.UIFigure);
            app.WavelengthListBoxLabel.HorizontalAlignment = 'right';
            app.WavelengthListBoxLabel.Position = [351 651 68 22];
            app.WavelengthListBoxLabel.Text = 'Wavelength';

            % Create WavelengthListBox
            app.WavelengthListBox = uilistbox(app.UIFigure);
            app.WavelengthListBox.Items = {};
            app.WavelengthListBox.Position = [355 289 59 361];
            app.WavelengthListBox.Value = {};

            % Create FiberLenListBox_2Label
            app.FiberLenListBox_2Label = uilabel(app.UIFigure);
            app.FiberLenListBox_2Label.HorizontalAlignment = 'right';
            app.FiberLenListBox_2Label.Position = [160 651 56 22];
            app.FiberLenListBox_2Label.Text = 'Fiber Len';

            % Create FiberLenListBox
            app.FiberLenListBox = uilistbox(app.UIFigure);
            app.FiberLenListBox.Items = {};
            app.FiberLenListBox.Position = [165 289 45 360];
            app.FiberLenListBox.Value = {};

            % Create FormatListBox_2Label
            app.FormatListBox_2Label = uilabel(app.UIFigure);
            app.FormatListBox_2Label.HorizontalAlignment = 'right';
            app.FormatListBox_2Label.Position = [25 651 43 22];
            app.FormatListBox_2Label.Text = 'Format';

            % Create FormatListBox
            app.FormatListBox = uilistbox(app.UIFigure);
            app.FormatListBox.Items = {};
            app.FormatListBox.Position = [23 578 57 71];
            app.FormatListBox.Value = {};

            % Create BitrateListBox_2Label
            app.BitrateListBox_2Label = uilabel(app.UIFigure);
            app.BitrateListBox_2Label.HorizontalAlignment = 'right';
            app.BitrateListBox_2Label.Position = [263 654 40 22];
            app.BitrateListBox_2Label.Text = 'Bitrate';

            % Create BitrateListBox
            app.BitrateListBox = uilistbox(app.UIFigure);
            app.BitrateListBox.Items = {};
            app.BitrateListBox.Position = [239 289 89 361];
            app.BitrateListBox.Value = {};

            % Create EqualizerListBoxLabel
            app.EqualizerListBoxLabel = uilabel(app.UIFigure);
            app.EqualizerListBoxLabel.HorizontalAlignment = 'right';
            app.EqualizerListBoxLabel.Position = [448 651 55 22];
            app.EqualizerListBoxLabel.Text = 'Equalizer';

            % Create EqualizerListBox
            app.EqualizerListBox = uilistbox(app.UIFigure);
            app.EqualizerListBox.Items = {};
            app.EqualizerListBox.Position = [453 555 95 94];
            app.EqualizerListBox.Value = {};

            % Create QueryButton
            app.QueryButton = uibutton(app.UIFigure, 'push');
            app.QueryButton.ButtonPushedFcn = createCallbackFcn(app, @QueryButtonPushed, true);
            app.QueryButton.Position = [619 630 100 22];
            app.QueryButton.Text = 'Query';

            % Create UITable
            app.UITable = uitable(app.UIFigure);
            app.UITable.ColumnName = '';
            app.UITable.RowName = {};
            app.UITable.Position = [23 69 799 185];

            % Show the figure after all components are created
            app.UIFigure.Visible = 'on';
        end
    end

    % App creation and deletion
    methods (Access = public)

        % Construct app
        function app = auswertungs_app

            % Create UIFigure and components
            createComponents(app)

            % Register the app with App Designer
            registerApp(app, app.UIFigure)

            % Execute the startup function
            runStartupFcn(app, @startupFcn)

            if nargout == 0
                clear app
            end
        end

        % Code that executes before app deletion
        function delete(app)

            % Delete UIFigure when app is deleted
            delete(app.UIFigure)
        end
    end
end