% STD_CHECKSET - check STUDY set consistency
%
% Usage: >> [STUDY, ALLEEG] = std_checkset(STUDY, ALLEEG);
%
% Input:
%   STUDY      - EEGLAB STUDY set
%   ALLEEG     - vector of EEG datasets included in the STUDY structure
%
% Output:
%   STUDY      - a new STUDY set containing some or all of the datasets in ALLEEG,
%                plus additional information from the optional inputs above.
%   ALLEEG     - an EEGLAB vector of EEG sets included in the STUDY structure
%
% Authors:  Arnaud Delorme & Hilit Serby, SCCN, INC, UCSD, November 2005

% Copyright (C) Arnaud Delorme, SCCN, INC, UCSD, arno@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, ALLEEG, command] = std_checkset(STUDY, ALLEEG, options)

if nargin < 2
    help std_checkset;
    return;
end
command  = '';

if isempty(STUDY), return; end
studywasempty = 0;

modif = 0;
if ~isfield(STUDY, 'name'),  STUDY.name  = ''; modif = 1; end
if ~isfield(STUDY, 'task'),  STUDY.task  = ''; modif = 1; end
if ~isfield(STUDY, 'notes'), STUDY.notes = ''; modif = 1; end
if ~isfield(STUDY, 'filename'),  STUDY.filename  = ''; modif = 1; end
if ~isfield(STUDY, 'filepath'),  STUDY.filepath  = ''; modif = 1; end
if ~isfield(STUDY, 'history'),   STUDY.history   = ''; modif = 1; end
if ~isfield(STUDY, 'subject'),   STUDY.subject   = {}; modif = 1; end
if ~isfield(STUDY, 'group'),     STUDY.group     = {}; modif = 1; end
if ~isfield(STUDY, 'session'),   STUDY.session   = {}; modif = 1; end
if ~isfield(STUDY, 'run'),       STUDY.run       = {}; modif = 1; end
if ~isfield(STUDY, 'condition'), STUDY.condition = {}; modif = 1; end
if ~isfield(STUDY, 'etc'),       STUDY.etc       = []; modif = 1; end
if ~isfield(STUDY, 'cache'),     STUDY.cache     = []; modif = 1; end
if ~isfield(STUDY, 'etc.warnmemory'), STUDY.etc.warnmemory = 1; modif = 1; end
if ~isfield(STUDY, 'preclust'),  STUDY.preclust  = []; modif = 1; end
if ~isfield(STUDY, 'datasetinfo'), STUDY.datasetinfo = []; modif = 1; end
if ~isfield(STUDY.etc, 'version'), STUDY.etc.version = []; modif = 1; end
if ~isfield(STUDY.preclust, 'erpclusttimes' ),  STUDY.preclust.erpclusttimes = []; modif = 1; end
if ~isfield(STUDY.preclust, 'specclustfreqs' ), STUDY.preclust.specclustfreqs = []; modif = 1; end
if ~isfield(STUDY.preclust, 'erspclustfreqs' ), STUDY.preclust.erspclustfreqs = []; modif = 1; end
if ~isfield(STUDY.preclust, 'erspclusttimes' ), STUDY.preclust.erspclusttimes = []; modif = 1; end
if ~isfield(STUDY.datasetinfo, 'comps') && ~isempty(STUDY.datasetinfo), STUDY.datasetinfo(1).comps = []; modif = 1; end
if ~isfield(STUDY.datasetinfo, 'index') && ~isempty(STUDY.datasetinfo), STUDY.datasetinfo(1).index = []; modif = 1; end
if ~isfield(STUDY.datasetinfo, 'run') && ~isempty(STUDY.datasetinfo), STUDY.datasetinfo(1).run = []; modif = 1; end

% all summary fields
% ------------------
try, subject = unique_bc({ STUDY.datasetinfo.subject });
catch,
    subject = '';
    disp('Important warning: some datasets do not have subject codes; some functions may crash!');
end
try, group = unique_bc({ STUDY.datasetinfo.group });
catch,
    group = {};
    % disp('Important warning: some datasets do not have group codes; some functions may crash!');
end
try, condition = unique_bc({ STUDY.datasetinfo.condition });
catch,
    condition = {};
    disp('Important warning: some datasets do not have condition codes; some functions may crash!');
end
try, session = unique_bc([STUDY.datasetinfo.session]);
catch,
    session = '';
    % disp('Important warning: some datasets do not have session numbers; some functions may crash!');
