function varargout = commblkrandintsrc2(block, action, varargin)
%COMMBLKRANDINTSRC2 Mask dynamic dialog function for Random Integer Generator block

% Copyright 1996-2019 The MathWorks, Inc.

%  Possible calls:
%      commblkrandintsrc2(block, 'cbFrameBased')
%      commblkrandintsrc2(block, 'cbOrient')
%      commblkrandintsrc2(block, 'cbOutDataType')
%      commblkrandintsrc2(block, 'init', mul, seed, frameBased)

switch(action)
%*********************************************************************
% Function:			initialize
% Description:		Set the dialogs up based on the parameter values.
%						MaskEnables/MaskVisibles are not save in reference 
%						blocks.
% Inputs:			current block
% Return Values:	none
%********************************************************************
  case 'init'     
    isSysObj = matlab.system.isSystemObject(block);
    if ~isSysObj
        % Ensure that the mask is correct
        cbFrameBased(block);
        cbOrient(block);
    end
   % --- Exit code and error message definitions
   eStr.ecode = 0;
   eStr.eID   = '';
   eStr.emsg  = '';
   
   if ~isSysObj
       % --- If the simulation status is 'stopped', then the function is being called
       %     because of an OK or apply and so the parameters do not need to be valid
       %     and hence, need not be evaluated
       simStatus = get_param(bdroot(gcb),'SimulationStatus');
       if(strcmpi(simStatus,'stopped'))
           eStr.ecode = 3;  % Quiet exit
           varargout{1} = eStr;
           return;
       end
   end
   % Set parameter values from the mask workspace  
   [mul, seed, frameBased, orient] = deal(varargin{:});  
   
   vLen = [length(mul) length(seed)];
   lenmax = max(vLen);            % Largest of all the parameter lengths

   vSizeMValue = size(mul);
   vSizeSeed   = size(seed);
           
   % Check for consistency among vector parameter lengths.  The M-ary number and
   % Seed parameters are singly checked by the Random source S-function.
   if ~isequal(lenmax,1)   % if there exist vector parameters 
       % Check if vector lengths (if any) agree
       if any(find(vLen(vLen~=1)~=lenmax))
           eStr.ecode = 1;
           eStr.eID   = 'comm:commblkrandintsrc2:InvalidParamDims';
           eStr.emsg  = 'M-ary number and Initial seed must be either all scalars, or if more than one of them is a vector, their vector sizes should agree.';
           
           % If dimensions are to be preserved, check if they agree
       elseif strcmp(orient,'off') && strcmp(frameBased,'off') ...
               && ~isequal(vSizeMValue(1),vSizeSeed(1)) && ~isequal(vSizeMValue(2),vSizeSeed(2))
           eStr.ecode = 1;
           eStr.eID   = 'comm:commblkrandintsrc2:InconsistentParamDims';
           eStr.emsg  = ['Dimensions of parameter values in ', block, ' are inconsistent.'];
       end
   end     
   
   if ~is(mul, 'positive integer')   
       eStr.ecode = 1;
       eStr.eID   = 'comm:commblkrandintsrc2:InvalidM';
       eStr.emsg  = ['The M-ary number in ', block, ' must be a positive integer.'];
   end   
   
   if isSysObj
       outDataType = block.OutputMode;
   else
        outDataType = get_param(block, 'OutDataType');
   end
   if (strcmp(outDataType, 'boolean') && any(mul>2))
       eStr.ecode = 1;
       eStr.eID   = 'comm:commblkrandintsrc2:InvalidMBool';
       eStr.emsg  = 'The M-ary number must be 2 for boolean outputs.';
   end   
   
   if ~isSysObj
       cbOutDataType(block);
       
       if ~eStr.ecode
           UpdataBlocks(block, vLen, vSizeMValue, vSizeSeed);
       end
   end
   
   varargout{1}=eStr;

 case 'cbFrameBased'
    cbFrameBased(block)

 case 'cbOrient'
    cbOrient(block);

 otherwise
   default_setting(block);
end


%----------------------------------------------------------------------
%
%	Subfunctions
%
%----------------------------------------------------------------------

%*********************************************************************
% Function Name:	'cbFrameBased'
%  - Callback function for 'frameBased' parameter
%********************************************************************
function cbFrameBased(block)

  frameBased = get_param(block, 'FrameBased');
  [idxSampPerFrame, idxOrient] = dspGetMaskParamIdx(block, 'sampPerFrame', 'orient');
  Vis   = get_param(block, 'maskvisibilities');
  En    = get_param(block, 'maskenables');
  oldEnSamp   = En{idxSampPerFrame};
  oldEnOrient = En{idxOrient};

  if(strcmp(frameBased,'off'))  % Sample-based
    En{idxSampPerFrame}  = 'off';
    En{idxOrient}  = 'on';
    Vis{idxSampPerFrame}  = 'off';
    Vis{idxOrient}  = 'on';
  else % 'Frame-based'
    En{idxSampPerFrame}  = 'on';
    En{idxOrient}  = 'off';
    Vis{idxSampPerFrame}  = 'on';
    Vis{idxOrient}  = 'off';
  end
  
  if ~strcmp(oldEnSamp, En{idxSampPerFrame}) || ~strcmp(oldEnOrient, En{idxOrient})
      set_param(block,'MaskEnables',En,'MaskVisibilities',Vis);
  end


