function [cmds, rbs] = parseBlocks(blocks, wb, varID)
  
  cmds = {};
  rbs = [];
  Nrbs = awtinvoke(blocks, 'size');
  
  
  % loop over blocks
  for jj=1:Nrbs
    block = awtinvoke(blocks, 'get', jj-1);
    
    if ~block.isCommentedOut
      rbs = [rbs block];
      bname = char(block.getName);
      %     if  exist(bname) > 1 || ~isvarname(bname)
      %       error('The block named "%s" is not a valid variable name. \nPlease rename it.', bname);
      %     end
      
      % if this is a MATBlock we treat it differently since it has
      % no plist.
      if isa(block, 'mpipeline.canvas.MATBlock')
        
        cmds = parseMATblock(cmds, block, varID);
        
      elseif isa(block, 'mpipeline.canvas.PipelineBlock')
        
        cmds = parsePipelineBlock(cmds, block, varID);
        
      elseif isa(block, 'mpipeline.canvas.MATfcn')
        
        cmds = parseMATfcn(cmds, block, varID);
        
      elseif isa(block, 'mpipeline.canvas.MTerminal')
        % Terminals are not executed. They are skipped over when asking
        % for source and child blocks; that's handled on the java side.
      elseif isa(block, 'mpipeline.canvas.MConstant')
        % Don't do anything, we did this at the beginning of
        % execution
      elseif isa(block, 'mpipeline.canvas.Mux')
        
        cmds = parseMux(cmds, block, varID);
        
      elseif isa(block, 'mpipeline.canvas.Demux')
        
        cmds = parseDemux(cmds, block, varID);
        
      elseif isa(block, 'mpipeline.canvas.ToWorkspace')
        
        cmds = parseToWorkspace(cmds, block, varID);
        
      else
        
        cmds = parseLTPDAblock(cmds, block, wb, varID);
        
      end % End if on block type
    end % End if block commented out
  end % End loop over blocks
end


%--------------------------------------------------------------------------
% Parse a ToWorkspace block
%
function cmds = parseToWorkspace(cmds, block, varID)
  
  % loop over inputs to make input vars
  inputs = block.getInputs();
  
  % Loop over the inputs to get the variable names of the inputs
  for kk=0:inputs.size()-1
    ip = inputs.get(kk);
    % get the block which is connected to this input
    srcblock = block.getSourceBlock(ip.getNumber);
    % get the port number at the source block
    srcportNumber = block.getSourceBlockPortNumber(ip.getNumber);
    if ~isempty(srcblock)
      varname = LTPDAworkbench.getWS_VarName(varID, srcblock, srcportNumber);
      
      % get class of the object
      cl = evalin('base', [ 'class(' varname ')']);
      
      % get new var name
      %   - this means split the outvar at the last '.'
      nv = getVar(varname);
      
      if ismember(cl, utils.helper.ltpda_userclasses)
        cmd  = [nv ' = copy(' varname ',1);'];
      else
        cmd  = [nv ' = ' varname ';'];
      end
      
      cmds = [cmds {cmd}];
    end
  end
  
  assignin('base', 'cmds', cmds);
  clear();
  cmds = evalin('base', 'cmds');
  
end


function nv = getVar(ov)
  
  nv = '';
  
  for kk=length(ov):-1:1
    if ov(kk) == '.'
      break
    else
      nv = [nv ov(kk)];
    end
  end
  
  nv = nv(end:-1:1);
  
end

%--------------------------------------------------------------------------
% Parse a Demux block
%
function cmds = parseDemux(cmds, block, varID)
  
  % loop over inputs to make input vars
  inputs = block.getInputs();
  
  % Demux has one input
  ip = inputs.get(0);
  % get the block which is connected to this input
  srcblock = block.getSourceBlock(ip.getNumber);
  % get the port number at the source block
  srcportNumber = block.getSourceBlockPortNumber(ip.getNumber);
  if ~isempty(srcblock)
    varname = LTPDAworkbench.getWS_VarName(varID, srcblock, srcportNumber);
    incmd = [varname];
  end
  
  % make output vars
  outputs = block.getOutputs();
  for kk=1:outputs.size()
    outvar = LTPDAworkbench.getWS_VarName(varID, block, kk-1);
    cmds = [cmds {[outvar ' = ' incmd '(' num2str(kk) ');']}];
  end
  
  
end

