classdef QueuedIOFunctionInfo < rtw.pil.CSFunctionInfo & rtw.pil.BaseCallerFunctionInfo
    %QUEUEDIOFUNCTIONINFO: common parent of all queued message interfaces
    
    %   Copyright 2017-2019 The MathWorks, Inc.
      
    properties (Access = protected)
        PortNumber = [];
        ArgName = '';
        ArgDir = '';
    end
    
    properties (Constant)
        IsSimulinkFunction = false;
    end
    
    methods
        function this = QueuedIOFunctionInfo(fcnName, ...
                rtmTypeIdentifier, ...
                argType, ...
                timing, ...
                variantInfo,...
                tid,...
                fcnId,...
                isDefined,...
                isAUTOSAR, ...
                portNumber, ...
                argName, ...
                argDir, ...
                mf0Instance)
            
            % validate inputs
            validateattributes(fcnId,{'numeric'},{'scalar','nonempty'},'QueuedIOFunctionInfo');
            
            codeInfoData.Prototype = generateQueuedPrototype(mf0Instance, fcnName, argType, argDir, argName);
            codeInfoData.PortName = fcnName;
            codeInfoData.Timing = timing;
            codeInfoData.VariantInfo = variantInfo;
            codeInfoData.IsQueuedMessageInterface = true;
            
            % call superclass constructor
            isLegacyAutosarOperation = false;
            this@rtw.pil.CSFunctionInfo(codeInfoData, fcnName, rtmTypeIdentifier, tid, isAUTOSAR, isLegacyAutosarOperation);
            this@rtw.pil.BaseCallerFunctionInfo(fcnId, isDefined);

            this.PortNumber = portNumber - 1; %Zero based
            this.ArgName = argName;
            this.ArgDir = argDir;
            
            this.IsQueued = true;
            
            % Set the name of the caller on the target.
            % This is just the port name for queued I/O.
            portName = this.getCodeInfoData.PortName;
            this.TargetFunctionName = portName;
        end
        
        function portNumber = getPortNumber(this)
            portNumber = this.PortNumber;
        end
        
        function [sid, argTypePrefix, argNamePrefix, argConstructor] = getArgDataInfo(this) %#ok<MANU>
            sid = '';
            argTypePrefix = 'queued';
            argNamePrefix = 'xsd_que';
            argConstructor = @rtw.pil.MessageFunctionArgData;
        end                                
        
        function slFunctionName = getSlFunctionName(this)
            slFunctionName = this.getOperationName;
        end
    end    
    
    methods (Access = 'protected')
        % returns the function name of the caller on the target. For AUTOSAR,
        % the function name is normally Rte_Call_<PortName>_<OperationName>
        function initializeTargetFunctionName(this)
            
            portName = this.getCodeInfoData.PortName;
            this.TargetFunctionName = portName;
            
        end        
    end
    
        
        
end



function queuedProto = generateQueuedPrototype(mf0Instance, fcnName, argType, argDir, argName)

returnArg = generateArg('', generateRetType(mf0Instance) , 'OUTPUT', -1, mf0Instance);
rhsArg = generateArg(argName, argType, argDir, 0, mf0Instance);

if isempty(mf0Instance)
    queuedProto = coder.types.Prototype;
    queuedProto.Arguments = rhsArg;
else
    queuedProto = coder.descriptor.types.Prototype(mf0Instance);
    assert(numel(rhsArg) == 1, 'rhsArg should be scalar');
    queuedProto.Arguments.add(rhsArg);
end
queuedProto.HeaderFile = '';
queuedProto.SourceFile = '';
queuedProto.Name = fcnName;
queuedProto.Return = returnArg;

end

function newArg = generateArg(argName, argType, argDir, graphicalIdx, mf0Instance)

%Create prototype argument
if isempty(mf0Instance)
    newArg = coder.types.Argument;
    newArg.GraphicalIndex = int32(graphicalIdx);
else
    newArg  = coder.descriptor.types.Argument(mf0Instance);
    assert(numel(graphicalIdx) == 1, 'graphicalIdx should be scalar');
    newArg.GraphicalIndex.add(int32(graphicalIdx));
end
newArg.Name= argName;
newArg.Type= argType;
newArg.IOType= argDir;
end

function retType = generateRetType(mf0Instance)
if isempty(mf0Instance)
    retType = coder.types.Int;
else
    retType = coder.descriptor.types.Integer(mf0Instance);
end
retType.Signed = 0;
retType.WordLength = 8;
retType.Identifier = 'uint8_T';
retType.Name = 'Std_ReturnType';

end