end
try, run = unique_bc([STUDY.datasetinfo.run]);
catch,
    run = '';
    % disp('Important warning: some datasets do not have session numbers; some functions may crash!');
end
if ~isequal(STUDY.subject,   subject  ), STUDY.subject   = subject;   modif = 1; end
if ~isequal(STUDY.group,     group    ), STUDY.group     = group;     modif = 1; end
if ~isequal(STUDY.condition, condition), STUDY.condition = condition; modif = 1; end
if ~isequal(STUDY.session,   session  ), STUDY.session   = session;   modif = 1; end
if ~isequal(STUDY.run,       run      ), STUDY.run       = run;       modif = 1; end

% check dataset info consistency
% ------------------------------
for k = 1:length(STUDY.datasetinfo)
    if ~strcmpi(STUDY.datasetinfo(k).filename, ALLEEG(k).filename)
        STUDY.datasetinfo(k).filename = ALLEEG(k).filename; modif = 1;
        fprintf('Warning: file name has changed for dataset %d and the study has been updated\n', k);
        fprintf('         to discard this change in the study, reload it from disk\n');
    end
end

% recompute setind array (setind is deprecated but we keep it anyway)
% -------------------------------------------------------------------
setind  = [];
sameica = std_findsameica(ALLEEG);
for index = 1:length(sameica)
    setind(length(sameica{index}):-1:1,index) = sameica{index}';
end
setind(find(setind == 0)) = NaN;
if any(isnan(setind))
    warndlg('Warning: non-uniform set of dataset, some function might not work');
end

% check that dipfit is present in all datasets
% --------------------------------------------
for cc = 1:length(sameica)
    idat = [];
    if length(sameica{cc}) > 1
        for tmpi = 1:length(sameica{cc})
            if isfield(ALLEEG(sameica{cc}(tmpi)).dipfit, 'model')
                idat = sameica{cc}(tmpi);
            end
        end
        if ~isempty(idat)
            for tmpi = 1:length(sameica{cc})
                if ~isfield(ALLEEG(sameica{cc}(tmpi)).dipfit, 'model')
                    ALLEEG(sameica{cc}(tmpi)).dipfit = ALLEEG(idat).dipfit;
                    ALLEEG(sameica{cc}(tmpi)).saved  = 'no';
                    fprintf('Warning: no ICA dipoles for dataset %d, using dipoles from dataset %d (same ICA)\n', sameica{cc}(tmpi), idat);
                end
            end
        end
    end
end

% put in fake channels if channel labels are missing
% --------------------------------------------------
chanlabels = { ALLEEG.chanlocs };
if any(cellfun(@isempty, chanlabels))
    if any(~cellfun(@isempty, chanlabels))
        disp('********************************************************************');
        disp(' IMPORTANT WARNING: SOME DATASETS DO NOT HAVE CHANNEL LABELS AND ');
        disp(' SOME OTHERs HAVE CHANNEL LABELS. GENERATING CHANNEL LABELS FOR ');
        disp(' THE FORMER DATASETS (THIS SHOULD PROBABLY BE FIXED BY THE USER).');
        disp('********************************************************************');
    end
    disp('Generating channel labels for all datasets...');
    for currentind = 1:length(ALLEEG)
        for ind = 1:ALLEEG(currentind).nbchan
            ALLEEG(currentind).chanlocs(ind).labels = int2str(ind);
        end
    end
    ALLEEG(currentind).saved = 'no';
end

if length( unique( [ ALLEEG.srate ] )) > 1
    disp('********************************************************************');
    disp(' IMPORTANT WARNING: SOME DATASETS DO NOT HAVE THE SAME SAMPLING ');
    disp(' RATE AND THIS WILL MAKE MOST OF THE STUDY FUNCTIONS CRASH. THIS');
    disp(' SHOULD PROBABLY BE FIXED BY THE USER.');
    disp('********************************************************************');
end

