% STD_CREATECLUST  - dreate a new empty cluster.  After creation, components 
%                      may be (re)assigned to it using STD_MOVECOMP.
% Usage:
%                    >> [STUDY] = std_createclust(STUDY, ALLEEG, 'key', val);
% Inputs:
%   STUDY    - STUDY set comprising some or all of the EEG datasets in ALLEEG.
%   ALLEEG   - vector of EEG datasets included in the STUDY, typically created 
%              using LOAD_ALLEEG.
%
% Optional inputs:
%   'name'     - ['string'] name of the new cluster {default: 'Cls #', where 
%                '#' is the next available cluster number}
%   'clusterind' - [integer] cluster for each of the component. Ex: 61 components 
%                and 2 clusters: 'clusterind' will be a 61x1 vector of 1 and
%                2 (and 0=outlisers)
%   'centroid' - centroid for clusters. If 2 clusters, size will be 2 x
%                width of the preclustering matrix. This is a deprecated 
%                functionality.
%   'algorithm' - [cell] algorithm parameters used to obtain the clusters
%   'parentcluster' - ['on'|'off'] use the parent cluster (cluster 1) to
%                 perform clustering (this cluster contains all the selected
%                 components by default). Otherwise, the cluster defined in
%                 STUDY.etc.preclust.clustlevel is used as parent.
%   
% Outputs:
%   STUDY    - the input STUDY set structure modified with the new cluster.
%
% Example: 
%   >> [STUDY] = std_createclust(STUDY, ALLEEG, 'name', 'eye_movements', ...
%                   'clusterind', [0 1 0 1 0 1], 'parentcluster', 'on');
%   % Create a new cluster named 'eye_movements' with components 2, 4, and
%   % of 6 the default parent cluster defined in 
%
%  See also  POP_CLUSTEDIT, STD_MOVECOMP
%
% Authors:  Hilit Serby, Arnaud Delorme, Scott Makeig, SCCN, INC, UCSD, June, 2005

% Copyright (C) Hilit Serby, SCCN, INC, UCSD, June 07, 2005, hilit@sccn.ucsd.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [STUDY] = std_createclust(STUDY, ALLEEG, varargin)

if nargin< 2
    help std_createclust;
    return;
end

% decoding options for backward compatibility
% -------------------------------------------
options = {};
if length(varargin) > 0 && ~ischar(varargin{1})
    % STUDY, IDX, algorithm, parentClusterNumber
    if isnumeric(ALLEEG)
        options = { options{:} 'clusterind' ALLEEG };
        if nargin > 3, options = { options{:} 'centroid'      varargin{1} }; end
        if nargin > 4, options = { options{:} 'algorithm'     varargin{2} }; end
        ALLEEG = [];
    end
elseif length(varargin) < 2
    options = { options{:} 'name' varargin{1} };
else
    options =  varargin;
end
opt = finputcheck(options, { 'name'             'string'   []  'Cls';
                             'clusterind'       'integer'  []  length(STUDY.cluster)+1;
                             'parentcluster'    'string'   { 'on','off' }  'off';
                             'algorithm'        'cell'     []  {};
                             'ignore0'          'string'   { 'on','off' }  'off';
                             'centroid'         'real'     []  [] }, 'std_createclust');
if ischar(opt), error(opt); end

% opt.clusterind - index of cluster for each component. Ex: 63 components and 2
% clusters: opt.clusterind will be a 61x1 vector of 1 and 2 (and 0=outlisers)
% C - centroid for clusters. If 2 clusters, size will be 2 x
%     width of the preclustering matrix

