function varargout = commblkMultibandCombiner(blkH, action, varargin)
    % Mask initialization function for Multiband Combiner block

    %   Copyright 2021-2022 The MathWorks, Inc.

    if strcmp(action, 'Init')
        % Mask initialization

        blkName = getfullname(blkH);
        maskObj = Simulink.Mask.get(blkH);
        outputSampleRateComputed = maskObj.getDialogControl('OutputSampleRateComputed');
        delayComputed = maskObj.getDialogControl('DelayComputed');
        M = 1;

        [inputSampleRate, frequencyOffsets, rateOption, outputSampleRateOption, ...
            outputSampleRate] = deal(varargin{:});

        validateattributes(inputSampleRate, "double", ["finite", "real", "scalar", "positive"], ...
            "", "Input sample rate");
        validateattributes(frequencyOffsets, "double", ["finite", "vector", "real"], ...
            "", "Frequency offsets");

        if (outputSampleRateOption == 1)
            % Auto

            bwMax = max(abs(frequencyOffsets)) + (inputSampleRate/2);
            L = ceil( (2 * bwMax) / inputSampleRate ) ;
            outputSampleRate = L * inputSampleRate;

            % Update output sample rate display in mask
            outputSampleRateComputed.Prompt = sprintf('Output sample rate (Hz): %0.5g', outputSampleRate);
            outputSampleRateComputed.Visible = 'on';

        else
            % Specify via property

            validateattributes(outputSampleRate, "double", ["finite", "real", "scalar", "positive"], ...
                "", "Output sample rate");

            if (rateOption == 1)
                % Enforce single-rate processing
                L = outputSampleRate / inputSampleRate;
                if (L ~= floor(L))
                    error(message('comm:MultibandCombiner:invalidOutputSR'));
                end
            else
                % Allow multirate processing
                [L, M] = rat(outputSampleRate/inputSampleRate, 0);
            end
            outputSampleRateComputed.Visible = 'off';
        end

        % Update the underneath subsystem
        frcBlkName = 'FRC';
        % @todo update the usage of edit-time filter filterOutInactiveVariantSubsystemChoices()
        % instead use the post-compile filter activeVariants() - g2597271
        frcBlkCell = find_system(blkName,'LookUnderMasks','on','FollowLinks','on', ...
            'MatchFilter',@Simulink.match.internal.filterOutInactiveVariantSubsystemChoices,... % look only inside active choice of VSS
            'FirstResultOnly','on','Name',frcBlkName);

        if (L == M)
            % Upsampling not required

            if ~isempty(frcBlkCell)
                % Remove the FRC block
                csaBlkName = 'CSA'; % [blkName '/CSA'];
                frcBlkFullName = frcBlkCell{1};
                fscBlkName = 'FSC'; % [blkName '/FSC'];
                delete_line(blkName, [csaBlkName '/1'], [frcBlkName '/1']);
                delete_line(blkName, [frcBlkName '/1'], [fscBlkName '/1']);
                delete_block(frcBlkFullName);
                add_line(blkName, [csaBlkName '/1'], [fscBlkName '/1']);
            end
            delayComputed.Visible = 'off';

        else
            % Upsampling is required

            frcBlkFullName = [blkName '/' frcBlkName];
            if isempty(frcBlkCell)
                % Add the FRC block
                csaBlkName = 'CSA'; % [blkName '/CSA'];
                fscBlkName = 'FSC'; % [blkName '/FSC'];
                delete_line(blkName, [csaBlkName '/1'], [fscBlkName '/1']);

                csaPosition = get_param([blkName '/' csaBlkName], 'Position');
                fscPosition = get_param([blkName '/' fscBlkName], 'Position');
                w = round((fscPosition(1) - csaPosition(3))/3);
                x = csaPosition(3) + w;
                h = fscPosition(4) - fscPosition(2);
                y = fscPosition(2);
                frcPosition = [x y x+w y+h];
                add_block('dspmlti4/FIR Rate Conversion', frcBlkFullName, ...
                    'L', 'L', 'M', 'M', 'Position', frcPosition);
                add_line(blkName, [csaBlkName '/1'], [frcBlkName '/1']);
                add_line(blkName, [frcBlkName '/1'], [fscBlkName '/1']);
            end

            % Update delay display in mask
            num = designMultirateFIR(L, M);
            dly = round(length(num)/2/M);
            prompt = sprintf('Output delay (samples): %d', dly);
            if (rateOption == 2)
                % Allow multirate processing
                prompt = [prompt ' + Input length'];
            end
            delayComputed.Prompt = prompt;
            delayComputed.Visible = 'on';

            % Set rate options of underlying FRC block
            modes = {'Enforce single-rate processing', 'Allow multirate processing'};
            set_param(frcBlkFullName, 'rateMode', modes{rateOption});
        end

        varargout = {L, M};

    elseif strcmp(action, 'OutputSampleRateOption')
        % Mask parameter visibilities

        outputSampleRateOption = get_param(blkH,'OutputSampleRateOption');

        maskParamNames = get_param(blkH,'MaskNames');
        mask_vis_old   = get_param(blkH,'MaskVisibilities');
        mask_vis_new   = mask_vis_old;
        maskObj = Simulink.Mask.get(blkH);
        outputSampleRateComputed = maskObj.getDialogControl('OutputSampleRateComputed');

        onOff = {'on', 'off'};
        rateOptions = strcmpi(outputSampleRateOption, {'Auto', 'Specify via property'});
        outputSampleRateVis = onOff{~rateOptions};
        outputSampleRateComputed.Visible = onOff{rateOptions};

        mask_vis_new{strcmp(maskParamNames,'OutputSampleRate')} = outputSampleRateVis;
        if ~isequal(mask_vis_old,mask_vis_new)
            set_param(blkH, 'MaskVisibilities', mask_vis_new);
        end

        varargout = {};

    elseif strcmp(action, 'StartFcn')
        % StartFcn callback

        wsVar = get_param(blkH, 'MaskWSVariables');
        idx = strcmp({wsVar.Name}, 'InputSampleRate');
        inputSampleRate = wsVar(idx).Value;
        framePeriod = get_param(blkH, 'CompiledSampleTime');
        if iscell(framePeriod)
            % Multi-rate
            fp = framePeriod{2}(1);
        else
            % Single-rate
            fp = framePeriod(1);
        end
        dims = get_param(blkH, 'CompiledPortDimensions');
        actualInputSampleRate = dims.Inport(2) / fp;
        err = abs(actualInputSampleRate - inputSampleRate)/actualInputSampleRate;
        if (err > sqrt(eps))
            MSLDiagnostic(message('comm:shared:inputSampleRateMismatch', ...
                getfullname(blkH), inputSampleRate, actualInputSampleRate)).reportAsWarning();
        end

        varargout = {};
        
    elseif any(strcmp(action, {'comm:block:freqOffElemRwColWrongP', 'comm:block:freqOffElemSzWrongP'}))
        % Error from Phase/Frequency Offset block
        % action - error id
        % varargin{1} - MSLException
        
        % Return Multiband Combiner specific error
        varargout = {MSLException(message('comm:MultibandCombiner:inputSizeMisMatch'))};
        
    else        
        % Other error
        % varargin{1} - MSLException
        
        if ~isempty(varargin)
            varargout = varargin(1);
        else
            varargout = {};
        end
    end

end
