function [sTo] = som_autolabel(sTo, varargin)

%SOM_AUTOLABEL Automatical labeling, or clearing of labels.
%
% sTo = som_autolabel(sTo, sFrom, [mode], [inds])
%  or
% sTo = som_autolabel(sTo, 'clear', [inds])
%
% ARGUMENTS ([]'s are optional)
%
%  sTo      (struct) data or som struct to which the labels are put 
%            or cleared from
%  [sFrom]  (struct) data or som struct which is used as the label source.
%            If missing the mode should be 'clear'. 
%  [mode]   (string) labeling algorithm: 'add' or 'freq' or 'vote' 
%            or 'clear' (see below), default is 'add'. 
%            If mode is 'clear', the sFrom argument should
%            be missing, empty or NaN.
%  [inds]   (vector) the indexes of the labels that are to be used in 
%            the operation
%
% RETURNS
%
%  sTo      (struct) the labeled structure 
% 
% NOTE: all empty labels ('') are ignored.
%
% The modes:
%  'add':   all labels from sFrom are added to sTo
%  'freq':  only one instance of each label is kept and '(#)', where 
%           # is the frequency of the label, is added to the label.
%           Labels are ordered according to frequency. 
%  'vote':  only the label with most instances is kept
%  'clear': replace the labels with empty strings ('')
%
% EXAMPLES
%
%  sM = som_autolabel(sM,sD);      % label sM based on sD 
%  sD = som_autolabel(sD,sM);   
%     % label sD based on sM, notice that in this case the 
%     % value of mode does not matter (unless it is 'clear')
%     % because a data vector can only have a single BMU
%  sM = som_autolabel(sM,sD,'vote',[1,2,5]);
%     % label each node of sM with the most frequent label in 
%     % that node using labels 1, 2 and 5 from sD
%  sD = som_autolabel(sD,'clear'); % clear labels of sD
%
% See also SOM_HITS, SOM_BMUS, SOM_ADDLABELS, SOM_PLANEL.     

% Copyright (c) 1997 by the SOM toolbox programming team.
% http://www.cis.hut.fi/projects/somtoolbox/

% Version 1.0beta juuso 061197 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% check arguments

error(nargchk(2, 4, nargin));  % check no. of input args is correct

% default values
mode = 'add'; 

% sTo
if isstruct(sTo)
  if isfield(sTo, 'data')         % data struct
    to = 'data'; 
    [dlen m] = size(sTo.labels); 
  elseif isfield(sTo, 'codebook') % map struct
    to = 'map';
    si = size(sTo.labels); m = 0;
    for i=1:prod(si), m = max(m,length(sTo.labels{i})); end
  else
    error('First argument is an invalid structure.');
  end
  label_inds = 1:m;
else 
  error('First argument is invalid.');
end

% sFrom
if isstruct(varargin{1})
  sFrom = varargin{1};
  if isfield(sFrom, 'data')         % data struct
    from = 'data'; 
    [dlen m] = size(sFrom.labels); 
  elseif isfield(sFrom, 'codebook') % map struct
    from = 'map';
    si = size(sFrom.labels); m = 0;
    for i=1:prod(si), m = max(m,length(sFrom.labels{i})); end
  else
    error('Second argument is an invalid structure.');
  end
  label_inds = 1:m;
else
  if strcmp(varargin{1},'clear') | isempty(varargin{1}) | all(isnan(varargin{1})), 
    mode = 'clear'; 
    from = 'nil';
  else 
    error('Second argument is invalid.');
  end
end

if strcmp(to,from) & ~strcmp(mode,'clear'), 
  error(['Cannot label from ',from,' to ',to,'.']);
end

% mode, label_inds
if strcmp(mode,'clear'), 
  switch nargin,
  case 2, %ok
  case 3, 
    if any(strcmp(varargin{2},{'add','freq','vote'})), 
      error('Second and third arguments mismatch.');
    elseif strcmp(varargin{2},'clear'), 
      %ok
    else
      label_inds = varargin{2}; 
    end
  case 4,
    if any(strcmp(varargin{2},{'add','freq','vote'})), 
      error('Second and third arguments mismatch.');
    else
      label_inds = varargin{3};
    end
  end
else
  % mode = 'add' by default
  if nargin > 2,
    if any(strcmp(varargin{2},{'add','freq','vote'})), 
      mode = varargin{2};
    elseif strcmp(varargin{2},'clear'),
      error('Second and third arguments mismatch.');
    elseif isempty(varargin{2}),
      %ok
    else
      error('Third argument is invalid.');
    end
    if nargin==4,
      label_inds = varargin{3};
    end
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% initialize

if strcmp(mode,'clear'), 
  if strcmp(to,'map'), 
    for i=1:prod(size(sTo.labels));
      % choose the valid indexes and set those labels to ''
      inds = label_inds(find(label_inds <= length(sTo.labels{i}))); 
      for j=inds, sTo.labels{i}{j} = ''; end 
    end 
  else 
    for i=1:dlen, 
      for j=label_inds, sTo.labels{i,j} = ''; end 
    end 
  end 
  return; 
end

% calculate BMUs
if strcmp(to,'data'), 
  bmus = som_bmus(sFrom,sTo,1);
else
  bmus = som_bmus(sTo,sFrom,1);
end

% convert data label cell structure
if strcmp(to,'data'), sTo.labels = data_labels_to_cellarray(sTo.labels); end
if strcmp(from,'data'), sFrom.labels = data_labels_to_cellarray(sFrom.labels); end

% for each vector in sTo, give all labels of the corresponding 
% vector in sFrom
for d=1:length(bmus), 
  m = bmus(d);
  if strcmp(to,'data'), t = d; f = m; else t = m; f = d; end
  if ~isnan(m), 
    % choose valid indexes
    inds = label_inds(find(label_inds <= length(sFrom.labels{f}))); 
    % add the corresponding labels
    for j=1:length(inds), 
      if ~isempty(sFrom.labels{f}{inds(j)}), 
        sTo.labels{t}{length(sTo.labels{t})+1} = sFrom.labels{f}{inds(j)}; 
      end
    end 
  end
end
  
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% action

if strcmp(mode,'add'), 
  % convert back
  if strcmp(to,'data'), sTo.labels = cellarray_to_data_labels(sTo.labels); end
  return; 
end

for i=1:prod(size(sTo.labels)),
  % calculate frequency of each label in each node
  new_labels = {};
  new_freq = [];
  for j=1:length(sTo.labels{i}),
    if isempty(sTo.labels{i}{j}), % ignore
    elseif ~any(strcmp(sTo.labels{i}{j},new_labels)), % a new one!
       k = length(new_labels) + 1;
       new_labels{k} = sTo.labels{i}{j};
       new_freq(k) = sum(strcmp(new_labels{k},sTo.labels{i}));
    else, % an old one, ignore       
    end
  end

  if length(new_labels) > 0,
    % sort labels according to frequency
    [dummy order] = sort(1./(1+new_freq));
    new_labels = new_labels(order);
    new_freq = new_freq(order);

    switch mode,
    case 'freq', 
      % replace each label with 'label(#)' where # is the frequency
      for j=1:length(new_labels), 
        labf = sprintf('%s(%d)',new_labels{j},new_freq(j));
        new_labels{j} = labf;
      end
      sTo.labels{i} = new_labels;
    case 'vote',
      % place only the one with most votes 
      sTo.labels{i} = {new_labels{1}};
    end 
  end 
end

% convert back
if strcmp(to,'data'), sTo.labels = cellarray_to_data_labels(sTo.labels); end

return;


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% subfunctions

function caout = data_labels_to_cellarray(cm)

  [s,n] = size(cm); 
  caout = cell(s,1);
  for i=1:s, caout{i} = cm(i,:); end


function cmout = cellarray_to_data_labels(ca)

  cmout = cell(size(ca));
  for i=1:length(ca), cmout(i,1:length(ca{i})) = ca{i}; end