% create STUDY design if it is not present
% ----------------------------------------
rebuild_design = 0;
if ~isfield(STUDY, 'cluster'), STUDY.cluster = []; modif = 1; end
if ~isfield(STUDY, 'changrp'), STUDY.changrp = []; modif = 1; end
if ~studywasempty
    if isfield(STUDY.datasetinfo, 'trialinfo')
        alltrialinfo = { STUDY.datasetinfo.trialinfo };
        if any(cellfun(@isempty, alltrialinfo)) && any(~cellfun(@isempty, alltrialinfo))
            disp('Rebuilding trial information structure for STUDY');
            STUDY  = std_maketrialinfo(STUDY, ALLEEG); % some dataset do not have trialinfo and
            % some other have it, remake it for everybody
        end
    elseif ALLEEG(1).trials > 1
        disp('Rebuilding trial information structure for STUDY');
        STUDY  = std_maketrialinfo(STUDY, ALLEEG); % some dataset do not have trialinfo and
    end
    if ~isfield(STUDY, 'design') || isempty(STUDY.design) || ~isfield(STUDY.design, 'name')
        STUDY  = std_maketrialinfo(STUDY, ALLEEG);
        STUDY  = std_makedesign(STUDY, ALLEEG);
        STUDY  = std_selectdesign(STUDY, ALLEEG,1);
        rebuild_design = 0;
    else
        if isfield(STUDY.design, 'indvar1')
            STUDY  = std_convertdesign(STUDY, ALLEEG);
        end
        
        % check independent variable
        setFields   = fieldnames(STUDY.datasetinfo);
        if isempty(ALLEEG(1).event)
             trialFields = [];
        else trialFields = fieldnames(ALLEEG(1).event);
        end
        rmInd       = [];
        for indDes = 1:length(STUDY.design)
            for indVar = 1:length(STUDY.design(indDes).variable)
                if isempty(strmatch( STUDY.design(indDes).variable(indVar).label, setFields)) && ...
                        ~isempty(trialFields) && ~isempty(STUDY.design(indDes).variable(indVar).label) && ...
                        isempty(strmatch( STUDY.design(indDes).variable(indVar).label, trialFields))

                    % Missing independent variable
                    if isempty(rmInd)
                        textVal1 = sprintf('The variable ''%s'' defined in the STUDY design is not found in ', STUDY.design(indDes).variable(indVar).label);
                        textVal2 = 'some of the EEG datasets. Some STUDY features will not be functional.';
                        if nargin > 2 && strcmpi(options, 'popup')
                            textVal = [ textVal1 10 textVal2 10 10 'Do you want to remove all designs with missing variables?' ];
                            res = questdlg2(  textVal, 'Issue with studies', 'No', 'Yes', 'Yes');
                            if strcmpi(res, 'Yes')
                                rmInd = [ rmInd indDes ];
                            end
                        else
                            disp([textVal1 textVal2]);
                        end
                    else
                        rmInd = [ rmInd indDes ];
                    end
                end
            end
        end
        if ~isempty(rmInd)
            STUDY.design(rmInd) = [];
        end

        % check cases
        for indDes = 1:length(STUDY.design)
            if ~isempty(setdiff(STUDY.design(indDes).cases.value, STUDY.subject))
                fprintf('Fixing STUDY design to account for removed subjects\n');
                STUDY.design(indDes).cases.value = intersect( STUDY.design(indDes).cases.value, STUDY.subject );
            end
        end
        
        % convert combined independent variable values
        % between dash to cell array of strings
        % -------------------------------------
        for inddes = 1:length(STUDY.design)
            rmVar = [];
            for indvar = 1:length(STUDY.design(inddes).variable)
                
                % add pairing info in case it is missing
                if isempty(STUDY.design(inddes).variable(indvar).label)
                    rmVar = [ rmVar indvar ];
                end
                if ~isfield(STUDY.design(inddes).variable, 'pairing') || isempty(STUDY.design(inddes).variable(indvar).pairing)
                    if strcmpi(STUDY.design(inddes).variable(indvar).label, 'group')
                        STUDY.design(inddes).variable(indvar).pairing = 'off';
                    else
                        STUDY.design(inddes).variable(indvar).pairing = 'on';
                    end
                end
                
                for indval = 1:length(STUDY.design(inddes).variable(indvar).value)
                    STUDY.design(inddes).variable(indvar).value{indval} = convertindvarval(STUDY.design(inddes).variable(indvar).value{indval});
                end
            end
            STUDY.design(inddes).variable(rmVar) = [];
            for indinclude = 1:length(STUDY.design(inddes).include)
                if iscell(STUDY.design(inddes).include{indinclude})
                    for indval = 1:length(STUDY.design(inddes).include{indinclude})
                        STUDY.design(inddes).include{indinclude}{indval} = convertindvarval(STUDY.design(inddes).include{indinclude}{indval});
                    end
                end
            end
        end
    end
    
    if rebuild_design % in case datasets have been added or removed
        STUDY = std_rebuilddesign(STUDY, ALLEEG);
    end
    
    % scan design to fix old pairing format
    % ------------------------------------
    for design = 1:length(STUDY.design)
        for var = 1:length(STUDY.design(design).variable)
            if ischar(STUDY.design(design).variable(var).pairing)
                if strcmpi(STUDY.design(design).variable(var).pairing, 'paired')
                    STUDY.design(design).variable(var).pairing = 'on';
                elseif strcmpi(STUDY.design(design).variable(var).pairing, 'unpaired')
                    STUDY.design(design).variable(var).pairing = 'off';
                end
            end
        end
    end
    
    % add filepath field if absent
    for ind = 1:length(STUDY.design)
        if ~isfield(STUDY.design, 'filepath') || (isnumeric(STUDY.design(ind).filepath) && isempty(STUDY.design(ind).filepath))
            STUDY.design(ind).filepath = '';
            STUDY.saved = 'no';
            modif = 1;
        end
    end
    
    % check for level field and add it if it not present
    if length(STUDY.design) > 0 && isfield(STUDY.design, 'variable')
        if ~isfield(STUDY.design(1).variable, 'level')
            STUDY = std_addvarlevel(STUDY);
        end
    end
    
    % check that ICA is present and if it is update STUDY.datasetinfo
    recreateclusters = 0;
    for index = 1:length(STUDY.datasetinfo)
        if max(STUDY.datasetinfo(index).comps) > size(ALLEEG(index).icaweights,1)
            STUDY.datasetinfo(index).comps = [1:size(ALLEEG(index).icaweights,1)];
            recreateclusters = 1;
            modif = 1;
        end
    end
    if recreateclusters
        fprintf('Recreating empty clusters because ICA has changed for some datasets\n');
        STUDY.cluster = [];
    end
    
    % make channel groups
    % -------------------
    STUDYTMP = std_changroup(STUDY, ALLEEG);
    if length(STUDYTMP.changrp) ~= length(STUDY.changrp)
        STUDY.changrp = STUDYTMP.changrp;
        modif = 1;
    end
    clear STUDYTMP;