%--------------------------------------------------------------------------
% Parse a Mux block
%
function cmds = parseMux(cmds, block, varID)
  
  % loop over inputs to make input vars
  inputs = block.getInputs();
  incmd = '[';
  varnames = {};
  
  % Loop over the inputs to get the variable names of the inputs
  for kk=0:inputs.size()-1
    ip = inputs.get(kk);
    % get the block which is connected to this input
    srcblock = block.getSourceBlock(ip.getNumber);
    % get the port number at the source block
    srcportNumber = block.getSourceBlockPortNumber(ip.getNumber);
    if ~isempty(srcblock)
      varname = LTPDAworkbench.getWS_VarName(varID, srcblock, srcportNumber);
      varnames = [varnames {varname}];
      incmd = [incmd varname ','];
    end
  end
  if incmd(end)==','
    incmd = incmd(1:end-1);
  end
  incmd = strtrim(incmd);
  incmd = [incmd ']'];
  % make output vars
  outputs = block.getOutputs();
  if outputs.size() > 1
    error('### Mux blocks should have only one output.');
  elseif outputs.size() == 1
    outcmd = '[';
    for kk=1:outputs.size()
      outvar = LTPDAworkbench.getWS_VarName(varID, block, kk-1);
      outcmd = [outcmd outvar ' '];
    end
    outcmd = strtrim(outcmd);
    outcmd = [outcmd '] = '];
  else
    outcmd = '';
  end
  
  cmds = [cmds {[outcmd incmd ';']}];
  
  
end


%--------------------------------------------------------------------------
% Parse a command from a MATBlock block
%
function cmds = parsePipelineBlock(cmds, block, varID)
  
  % get variable name
  outvar = LTPDAworkbench.getWS_VarName(varID, block, 0);
  
  % Get source port that this block links to
  sp = block.getSourcePort;
  % get the parent of that port
  sb = sp.getParent;
  % get var name
  srcvar = LTPDAworkbench.getWS_VarName(varID, sb, sp.getNumber);
  
  % build command string
  cmd = [outvar ' = ' srcvar ';'];
  
  % we should check if the srcvar exists
  try
    evalin('base', [srcvar ';']);
  catch
    utils.helper.errorDlg(sprintf('Source variable [%s] doesn''t exist. Did you run the required pipeline?', srcvar), 'Pipeline Source Error');
  end
  
  cmds = [cmds {cmd}];
  
end


