%

% Copyright 2017-2018 The MathWorks, Inc.
classdef ReadTable < handle
    properties (SetAccess = private)
        Sheets (1,:) cell;
        Ranges (1,:) string;
        ds (1,1) Simulink.SimulationData.Dataset;
        Model (1,1) string;
        M table; % metadata
        D table; % data
    end

    properties (SetAccess = immutable)
        Filename (1,1) string;
        Workbook (1,1) matlab.io.spreadsheet.internal.Workbook = ...
            matlab.io.spreadsheet.internal.Workbook('xlsx');
    end

    properties (Constant, Hidden)
        TextType = 'string';
        Boolean = 'boolean';
    end

    properties (Hidden)
        MaxMetadataRows (1,1) double = 12;
        UseExcel (1,1) logical = false;
        rangeID (1,1) int32 = 0;
    end

    methods
        function this = ReadTable(filename, varargin)
            import xls.internal.ReadTable;
            filename = string(filename);
            if nargin == 1
                % readtable default
                varargin = {'Sheets', 1};
            end

            [~,~,ext] = fileparts(filename);
            if strlength(ext) == 0
                filename = filename + xls.internal.WriteTable.DefaultExt;
                ext = xls.internal.WriteTable.DefaultExt;                
            end
            ext = ext{1}(2:end); % remove '.'

            sheetClasses = ["char", "string", "cell", "numeric"];
            p = inputParser;
            p.addRequired('filename', @exist);
            p.addParameter('Sheets','',@(x)validateattributes(x,sheetClasses,{'nonempty'}));
            p.addParameter('Ranges','',@(x)validateattributes(x,sheetClasses,{'nonempty'}));
            p.addParameter('Model','',@(x)validateattributes(x,["char", "string"],{'scalartext'}));
            p.parse(filename, varargin{:});
            if isnumeric(p.Results.Sheets)
                sheets = num2cell(p.Results.Sheets);
            else
                sheets = cellstr(p.Results.Sheets);
            end

            ranges = string(p.Results.Ranges);
            if numel(ranges) == 1 && ranges == ""
                % range is optional, set all to empty strings
                ranges = strings(size(sheets));
            end

            if iscellstr(sheets) && any(strlength(sheets) == 0)
                error(message('sl_xls:ReadTable:SheetsCannotBeEmpty'));
            elseif ~isequal(size(sheets), size(ranges))
                error(message('sl_xls:ReadTable:InvalidSheetRangeSizes'));
            end
            this.Filename = filename;
            this.Sheets = sheets;
            this.Ranges = ranges;
            this.Model = p.Results.Model;
            this.Workbook = matlab.io.spreadsheet.internal.createWorkbook( ...
                ext, ReadTable.resolveFilePath(this.Filename.char));
        end

        ds = readMetadata(this, sourceType, simIndex);
        paramArray = readParameters(this, simIndex);
        resetTable(this, keepDataset);
        range = getRange(this);
    end

    methods (Access = private)
        readMetadataHelper(this, idx);
        readDataHelper(this, sheetName, paramRange);
        readSignalData(this, range, sourceType, simIndex);
        addToDataset(this, source);
        addElement(this, data, name, element);
        dataRange = getUsedDataRange(this, sheet);
        addBusSignalsToDataset(this, T, element, timeCol);
        addNonBusSignalsToDataset(this, T, element, timeCol);
        tseries = createTimeSeries(this, T, signal, timeCol, busStruct);
        signalData = castSignalData(this, signalData, signal, busStruct);
        opts = getImportOptions(this, sheetName, sRange, usedRange);
        sheetName = getSheetFromIdx(this, idx);
    end

    methods (Static)
        filename = resolveFilePath(filename);
        scope = getScope(model);
        context = getContext(model);
    end

    methods (Static, Access = ?matlab.unittest.TestCase)
        data = removeTrailingNan(data);
        cellLoc = getMissingDataLoc(data, startRow, startCol);
        colVec = createFunctionCall(T, signal);
        tseries = fillDimensions(tseries, signalData, splitDims);
        metadataRange = getMetadataRange(maxMetadataRows, range);
        tseries = setUnit(signal, tseries);
        tseries = setInterpolation(signal, tseries);
        throwMissingDataError(signal, cellLoc);
    end
end
