function flatSignalInfo = util_getCompFlatSignalInfo( compIOElem, dataAccessor)
%UTIL_GETCOMPFLATSIGNALINFO calculate the flat signal information for an
%element of compIOInfo element (see Sldv.xform.getCompiledBusOnSubSystems)
%for generation of compIOInfo for a block.

%   Copyright 2013-2020 The MathWorks, Inc.

    flatSignalInfo = [];

    signalName = cr_to_space(strrep(get_param(compIOElem.block,'Name'),'.','_'));

    if isempty(compIOElem.bus)
        % a simple signal
        compiledportPrm = Simulink.CompiledPortInfo(compIOElem.port);

        flatSignalInfo.DataType = compiledportPrm.AliasThruDataType;
        flatSignalInfo.Complexity = compiledportPrm.Complexity;
        flatSignalInfo.Dimensions = compiledportPrm.Dimensions;
        flatSignalInfo.SignalPath = signalName;
    else
        busName = compIOElem.busName;
        busObject = sl('slbus_get_object_from_name_withDataAccessor', busName, true, dataAccessor);
        busPath = busName;

        flatSignalInfo = constructLeaves(busObject, busPath, signalName, flatSignalInfo, dataAccessor, compIOElem.block);
    end
end

function out = cr_to_space(in)
    out = in;
    if ~isempty(in)
        out(in==10) = char(32);
    end
end

function [out, baseTypStr] = isLeafType(dataTypeStr, dataAccessor, blockH)
    baseTypStr = dataTypeStr;
    out = false;

    % check for builtin and predefined types
    if util_is_simulink_builtin(dataTypeStr) || ...
            util_is_fxp_type(dataTypeStr, blockH) || ...
            util_is_predefined_type(dataTypeStr)  %g1174877
        out = true;
        return;
    end

    % check for enum type
    [isEnum, className] = util_is_enum_type(dataTypeStr);
    if isEnum
        out = true;
        baseTypStr = className;
        return;
    end

    % check for fixdt and numeric types
    if strncmp(dataTypeStr,'fixdt',5) || ...
            strncmp(dataTypeStr,'numerictype',11)
        out = true;
        return;
    end

    %check for Simulink NumericType
    [isSimNumeric, baseTypStr] = util_is_sim_numeric_type(dataTypeStr, dataAccessor);
    if (isSimNumeric)
        out = true;
        return;
    end

    %check for alias type
    [isSimAlias, baseTypStr] = util_is_sim_alias_type(dataTypeStr, dataAccessor);
    if isSimAlias
        out = true;
        return;
    end

    % check if the data-type can be resolved to a bus. If not
    % assume that this is a leaf element and return the input
    % dataTypeStr as the baseTypeStr.
    % This is defensive code
    if isempty(Sldv.utils.getBusObjectFromName(dataTypeStr, false, dataAccessor))
        out = true;
        baseTypStr = dataTypeStr;
        return;
    end
end

function flatSignalInfo = constructLeaves(busObject, busPath, busElemNamePath, flatSignalInfo, dataAccessor, blockH)
    for i=1:length(busObject.Elements)
        subBusObject = busObject.Elements(i);
        subBusElemNamePath = sprintf('%s.%s',busElemNamePath,subBusObject.Name);
        busName = subBusObject.DataType;
        [isleaf, baseTyp] = isLeafType(busName, dataAccessor, blockH);
        if(isleaf)
            subBusObject.DataType = baseTyp;
            flatSignalInfo = push_into_flatSignalInfo(flatSignalInfo,...
                                                      subBusObject,...
                                                      busPath,...
                                                      subBusElemNamePath);
        else
            [leafebusObject, busName] = Sldv.utils.getBusObjectFromName(busName, true, dataAccessor);
            subBusPath = sprintf('%s.%s',busPath,busName);
            flatSignalInfo = constructLeaves(leafebusObject, subBusPath, subBusElemNamePath, flatSignalInfo, dataAccessor, blockH);
        end
    end
end

function flatSignalInfo = push_into_flatSignalInfo(flatSignalInfo,subBusObject,busPath,busElemNamePath)

    if isempty(flatSignalInfo)
        flatSignalInfo = get_bus_object_properties(subBusObject,busPath,busElemNamePath);
    else
        flatSignalInfo(end+1) = get_bus_object_properties(subBusObject,busPath,busElemNamePath);
    end

end

function busObjectProperties = get_bus_object_properties(subBusObject,busPath,busElemNamePath)
    busObjectProperties.DataType = subBusObject.DataType;
    busObjectProperties.Complexity = subBusObject.Complexity;
    busObjectProperties.Dimensions = subBusObject.Dimensions;
    busObjectProperties.SampleTime = subBusObject.SampleTime;
    busObjectProperties.BusObjPath = busPath;
    busObjectProperties.SignalPath = busElemNamePath;
    busObjectProperties.Used = true;
end
