function varargout=loopblock(c,sortBy,blockScope,searchTerms)
%LOOPBLOCK loop over blocks
%   BLKLIST= LOOPBLOCK(ZSLMETHODS,SORTBY,CONTEXT)
%            Returns a sorted list of blocks appropriate
%            to the current context.
%   INFO   = LOOPBLOCK(ZSLMETHODS) 
%            Returns a list of SORTBY and CONTEXT values
%            with descriptions of each.
%            INFO.sort
%            INFO.context
%       
%     Valid SORTBY values are 
%          $alphabetical - block name
%          $systemalpha - system name
%          $depth - depth of system
%          ''      - no sort
%     Valid CONTEXT values are
%          System - returns all blocks in current system
%          Signal - returns parent block of current signal
%          Block  - just returns current block
%          Model  - returns a list of blocks in looped systems
%                   in the current model.  (defined
%                   in csl_mdl_loop
%          {'blockname','blockname'} - a cell array of full block names
%          [h1 h2 h3 h4 h5] - a vector of block handles
%
%    See also CSL_BLK_LOOP, CSL_MDL_LOOP
 
%   Copyright (c) 1997-2000 by The MathWorks, Inc.
%   $Revision: 1.16 $  $Date: 2000/09/11 09:12:38 $

if nargin==1
   bList.sortCode={
      '$alphabetical'
      '$systemalpha'
      '$fullpathalpha'
      '$blocktype'
      '$depth'
      '$none'
   };
   bList.sortName={
      'Alphabetically by block name'
      'Alphabetically by system name'
      'Alphabetically by full Simulink path'
      'By block type'
      'By block depth'
      'No sort'
   };
   if strcmp(get_param(0,'RtwLicensed'),'on')
      bList.sortCode{end+1}='$runtime';
      bList.sortName{end+1}='By simulation order (req RTW)';
   end
   
   bList.contextCode={
      'System'
      'Model'
      'Signal'
      'Block'
      ''
   };
   bList.contextName={
      sprintf('All blocks in current system')
      sprintf('All reported blocks in current model')
      sprintf('All blocks connected to current signal')
      sprintf('Current block')
      sprintf('All blocks in all models')
   };
   varargout{1} = bList; varargout{2} = [];
else
   if nargin<4
      searchTerms={};
   end
   
   z=zslmethods;
   
   if iscell(blockScope) | isnumeric(blockScope)
      [bList, badList]=LocFindBlocks(blockScope,0,searchTerms);
   else
      switch blockScope
      case 'System'
         currSys=subsref(z,substruct('.','System'));
         [bList, badList]=LocFindBlocks(...
            currSys,...
            1,...
            searchTerms);
         bList=setdiff(bList,currSys);
      case 'Signal'
         [bList, badList]=LocFindBlocks(...
            LocConnectedBlocks(subsref(z,substruct('.','Signal'))),...
            0,...
            searchTerms);
      case 'Block'
         [bList, badList]=LocFindBlocks(...
            subsref(z,substruct('.','Block')),...
            0,...
            searchTerms);
      case 'Model'
         sysList=subsref(z,substruct('.','ReportedSystemList'));
         [bList, badList]=LocFindBlocks(...
            sysList,...
            1,...
            searchTerms);
         bList=setdiff(bList,sysList);
      otherwise
         mList=find_system('SearchDepth',1,...
            'BlockDiagramType','model');
         [bList, badList]=LocFindBlocks(...
            mList,...
            [],...
            searchTerms);
      end
   end

   if length(bList)>1
       %note that if sortBy is not one of these strings, no sort is done
      switch sortBy  
      case '$runtime'
         simList=subsref(z,substruct('.','SortedBlockList'));
         [sameBlocks,indexA,indexB]=intersect(simList,bList);
         notIntersectB=setdiff([1:length(bList)],indexB);
         bList={simList{indexA},bList{notIntersectB}};
      case '$fullpathalpha'
         if iscell( bList )
            sysList=bList;
         else
            sysList = handles2names( bList );
         end
         [sysList,sysIndex]=sort(lower(sysList));
         bList=bList(sysIndex);        
      case '$systemalpha'
         sysList=getparam(z,...
            getparam(z,...
            bList,'Parent'),'Name');
         [sysList,sysIndex]=sort(lower(sysList));
         bList=bList(sysIndex);
      case '$alphabetical'
         nameList=getparam(z,bList,'Name');
         [nameList,nameIndex]=sort(lower(nameList));
         bList=bList(nameIndex);
      case '$blocktype'
         typeList=getparam(z,bList,'Blocktype');
         [sortedTypeList,sortIndex]=sort(typeList);
         bList=bList(sortIndex);
      case '$depth'
         %calling with upper-case is important to force
         %the special-case property to happen
         depthList=propblock(z,'GetPropValue',bList,'Depth');
         emptyDepth=find(cellfun('isempty',depthList));
         if length(emptyDepth)>0
            [depthList{emptyDepth}]=deal(0);
         end      
         [depthList,depthIndex]=sort([depthList{:}]);
         bList=bList(depthIndex);
     otherwise
         %no sort
      end
      bList=bList(:);
   elseif length(bList)==0
      bList={};
   end
   varargout{1} = bList;
   varargout{2} = badList;
end
%guarantee that the list is a column array


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [oList, badList]=LocFindBlocks(objList,searchDepth,searchTerms);
%objList can be a vector of handles or a cell array of full block names

vNum=version;
%vNum='5.3 (R11)';
if str2num(vNum(1))<6
   %allow this to be used with pre-r12 code
   regCell={};
   bString='block';
   searchTerms=LocWashSearchTerms(searchTerms);
else
   if isempty(searchTerms)
      searchTerms={};
      rExp='off';
      bString='block';
   else
      searchTerms=LocWashSearchTerms(searchTerms);
      rExp='on';
      bString='\<block\>';
   end
   regCell={'RegExp',rExp};
end

if isempty(searchDepth)
   depthCell={};
else
   depthCell={'SearchDepth',searchDepth};
end

[objList, badList] = LocFilterBlocks( objList ); 
oList=find_system(objList,...
   depthCell{:},...
   regCell{:},...
   'Type',bString,...
   searchTerms{:});

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function t=LocWashSearchTerms(t);

numTerms=length(t);
if rem(numTerms,2)>0
   %the number of terms should be even
   t{end+1}='';
   numTerms=numTerms+1;
end

emptyCells=find(cellfun('isempty',t));
emptyNames=emptyCells(1:2:end-1);
emptyNames=emptyNames(:);

removeCells=[emptyNames;emptyNames+1];
okCells=setdiff([1:numTerms],removeCells);

t=t(okCells);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function bList=LocConnectedBlocks(currSig)
%find all blocks connected to a signal

bList={};
if ~isempty(currSig)
   try
      lineHandle=get_param(currSig,'Line');
   catch
      lineHandle=-1;
   end
   
   if ishandle(lineHandle)
      try
         bHandles=[get_param(lineHandle,'SrcBlockHandle')
            get_param(lineHandle,'DstBlockHandle')];
      catch
         bHandles=[];
      end
      
      bHandles=bHandles(ishandle(bHandles));
      
      for i=length(bHandles):-1:1
         bList{i}=getfullname(bHandles(i));
      end
   else
      %there is no line - just return the parent block
      bList={get_param(currSig,'Parent')};
   end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [objList, badBlockList] = LocFilterBlocks( objList )
%Makes sure that all blocks listed are valid

try
   objList = find_system( objList,'SearchDepth',0);
   badBlockList = [];
catch
   % this happens when there is a problem in the objList
   % (such as some of the entries of the list are invalid)
   badList = [];
   if iscell( objList ), ic = 1; else ic = 0; end
   for i = 1:length( objList )
      if ic, curItem = objList{i}; else curItem = objList(i); end
      try
         find_system( curItem,'SearchDepth',0);
      catch
         badList = [ badList, i ];
      end
   end
   badBlockList = objList( badList );
   objList ( badList ) = [];
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function names = handles2names (handles)
names = {};
for i = length( handles ):-1:1
   names{i} = getfullname( handles(i) );
end