end

% check cluster array
% -------------------
if isempty(STUDY.changrp) && isempty(STUDY.cluster)
    rebuild_design = 1;
end
if isfield(STUDY.cluster, 'sets'),
    if max(STUDY.cluster(1).sets(:)) > length(STUDY.datasetinfo)
        disp('Warning: Some datasets had been removed from the STUDY, clusters have been reinitialized');
        STUDY.cluster = []; modif = 1;
    else
    	if isempty(STUDY.cluster(1).sets)
            STUDY.cluster = []; modif = 1;
        end
    end
end
if ~studywasempty
    if isempty(STUDY.cluster)
        modif = 1;
        [STUDY] = std_createclust(STUDY, ALLEEG, 'parentcluster', 'on');
    end
    if length(STUDY.cluster(1).child) == length(STUDY.cluster)-1 && length(STUDY.cluster) > 1
        newchild = { STUDY.cluster(2:end).name };
        if ~isequal(STUDY.cluster(1).child, newchild)
            STUDY.cluster(1).child = newchild;
        end
    end
end

% adapt STUDY design to new framework
% -----------------------------------
if ~isempty(STUDY.design) && ~isfield(STUDY.design(1).variable, 'vartype')
    for inddes = 1:length(STUDY.design)
        for indvar = 1:length(STUDY.design(inddes).variable)
            STUDY.design(inddes).variable(indvar).vartype = 'categorical';
        end
    end
end
if ~isempty(STUDY.design) && isfield(STUDY.design(1), 'cell')
    STUDY.design = rmfield(STUDY.design, 'cell');
end

% determine if there has been any change
% --------------------------------------
if modif
    STUDY.saved = 'no';
    command = '[STUDY ALLEEG] = std_checkset(STUDY, ALLEEG);';
    addToHistory = true;
    % check duplicate
    if length(STUDY.history) >= length(command) && strcmpi(STUDY.history(end-length(command)+1:end), command)
        addToHistory = false;
    end
    if addToHistory
        STUDY.history =  sprintf('%s\n%s',  STUDY.history, command);
    end
end

% convert combined independent variables
% --------------------------------------
function val = convertindvarval(val)
if ischar(val)
    inddash = findstr(' - ', val);
    if isempty(inddash), return; end
    inddash = [ -2 inddash length(val)+1];
    for ind = 1:length(inddash)-1
        newval{ind} = val(inddash(ind)+3:inddash(ind+1)-1);
    end
    val = newval;
end