%--------------------------------------------------------------------------
% Parse a command from a MATBlock block
%
function cmds = parseMATblock(cmds, block, varID)
  
  % get variable name
  outvar = LTPDAworkbench.getWS_VarName(varID, block, 0);
  % get expression
  exp = char(block.getExpression());
  
  % can this expression be evaluated or is it a string?
  try
    evalin('base', [exp ';']);
    cmd = [outvar ' = ' exp ';'];
  catch
    cmd = [outvar ' = ''' exp ''';'];
  end
  cmds = [cmds {cmd}];
  
end


%--------------------------------------------------------------------------
% Parse a command from an LTPDA block
%
function cmds = parseLTPDAblock(cmds, block, wb, varID)
  
  % We have a normal LTPDA block with a plist etc....
  
  blockclass = char(block.getMinfo().getMclass);
  % build command
  cmd = strrep(char(block.getAlgoName), ' ', '_');
  
  % make plist for this block
  jpl = block.getPlist();
  pl = LTPDAworkbench.jpl2mpl(jpl);
  spl = string(pl);
  
  % We need to skip any PORT_# when making the inputs
  tks = regexpi(spl, 'PORT_(\d+)', 'tokens');
  skipports = [];
  for kk=1:numel(tks)
    skipports = [skipports str2double(tks{kk}{1})];
  end
  %       skipports = skipports + 1;
  % loop over inputs to make input vars
  inputs = block.getInputs();
  incmd = '(';
  varnames = {};
  
  % Loop over the inputs to get the variable names of the inputs
  for kk=0:inputs.size()-1
    ip = inputs.get(kk);
    if ~any(ip.getNumber==skipports)
      % get the block which is connected to this input
      srcblock = block.getSourceBlock(ip.getNumber);
      % get the port number at the source block
      srcportNumber = block.getSourceBlockPortNumber(ip.getNumber);
      if ~isempty(srcblock)
        varname = LTPDAworkbench.getWS_VarName(varID, srcblock, srcportNumber);
        varnames = [varnames {varname}];
        incmd = [incmd varname ','];
      end
    end
  end
  incmd = strtrim(incmd);
  incmd = [incmd spl ')'];
  % make output vars
  outputs = block.getOutputs();
  if outputs.size() > 0
    outcmd = '[';
    for kk=1:outputs.size()
      output = outputs.get(kk-1);
      outvar = LTPDAworkbench.getWS_VarName(varID, block, output.getNumber);
      bits = regexp(outvar, '\.', 'split');
      if  exist(outvar) > 1 && ~allAreVarNames(bits)
        error('The block named "%s" is not a valid variable name. \nPlease rename it.', outvar);
      end
      outcmd = [outcmd outvar ' '];
    end
    outcmd = strtrim(outcmd);
    outcmd = [outcmd '] = '];
  else
    outcmd = '';
  end
  
  % Modify plist constructors looking for PORT_#
  for kk=1:pl.nparams
    if ischar(pl.params(kk).getVal)
      idxs = regexpi(pl.params(kk).getVal, '(PORT_\d*)', 'tokens');
      repstr = pl.params(kk).getVal;
      for ii=1:numel(idxs)
        pstr = idxs{ii}{1};
        % get port number
        [s,r] = strtok(pstr, '_');
        portNumber = str2num(r(2:end));
        % Now we need to find the name of the output variable at the
        % other end of this pipe
        sb = block.getSourceBlock(portNumber);
        if ~isa(sb, 'mpipeline.canvas.MElementWithPorts')
          error('### Block %s has an input PORT_%d specified in the plist, \nbut the block has no such input, or the input is not connected to a source block', char(block.getName()), portNumber);
        end
        sbp = block.getSourceBlockPortNumber(portNumber);
        sbpn = LTPDAworkbench.getWS_VarName(varID, sb, sbp);
        % replace the PORT_# string with the correct variable name
        repstr = strrep(repstr, pstr, char(sbpn));
      end
      % If we modified the parameter value string, then we need to
      % remove the string quotes, and replace this in the string
      % representation of the plist (spl)
      if ~strcmp(repstr, pl.params(kk).getVal)
        repstr = strrep(repstr, '''', '');
        spl = strrep(spl, ['''' pl.params(kk).getVal ''''], repstr);
      end
      
      % rebuild incmd
      incmd = '(';
      for ll=1:numel(varnames)
        incmd = [incmd varnames{ll} ','];
      end
      incmd = strtrim(incmd);
      incmd = [incmd spl ')'];
    end
  end
  comment = ['% ' blockclass];
  
  % We do something different if this is a modifier
  if block.isModifier
    
    mcmd = [cmd incmd ';' comment];
    if outputs.size() > 1
      error('Block %s is set as a modifier but has more than one output. This is not possible.', char(block.getName));
    end
    cmds = [cmds {mcmd}];
    for kk=1:numel(varnames)
      ecmd = [outvar '(' num2str(kk) ') = ' varnames{kk} ';'];
      cmds = [cmds {ecmd}];
    end
    
  else
    cmds = [cmds {[outcmd cmd incmd ';' comment]}];
  end
  
  % add command to set name of block if this is a constructor
  cat = char(block.getMinfo.getMcategory);
  if outputs.size() == 1 && strcmpi(cat, 'constructor') && (strcmpi(pl.find('name'), 'None') || isempty(pl.find('name')))
    cmd = {[outvar '.setName(''' char(block.getName()) ''')']};
    cmds = [cmds cmd];
  end
  
  % add command to attach workbench if necessary
  if block.isAttachWorkbench
    
    % get the workbench in XML format
    if isa(wb, 'LTPDAworkbench')
      xmlout = char(wb.mp.workbenchAsXMLString);
    end
    
    for kk=1:outputs.size()
      outvar = LTPDAworkbench.getWS_VarName(varID, block, kk-1);
      bits = regexp(outvar, '\.', 'split');
      if  exist(outvar) > 1 && ~allAreVarNames(bits)
        error('The block named "%s" is not a valid variable name. \nPlease rename it.', outvar);
      end
      cmd = {[outvar '.setMdlfile('''  strrep(xmlout, '''', '''''') ''');']};
      cmds = [cmds cmd];
    end
    
  end
  
end

function res = allAreVarNames(cs)
  
  res = true;
  for jj=1:numel(cs)
    if ~isvarname(cs{jj})
      res = false;
      break;
    end
  end
  
end

%--------------------------------------------------------------------------
% Parse a command from a MATfcn block
%
function cmds = parseMATfcn(cmds, block, varID)
  
  % build command
  cmd = char(block.getFcnName);
  
  % loop over inputs to make input vars
  inputs = block.getInputs();
  incmd = '(';
  varnames = {};
  
  % Loop over the inputs to get the variable names of the inputs
  for kk=0:inputs.size()-1
    ip = inputs.get(kk);
    % get the block which is connected to this input
    srcblock = block.getSourceBlock(ip.getNumber);
    % get the port number at the source block
    srcportNumber = block.getSourceBlockPortNumber(ip.getNumber);
    if ~isempty(srcblock)
      varname = LTPDAworkbench.getWS_VarName(varID, srcblock, srcportNumber);
      varnames = [varnames {varname}];
      incmd = [incmd varname ','];
    end
  end
  if incmd(end)==','
    incmd = incmd(1:end-1);
  end
  incmd = strtrim(incmd);
  incmd = [incmd ')'];
  % make output vars
  outputs = block.getOutputs();
  if outputs.size() > 0
    outcmd = '[';
    for kk=1:outputs.size()
      outvar = LTPDAworkbench.getWS_VarName(varID, block, kk-1);
      outcmd = [outcmd outvar ' '];
    end
    outcmd = strtrim(outcmd);
    outcmd = [outcmd '] = '];
  else
    outcmd = '';
  end
  
  cmds = [cmds {[outcmd cmd incmd ';']}];
end

