function tc = createDefaultTC(modelH, inportCompInfos, forLogging)
%

%   Copyright 2009-2020 The MathWorks, Inc.

    if nargin < 3
        forLogging = false;
    end

    numInputsToTestUnit = length(inportCompInfos); % Number of inports

    if forLogging
        tc = struct(...
            'timeValues', 0,...
            'dataValues', Simulink.SimulationData.Dataset,...
            'paramValues',[]);
    else
        dataValues = [];
        dataNoEffect = [];
        for idx = 1:numInputsToTestUnit
            [dataValues{end+1},dataNoEffect{end+1}] = createInportTCData(...
                modelH, inportCompInfos(idx)); %#ok<AGROW>
        end

        tc = struct(...
            'timeValues', 0,...
            'dataValues', '',...
            'paramValues',[],...
            'stepValues',[],...
            'objectives',[],...
            'dataNoEffect', ''...
            );

        tc.dataValues = dataValues(:);
        tc.dataNoEffect = dataNoEffect(:);
    end
end

function [Data, DataNoEffect] = createInportTCData(modelH, flatInportInfo)

    compInfo = flatInportInfo.compiledInfo; % Leaf-level signals
    sizedData = cell(size(compInfo));
    sizedNoEffect = cell(size(compInfo));

    signalDimList = cell(size(compInfo));
    if flatInportInfo.IsStructBus
        dataAccessor = Simulink.data.DataAccessor.create(get_param(modelH, 'name'));

        busPath = compInfo(1).BusObjPath;
        buses = sldvshareprivate('util_get_signal_parts', busPath);
        busObj = sl('slbus_get_object_from_name_withDataAccessor', buses{1}, true, dataAccessor);

        isBus = true;

        [signalDimList, signalId, tempSignalIdHierList] = getDimsForReshaping(busObj, signalDimList, 1, flatInportInfo.Dimensions, compInfo, dataAccessor);
        signalIdHierList = {1, signalId-1, tempSignalIdHierList};
    else
        isBus = false;
        for i=1:length(compInfo)
            signalDimList{i} = compInfo(i).Dimensions;
        end
    end

    for i=1:length(compInfo)
        [d, d_noeff]= prepare_default_testdata_forinport(compInfo(i), signalDimList{i}, isBus, modelH);
        sizedData{i} = d;
        sizedNoEffect{i} = d_noeff;
    end

    if flatInportInfo.IsStructBus
        if all(flatInportInfo.Dimensions == 1)
            for sigId = signalIdHierList{1}:signalIdHierList{2}   % g1586067, g1696243
                signalDimList{sigId} = signalDimList{sigId}(1:end-length(flatInportInfo.Dimensions));
            end
            Data = createBusCell(busObj, sizedData, signalDimList, signalIdHierList, 1, dataAccessor, compInfo);
            DataNoEffect = createBusCell(busObj, sizedNoEffect, signalDimList, signalIdHierList, 1, dataAccessor, compInfo);
        else
            Data = createBusArrayCell(busObj, sizedData, signalDimList, flatInportInfo.Dimensions, signalIdHierList, 1, dataAccessor, compInfo);
            DataNoEffect = createBusArrayCell(busObj, sizedNoEffect, signalDimList, flatInportInfo.Dimensions, signalIdHierList, 1, dataAccessor, compInfo);
        end


        % Clear cached bus data
        Sldv.utils.getBusObjectFromName(-1);
    else
        Data = sizedData{1}; % data should be a cell with 1 element
        DataNoEffect = sizedNoEffect{1};
    end
end

function [signalDimList, signalId, signalIdHierList] = getDimsForReshaping(busObj, signalDimList, signalId, parentDimList, compiledInfo, dataAccessor)
    signalIdHierList = cell(size(busObj.Elements));

    for i=1:length(busObj.Elements)
        [isBus, subBusObj] = Sldv.utils.isBusType(busObj.Elements(i).DataType, dataAccessor);
        if isBus
            busElemDims = busObj.Elements(i).Dimensions;
            if iscolumn(busElemDims)
                busElemDims = busElemDims'; % See comments in code against g1700670 in sldv/sldv/private/createTestcaseData.m
            end
            myDimList = [busElemDims parentDimList];

            startId = signalId;
            [signalDimList, signalId, childSignalIdHierList] = getDimsForReshaping(subBusObj, signalDimList, signalId, myDimList, compiledInfo, dataAccessor);
            endId = signalId-1;
            signalIdHierList{i} = {startId, endId, childSignalIdHierList};
        else
            elemDims = compiledInfo(signalId).Dimensions;
            if iscolumn(elemDims)
                elemDims = elemDims'; % See comments in code against g1700670 in sldv/sldv/private/createTestcaseData.m
            end
            myDimList = [elemDims parentDimList];
            signalDimList{signalId} = myDimList;
            signalIdHierList{i} = {signalId, signalId, {}};
            signalId = signalId+1;
        end
    end
end