%*********************************************************************
% Function Name:	'cbOrient'
%  - Callback function for 'orient' parameter
%********************************************************************
function cbOrient(block)
  idxFrameBased   = dspGetMaskParamIdx(block, 'frameBased');
  
  orient = get_param(block, 'Orient');
  Vis   = get_param(block, 'maskvisibilities');
  En    = get_param(block, 'maskenables');
  oldEnFrame = En{idxFrameBased};
  
  if(strcmp(orient,'on'))  % Interpret as 1-D
    En{idxFrameBased}   = 'off';
    Vis{idxFrameBased}  = 'off';
  else
    En{idxFrameBased}   = 'on';
    Vis{idxFrameBased}  = 'on';
  end
  
  if ~strcmp(oldEnFrame, En{idxFrameBased}) 
      set_param(block,'MaskEnables',En,'MaskVisibilities',Vis);
  end


%*********************************************************************
% Function Name:	'cbOutputDataType'
%  - Callback function for 'outDataType' parameter
%********************************************************************
function cbOutDataType(block)

  outDataType = get_param(block, 'OutDataType');

  addBlkName = 'Data Type Conversion';
  
  % Determine if the Data Type Conversion (DTC) block exists 
  isDTCPresent = find_system(block, 'LookUnderMasks', 'all', 'FollowLinks',...
                             'on', 'SearchDepth', 1, 'Name', addBlkName);
  
  % Delete the data type converter block if selected choice is double or
  % single else add it.
  if (strcmp(outDataType,'single'))
      % This gives different results for Single/Double from the DSP random source.
      set_param([block, '/Random Source'], 'DataType', 'Single', ...
                'MinVal', '-1+eps(''single'')');   
      
      if ~isempty(isDTCPresent) % if present, delete it
          delete_line(block,'Reshape/1', [addBlkName '/1']);
          delete_line(block, [addBlkName '/1'], 'Out1/1');
          delete_block([block '/' addBlkName]);
          add_line(block, 'Reshape/1', 'Out1/1');
      end
      
  elseif (strcmp(outDataType,'double'))
      set_param([block, '/Random Source'],'DataType', 'Double', ...
                'MinVal', '-1+eps');   
      
      if ~isempty(isDTCPresent) % if present, delete it
          delete_line(block,'Reshape/1',[addBlkName '/1']);
          delete_line(block,[addBlkName '/1'], 'Out1/1');
          delete_block([block '/' addBlkName]);
          add_line(block, 'Reshape/1', 'Out1/1');
      end
      
  else % all ints, boolean cases
      if isempty(isDTCPresent) % if not present, add it
          load_system('simulink');
          delete_line(block,'Reshape/1','Out1/1');
          add_block(sprintf(['simulink/Signal\nAttributes/' addBlkName]),...
                    [block '/' addBlkName], 'Position', [335 28 410 62]);
          add_line(block, 'Reshape/1', [addBlkName '/1']);
          add_line(block, [addBlkName '/1'], 'Out1/1');
      end
      
      % Set the Data Type converter block's output type
      set_param([block, '/' addBlkName], 'OutDataTypeStr', outDataType);   
      
      % Set the Random Source block's output type 
      set_param([block, '/Random Source'], 'DataType', 'Double', ...
                'MinVal', '-1+eps');   
      
  end    


%*********************************************************************
% Function:			UpDateBlocks
% Description:		Set the simulink blocks as required
% Inputs:			current block
% Return Values:	none
%********************************************************************

function UpdataBlocks(block, vLen, vSizeMValue, vSizeSeed)  

   frameBased = get_param(block, 'FrameBased');
   orient = get_param(block, 'Orient');
   
   % Sample-based case
   if(strcmp(frameBased,'off'))
      
      set_param([block, '/Frame Status Conversion'],'outframe','Sample-based');   
      
      % Interpret as 1-D; OR scalar output
      if(strcmp(orient,'on')) || ~any(vLen-1)
          set_param([block, '/Reshape'],'OutputDimensionality','1-D array');
       
      % 2-D vector output    
       else          
          % Column vector
          if ( (vSizeMValue(2) == 1)  && (vSizeSeed(2) == 1) )
             set_param([block, '/Reshape'],'OutputDimensionality','Column vector');
          % Row vector   
          elseif ( (vSizeMValue(1) == 1)  && (vSizeSeed(1) == 1) )
             set_param([block, '/Reshape'],'OutputDimensionality','Row vector');
          end            
       end
      
   % Frame-based case
   else
      set_param([block, '/Frame Status Conversion'],'outframe','Frame-based');   
      set_param([block, '/Reshape'],'OutputDimensionality','Customize');            
      set_param([block, '/Reshape'],'OutputDimensions','[sampPerFrame,max([length(mul), length(seed)])]');
      
   end

% [EOF]
