function mk_functions_by_category
  
  % Make a list of functions by category and write out
  % to html_help/help/ug/bycatagory_content.html
  %
  
  outfile = 'html_help/help/ug/bycategory_content.html';
  
  % Make a list of categories
  cats = utils.const.categories.list;
  
  % Start HTML header
  fd = fopen(outfile, 'w+');
  
  % Make table header
  fprintf(fd, '<h2><a name="TOP">Categories</a></h2>\n');
  fprintf(fd, '<br>\n');
  fprintf(fd, '<p>\n');
  fprintf(fd, '<ul>\n');
  for jj=1:length(cats)
    c   = cats{jj};
    cns = strrep(c, ' ', '_');
    fprintf(fd, '\t<li><a href="bycategory.html#%s">%s</a></li>\n', cns, c);
  end
  fprintf(fd, '</ul>\n');
  fprintf(fd, '</p>\n');
  fprintf(fd, '<br>\n');
  
  % Get functions for each category
  infos = getAllMethods();
  for jj=1:length(cats)
    
    c   = cats{jj};
    cns = strrep(c, ' ', '_');
        
    disp(sprintf('*** Writing help for category %s', c));
    % Start new section
    fprintf(fd, '<hr>\n');
    fprintf(fd, '<h4><a name="%s"></a>%s</h4>\n', cns, c);
    fprintf(fd, '\n');
    
    % start table
    fprintf(fd, '<table cellspacing="0" class="body" cellpadding="4" border="2">\n');
    fprintf(fd, '  <colgroup>\n');
    fprintf(fd, '      <col width="20%%">\n');
    fprintf(fd, '      <col width="20%%">\n');
    fprintf(fd, '      <col width="60%%">\n');
    fprintf(fd, '    </colgroup>\n');
    fprintf(fd, '    <thead>\n');
    fprintf(fd, '      <tr valign="top">\n');
    fprintf(fd, '        <th bgcolor="#B2B2B2">Function name</th>\n');
    fprintf(fd, '        <th bgcolor="#B2B2B2">Class</th>\n');
    fprintf(fd, '        <th bgcolor="#B2B2B2">Description</th>\n');
    fprintf(fd, '      </tr>\n');
    fprintf(fd, '    </thead>\n');
    fprintf(fd, '    <tbody>\n');
    
    % add each row
    for kk=1:numel(infos)
      ii = infos(kk);
      if strcmpi(ii.mcategory, c)
        
        % This function
        fcn = ii.mname;
        
        % Function description
        fi = which([ii.mclass '/' fcn]);
        desc = getDescription(fi);
        
        fprintf(fd, '      <!-- %s -->\n', fcn);
        fprintf(fd, '      <tr valign="top">\n');
        fprintf(fd, '         <td bgcolor="#F2F2F2">\n');
        fprintf(fd, '           <p>%s</p>\n', fcn);
        fprintf(fd, '         </td>\n');
        fprintf(fd, '         <td bgcolor="#F2F2F2">\n');
        fprintf(fd, '           <p>%s</p>\n', ii.mclass);
        fprintf(fd, '         </td>\n');
        fprintf(fd, '         <td bgcolor="#F2F2F2">\n');
        fprintf(fd, '           <p>%s</p>\n', desc);
        fprintf(fd, '         </td>\n');
        fprintf(fd, '      </tr>\n');
        
      end
    end
    
    % close table
    fprintf(fd, '  </tbody>\n');
    fprintf(fd, '</table>\n');
    
    % back to top link
    fprintf(fd, '\n');
    fprintf(fd, '<a href="bycategory.html#TOP">Back to top</a>\n');
    
  end
  
  fclose(fd);
end


function infos = getAllMethods()
  
  infos = [];
  cls = utils.helper.ltpda_userclasses;
  
  for cc=1:numel(cls)
    cl = cls{cc};
    infos = [infos getPublicMethods(cl)];    
  end
end

function infos = getPublicMethods(cl)
  
  mths = {};
  
%   prefs = getappdata(0, 'LTPDApreferences');
%   vl = LTPDAprefs.verboseLevel;
%   LTPDAprefs('display', 'verboseLevel', -1);
  
  cms = eval(['?' cl]);
  infos = [];
  for ll=1:numel(cms.Methods)
    try
      mt = cms.Methods{ll};
      if (~mt.Static && ...
          strcmpi(mt.Access, 'public') && ...
          ~strcmpi(cms.Methods{ll}.DefiningClass.Name, 'handle') && ...
          ~mt.Hidden)
        
        cmd = sprintf('%s.getInfo(''%s'');', cl, mt.Name);
        ii = eval(cmd);
        ii.setMclass(cl);
        
        disp(sprintf('Added method: %s/%s', ii.mclass, ii.mname));
        mths = [mths {ii.mname}];
        infos = [infos ii];
      end
    catch Me
      fprintf(2, 'failed to add %s/%s\n', cl, mt.Name);
      fprintf(2, '%s', Me.message);
    end
  end
  
%   LTPDAprefs('display', 'verboseLevel', vl);
  
  [mths,i,j] = unique(mths);
  infos = infos(i);
end

%--------------------------------------------------------------------------
% Reads the first comment line from the file
function desc = getDescription(fname)
  
  try
    fd = fopen(fname, 'r');
    
    while ~feof(fd)
      l = strtrim(fgetl(fd));
      % look for comments
      if ~isempty(l) && l(1) == '%'
        desc = l;
        break
      end
    end
    
    fclose(fd);
  catch
    desc = '';
  end
end

%--------------------------------------------------------------------------
% Make a list of files and functions in ltpda
%
%
function cats = mkfilecatlist(versions)
  
  
  cats = {};
  
  % get categories
  for j=1:length(versions)
    c = versions(j,9);
    if ~isempty(c{1})
      % check this is already in cats
      if ~ismember(c, cats)
        cats = [cats c];
      end
    end
  end
  
end