function [Data, DataNoEffect] = prepare_default_testdata_forinport(compiledInfo, signalDimension, isBus, modelH)
    signalDataTypeStr = compiledInfo.DataType;
    data = zeros(prod(signalDimension), 1);
    data_noeff = zeros(prod(signalDimension), 1); %Assume the data always has an effect

    if ~isBus
        [~, testDataNumberTimeSteps] = size(data);
        untypedData = Sldv.DataUtils.reshapeData(testDataNumberTimeSteps, signalDimension, data);
        DataNoEffect = Sldv.DataUtils.reshapeData(testDataNumberTimeSteps, signalDimension, data_noeff);
    else
        untypedData = data;
        DataNoEffect = data_noeff;
    end

    if sldvshareprivate('util_is_simulink_builtin', signalDataTypeStr)
        if strcmp(signalDataTypeStr, 'boolean') || strcmp(signalDataTypeStr, 'bool')
            Data = cast(untypedData, 'logical');
        else
            Data = cast(untypedData, signalDataTypeStr);
        end
    else
        %Get the default value for enum, not necessarily 0
        [isEnum, className] = sldvshareprivate('util_is_enum_type', signalDataTypeStr);
        if(isEnum)
            Data = sldvshareprivate('util_get_enum_defaultvalue', className);
            % Shape the data to the correct array type
            Data = Data(ones(size(untypedData)));
        else
            [isfxptype, fxpTypeInfo] = sldvshareprivate('util_is_fxp_type', signalDataTypeStr, modelH);
            if isfxptype && ~isempty(fxpTypeInfo)
                Data = fi(untypedData, fxpTypeInfo);
                for k=1:prod(size(Data)) %#ok<PSIZE>
                    a = Data(k);
                    a.int = untypedData(k);
                    Data(k) = a;
                end
            else
                error(message('Sldv:MdlPrepareTestdataForInport:UnrecognizedTypeForTestCase', signalDataTypeStr));
            end
        end
    end
end

function [out, id] = createBusArrayCell(busObj, data, signalDimList, myDim, signalIdHierList, signalId, dataAccessor, compiledInfo)
    if isscalar(myDim)
        out = cell(myDim, 1);
    else
        out = cell(myDim);
    end
    myDimLen = length(myDim);

    allDims = util_gen_all_combinations(myDim);
    for index = 1:numel(allDims)
        dim = allDims{index};

        slicedData = cell(size(data));
        slicedSignalDimList = cell(size(signalDimList));
        for sigId = signalIdHierList{1}:signalIdHierList{2}
            remainingDim = prod(signalDimList{sigId})/prod(myDim);
            [~, numTimeSteps] = size(data{sigId});

            temp_data = Sldv.DataUtils.reshapeData(numTimeSteps, [remainingDim myDim], data{sigId});
            indices = repmat({':'}, 1, ndims(temp_data));
            for i = 1:length(dim)
                indices{i+1} = dim(i);
            end
            slicedData{sigId} = temp_data(indices{:});

            slicedSignalDimList{sigId} = signalDimList{sigId}(1:end-myDimLen);
        end

        [elem, id] = createBusCell(busObj, slicedData, slicedSignalDimList, signalIdHierList, signalId, dataAccessor, compiledInfo);

        cell_dim = num2cell(dim);
        out{cell_dim{:}} = elem;
    end
end

function [out, id] = createBusCell(busObj, data, signalDimList, signalIdHierList, dataId, dataAccessor, compiledInfo)
    out = cell(size(busObj.Elements));
    id = dataId;
    for i=1:length(busObj.Elements)
        [elem, id] = createBusElementCell(busObj.Elements(i), data, signalDimList, signalIdHierList{3}{i}, id, dataAccessor, compiledInfo);
        out{i} = elem;
    end
end

function [elem, id] = createBusElementCell(busElem, data, signalDimList, signalIdHierList, dataId, dataAccessor, compiledInfo)
    [isbus, busObj] = Sldv.utils.isBusType(busElem.DataType, dataAccessor);
    if isbus
        if all(busElem.Dimensions == 1)
            for sigId = signalIdHierList{1}:signalIdHierList{2}   % g1586067, g1696243
                signalDimList{sigId} = signalDimList{sigId}(1:end-length(busElem.Dimensions));
            end
            [elem, id] = createBusCell(busObj, data, signalDimList, signalIdHierList, dataId, dataAccessor, compiledInfo);
        else
            [elem, id] = createBusArrayCell(busObj, data, signalDimList, busElem.Dimensions, signalIdHierList, dataId, dataAccessor, compiledInfo);
        end
    else
        signalDimension = compiledInfo(dataId).Dimensions;
        if iscolumn(signalDimension)
            signalDimension = signalDimension'; % See comments in code against g1700670 in sldv/sldv/private/createTestcaseData.m
        end
        [~, testDataNumberTimeSteps] = size(data{dataId});
        elem = reshape(data{dataId}, [signalDimension testDataNumberTimeSteps]);
        id = dataId+1;
    end
end

function allCombinations = util_gen_all_combinations(maxDims)
    allCombinations = getAllDimCombinations({}, maxDims, zeros(size(maxDims)), length(maxDims));
end

function allDimCombinations = getAllDimCombinations(allDimCombinations, maxDims, currentDims, i)
    if i >= 1
        for k = 1:maxDims(i)
            currentDims(i) = k;
            allDimCombinations = getAllDimCombinations(allDimCombinations, maxDims, currentDims, i-1);
        end
    else
        allDimCombinations{end+1} = currentDims;
    end
end
