%

% Copyright 2018-2020 The MathWorks, Inc.
function paramArray = readParameters(this, simIndex)
    arguments
        this;
        simIndex (1,1) int32 = 0;
    end

    paramArray = Simulink.Simulation.Variable.empty;
    this.resetTable;
    % Do not loop through all sheets for parameters. We only do this for
    % simulation data to be backwards compatible with 17a.
    idx = 1;
    this.readMetadataHelper(idx);
    range = this.getRange;
    if isempty(range)
        return;
    end
    simulation = range.getSimulations(simIndex);
    if isempty(simulation)
        return;
    end

    paramRange = simulation.getParametersRange;
    
    if ~isempty(paramRange)
        opts = getOpts(paramRange, this.getSheetFromIdx(idx), range.DataStartRow);
        this.D = readtable(this.Filename, opts, 'UseExcel', this.UseExcel);
        stringMatrix = getParameterStringMatrix(this.D);
        paramArray = stringMatrixToParamArray(stringMatrix);
    end
end

function stringMatrix = getParameterStringMatrix(paramTable)
    paramTable = xls.internal.ReadTable.removeTrailingNan(paramTable);
    stringMatrix = tableToStringMatrix(paramTable);
end

function T = tableToStringMatrix(T)
    T = string(T{:,:});
    T = fillmissing(T, 'constant', "");
end

function paramArray = stringMatrixToParamArray(M)
    import xls.internal.ParametersRange;

    names = M(:, ParametersRange.NameCol);
    values = M(:, ParametersRange.ValueCol);
    masks = getMaskBlockPaths(M);
    paramArray = prealloc(numel(names));
    for x = 1:size(paramArray, 1)
        paramArray(x) = createVariable(names(x), values(x), masks(x));
    end
end

function masks = getMaskBlockPaths(T)
    import xls.internal.ParametersRange;
    if size(T, 2) < ParametersRange.MaskCol
        masks = strings(size(T, 1), 1);
    else
        masks = T(:, ParametersRange.MaskCol);
    end
end

function paramArray = prealloc(num)
    % preallocate is faster than arrayfun
    dummyData = {'a', 1, 'workspace', ''};
    paramArray(1:num) = Simulink.Simulation.Variable(dummyData{:});
    paramArray = paramArray';
end

function variable = createVariable(name, value, mask)
    variable = Simulink.Simulation.Variable( ...
        name.char, value, 'Workspace', mask.char);
end

function opts = getOpts(paramRange, sheet, dataStartRow)
    import xls.internal.colNumberToLetter;
    num = paramRange.StopCol - paramRange.StartCol + 1;
    vars(1:num) = matlab.io.TextVariableImportOptions('type', 'string');
    opts = spreadsheetImportOptions('Sheet', sheet, ...
        'VariableOptions', vars, ...
        'DataRange', string(colNumberToLetter(paramRange.StartCol)) + dataStartRow);
end