if strcmpi(opt.parentcluster, 'on')
    firstind = 1;
    cls      = 1;
    sameica  = std_findsameica(ALLEEG);
    sets     = [];
    comps    = [];
    STUDY.cluster = [];
    for index = 1:length(sameica)
        newcomps = STUDY.datasetinfo(sameica{index}(1)).comps;
        if isempty(newcomps), newcomps = [1:size(ALLEEG(sameica{index}(1)).icaweights,1)]; end
        comps = [ comps newcomps ];
        sets(length(sameica{index}):-1:1,end+1:end+length(newcomps)) = repmat( sameica{index}', [1 length(newcomps) ] );
    end
    sets(find(sets == 0))   = NaN;
    STUDY.cluster(1).name   = 'Parentcluster 1';
    STUDY.cluster(1).sets   = sets;
    STUDY.cluster(1).comps  = comps;
    STUDY.cluster(1).parent = {};
    STUDY.cluster(1).child  = {};
    STUDY.cluster.preclust.preclustparams = [];    
    STUDY.cluster.preclust.preclustdata   = []; 
else
    % Find the next available cluster index
    % -------------------------------------
    cls = min(max(opt.clusterind), length(unique(opt.clusterind)));
    nc  = 0; % index of last cluster
    for k =  1:length(STUDY.cluster)
        ti = strfind(STUDY.cluster(k).name, ' ');
        tmp = STUDY.cluster(k).name(ti(end) + 1:end);
        nc = max(nc,str2num(tmp));
        % check if there is a cluster of Notclust components
        if isfield(STUDY.etc, 'preclust') && isfield(STUDY.etc.preclust, 'preclustparams')
            if ~isempty(STUDY.cluster(k).parent)
                %strcmp(STUDY.cluster(k).parent,STUDY.cluster(STUDY.etc.preclust.clustlevel).name) 
                STUDY.cluster(k).preclust.preclustparams = STUDY.etc.preclust.preclustparams;
            end
        end
    end
    len = length(STUDY.cluster);

    if ~isempty(find(opt.clusterind==0)) && strcmpi(opt.ignore0, 'off') %outliers exist
        firstind = 0;
        nc  = nc + 1;
        len = len + 1;
    else
        firstind = 1;
    end

    % create clustlevel if it does not exist
    % --------------------------------------
    if ~isfield(STUDY.etc, 'preclust')
        STUDY.etc.preclust.clustlevel = 1;
        STUDY.etc.preclust.preclustdata = [];
    elseif ~isfield(STUDY.etc.preclust, 'clustlevel')
        STUDY.etc.preclust.clustlevel = 1;
        STUDY.etc.preclust.preclustdata = [];
    end
    
    % create all clusters
    % -------------------
    for k = firstind:cls 

        % cluster name
        % ------------
        if k == 0
             STUDY.cluster(len).name   = [ 'outlier ' num2str(k+nc)];
        else STUDY.cluster(k+len).name = [ opt.name ' ' num2str(k+nc)];
        end

        % find indices
        % ------------
        tmp = find(opt.clusterind==k); % opt.clust.erind contains the cluster index for each component
        STUDY.cluster(k+len).sets  = STUDY.cluster(STUDY.etc.preclust.clustlevel).sets(:,tmp);
        STUDY.cluster(k+len).comps = STUDY.cluster(STUDY.etc.preclust.clustlevel).comps(tmp);
        STUDY.cluster(k+len).algorithm = opt.algorithm;
        STUDY.cluster(k+len).parent{end+1} = STUDY.cluster(STUDY.etc.preclust.clustlevel).name;
        STUDY.cluster(k+len).child = [];
        if ~isempty(STUDY.etc.preclust.preclustdata) && all(tmp <= size(STUDY.etc.preclust.preclustdata,1))
             STUDY.cluster(k+len).preclust.preclustdata   = STUDY.etc.preclust.preclustdata(tmp,:);
             STUDY.cluster(k+len).preclust.preclustparams = STUDY.etc.preclust.preclustparams;
        else STUDY.cluster(k+len).preclust.preclustdata   = [];
        end

        %update parents clusters with cluster child indices
        % -------------------------------------------------
        STUDY.cluster(STUDY.etc.preclust.clustlevel).child{end+1} = STUDY.cluster(k+nc).name;
    end
end


% Find out the highst cluster id number (in cluster name), to find
% next available cluster index


% % find max cluster ID
% 
% max_id = 0;
% if ~isfield(STUDY, 'cluster'), STUDY.cluster = []; end
% for k = 1:length(STUDY.cluster)
%     ti = strfind(STUDY.cluster(k).name, ' ');
%     clus_id = STUDY.cluster(k).name(ti(end) + 1:end);
%     max_id = max(max_id, str2num(clus_id));
% end
% max_id = max_id + 1;
% opt.name = sprintf('%s %d', opt.name, max_id);
% clustind = length(STUDY.cluster)+1;
% % Initialize the new cluster fields.
% if length(STUDY.cluster) > 0
%     STUDY.cluster(clustind).parent{1} = STUDY.cluster(1).name;
%     if ~iscell(STUDY.cluster(1).child)
%          STUDY.cluster(1).child = { opt.name };
%     else STUDY.cluster(1).child = { STUDY.cluster(1).child{:} opt.name };
%     end
% else  
%     STUDY.cluster(clustind).parent{1} = 'manual'; % update parent cluster if exists.
% end
% STUDY.cluster(clustind).name = opt.name;
% STUDY.cluster(clustind).child = [];
% STUDY.cluster(clustind).comps = [];
% STUDY.cluster(clustind).sets = [];
% STUDY.cluster(clustind).algorithm = [];
% STUDY.cluster(clustind).centroid = [];
% STUDY.cluster(clustind).preclust.preclustparams = [];
% STUDY.cluster(clustind).preclust.preclustdata = [];
% 
% if (~isempty(opt.datasets) || ~isempty(opt.subjects)) && ~isempty(opt.components)
%     
%     % convert subjects to dataset indices
%     % -----------------------------------
%     if ~isempty(opt.subjects)
%         if length(opt.subjects) ~= length(opt.components)
%             error('If subjects are specified, the length of the cell array must be the same as for the components');
%         end
%         alls = { ALLEEG.subject };
%         for index = 1:length(opt.subjects)
%             tmpinds = strmatch(opt.subjects{index}, alls, 'exact');
%             if isempty(tmpinds)
%                 error('Cannot find subject');
%             end
%             opt.datasets(1:length(tmpinds),index) = tmpinds;
%         end
%         opt.datasets(opt.datasets(:) == 0) = NaN;
%     end
%     
%     % deal with cell array inputs
%     % ---------------------------
%     if iscell(opt.components)
%         newcomps = [];
%         newdats  = [];
%         for ind1 = 1:length(opt.components)
%             for ind2 = 1:length(opt.components{ind1})
%                 if iscell(opt.datasets)
%                      newdats  = [ newdats  opt.datasets{ind1}' ];
%                 else newdats  = [ newdats  opt.datasets(:,ind1) ];
%                 end
%                 newcomps = [ newcomps opt.components{ind1}(ind2) ];
%             end
%         end
%         opt.datasets   = newdats;
%         opt.components = newcomps;
%     end
%     
%     % create .sets, .comps, .setinds, .allinds fields
%     % -----------------------------------------------
%     [tmp setinds allinds] = std_setcomps2cell( STUDY, opt.datasets, opt.components);
%     STUDY.cluster(clustind).setinds = setinds;
%     STUDY.cluster(clustind).allinds = allinds;
%     STUDY.cluster(clustind) = std_cell2setcomps( STUDY, ALLEEG, clustind); 
%     STUDY.cluster(clustind) = std_setcomps2cell( STUDY, clustind);
%     %[ STUDY.cluster(finalinds(ind)) setinds allinds ] =
%         %std_setcomps2cell(STUDY, finalinds(ind));
% end
