function [sldvDataRandomized, warnmsg] = randomize(sldvData, randSeed, modelH)
    % Randomly assign data values that don't affect objectives
    % to arbitrary values within the range of permissible values of
    % their data type.

%   Copyright 2008-2017 The MathWorks, Inc.

    warnmsg = '';

    if ~isfield(sldvData, 'Version') || Sldv.DataUtils.dataVersionLessThan(sldvData, '1.3')
        errstr = getString(message('Sldv:shared:DataUtils:SldvDataOldFormat'));
        error('Sldv:shared:DataUtils:SldvDataOldFormat', errstr);
    end

    sldvDataRandomized = sldvData;

    if Sldv.DataUtils.modelHasFixedPntInput(sldvData, modelH) && exist('fi', 'file') ~= 2
        warnmsg = getString(message('Sldv:shared:DataUtils:RandomizationNotDone'));
        return;
    end

    SimData = Sldv.DataUtils.getSimData(sldvData);
    if isempty(SimData)
        return;
    end

    % Cache the default random number stream and then create a new one with
    % initial state based on the number of model objects and objectives
    savedDflt = RandStream.setGlobalStream(RandStream('mt19937ar', 'seed', randSeed));

    inportInfo = sldvDataRandomized.AnalysisInformation.InputPortInfo;

	for tstIdx = 1:length(SimData)   % Loop over each port
		dataValues = SimData(tstIdx).dataValues;
		dataNoEffect = SimData(tstIdx).dataNoEffect;
        numTimeSteps = length(SimData(tstIdx).timeValues);

        if isempty(dataValues)
            continue;
        end

        simData = SimData(tstIdx);
        for portIdx = 1:length(dataValues)
            isPortBusArray = false;
            if iscell(inportInfo{portIdx}) && isfield(inportInfo{portIdx}{1}, 'Dimensions') && ...
               any(inportInfo{portIdx}{1}.Dimensions ~= 1)
                isPortBusArray = true;
            end

            computeInput = genRandomizedData(dataValues{portIdx}, ...
                                             dataNoEffect{portIdx}, ...
                                             inportInfo{portIdx}, ...
                                             numTimeSteps, ...
                                             isPortBusArray);

            simData.dataValues{portIdx} = computeInput;
        end
        sldvDataRandomized = Sldv.DataUtils.setSimData(sldvDataRandomized, tstIdx, simData);
	end

    % Restore the default random number stream
    RandStream.setGlobalStream(savedDflt);
end

function computeInput = genRandomizedData(inportTestData, inportNoEffectData, ...
                                          inportInfo, numTimeSteps, isBusArray)
    if ~iscell(inportTestData)
        % inportTestData corresponds to a non-bus / non-bus-array signal
        dimensions = inportInfo.Dimensions;

        computeInput = inportTestData;
        noEffect = Sldv.DataUtils.flattenData(numTimeSteps, dimensions, inportNoEffectData);
        if any(any(noEffect))
            computeInput = Sldv.DataUtils.flattenData(numTimeSteps, dimensions, computeInput);

            randomInput = Sldv.DataUtils.util_randvalue(prod(dimensions), numTimeSteps, computeInput);
            computeInput(noEffect) = randomInput(noEffect);

            computeInput = Sldv.DataUtils.reshapeData(numTimeSteps, dimensions, computeInput);
        end
    else
        computeInput = cell(size(inportTestData));
        if isBusArray
            % inportTestData corresponds to a bus array. So, it will
            % be a bus at the next level. inportInfo for the next level
            % should be the same
            for i=1:numel(inportTestData)
                computeInput{i} = genRandomizedData(inportTestData{i}, inportNoEffectData{i}, ...
                                                    inportInfo, numTimeSteps, false);
            end
        else
            % inportTestData corresponds to a bus. So, set inpInfo to
            % the inportInfo cell corresponding to the bus element. This
            % bus element may be a bus array - update isChildBusArray as
            % required.
            % Note: numel(inportTestData) == number of bus elements == length(inportInfo)-1
            for i=1:numel(inportTestData)
                inpInfo = inportInfo{i+1};
                isChildBusArray = false;
                if iscell(inpInfo) && isfield(inpInfo{1}, 'Dimensions') && any(inpInfo{1}.Dimensions ~= 1)
                    isChildBusArray = true;
                end
                computeInput{i} = genRandomizedData(inportTestData{i}, inportNoEffectData{i}, ...
                                                    inpInfo, numTimeSteps, isChildBusArray);
            end
        end
    end
end    
