classdef CoreCachedFileReader < handle
    % CoreCachedFileReader. A helper class to assist with reading a file
    %
    %
    %     Licence
    %     -------
    %     Part of CoreMat. https://github.com/tomdoel/coremat
    %     Author: Tom Doel, 2013.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    properties
        % The size of the text buffer to be read in. It is safe to change this
        % value while file reading is in progress
        MaxFileCacheSize = uint32(600000)
    end

    properties (Access = private)
        FileText
        FileId

        FilePointer
        FileCache
        SizeOfCurrentCache
        FlipEndian

        EofReached
    end

    methods
        function obj = CoreCachedFileReader(file_path, file_name, transfer_syntax, reporting)

            full_file_name = fullfile(file_path, file_name);

            computer_endian = CoreSystemUtilities.GetComputerEndian;
            obj.FlipEndian = (computer_endian ~= transfer_syntax.Endian);

            switch transfer_syntax.Endian
                case CoreEndian.BigEndian
                    file_encoding = 'b';
                case CoreEndian.LittleEndian
                    file_encoding = 'l';
                otherwise
                    error('Unknown file encoding');
            end

            switch transfer_syntax.CharacterEncoding
                case CoreCharacterEncoding.UTF8
                    character_encoding = 'UTF-8';
                otherwise
                    error('Unknown character encoding');
            end

            file_id = fopen(full_file_name, 'r', file_encoding, character_encoding);

            if (file_id == -1)
                reporting.Error('CoreCachedFileReader:CannotOpenFile', ['Unable to open file ' full_file_name]);
                obj.EofReached = true;
                obj.FileId = [];
            else
                obj.FileId = file_id;
                obj.EofReached = false;
                obj.ReadNextFileBlock;
            end
        end

        function data = ReadData(obj, data_type, number_of_bytes)
            data = ReadBytesFromCache(obj, number_of_bytes);
            data = typecast(data, data_type);
            if obj.FlipEndian
                data = swapbytes(data);
            end
        end

        function data = ReadString(obj, number_of_bytes)
            data = char(ReadBytesFromCache(obj, number_of_bytes));
        end

        function wrapper = ReadDataIntoWrapper(obj, data_type, number_of_bytes)
            wrapper = CoreWrapper;
            wrapper.RawImage = ReadBytesFromCache(obj, number_of_bytes);

            if strcmp(data_type, 'char')
                wrapper.RawImage = char(wrapper.RawImage);
            else
                wrapper.RawImage = typecast(wrapper.RawImage, data_type);
                if obj.FlipEndian
                    wrapper.RawImage = swapbytes(wrapper.RawImage);
                end
            end
        end

        function Close(obj)
            if ~isempty(obj.FileId)
                fclose(obj.FileId);
                obj.FileId = [];
            end
        end

        function delete(obj)
            obj.Close;
        end

        function more_data = MoreDataToRead(obj)
            more_data_in_cache = ~isempty(obj.FileCache) && (obj.FilePointer <= obj.SizeOfCurrentCache);
            more_data_to_read_from_disk = ~obj.EofReached;
            more_data = more_data_in_cache || more_data_to_read_from_disk;
        end

        function Skip(obj, number_of_bytes)
            bytes_left_to_read = uint32(number_of_bytes);
            bytes_left_in_cache = 1 + obj.SizeOfCurrentCache - obj.FilePointer;

            if bytes_left_in_cache >= bytes_left_to_read
                obj.FilePointer = obj.FilePointer + bytes_left_to_read;
            else

                while (bytes_left_to_read > 0) && (obj.MoreDataToRead)
                    bytes_left_in_cache = 1 + obj.SizeOfCurrentCache - obj.FilePointer;
                    next_bytes_read = min(bytes_left_in_cache, bytes_left_to_read);
                    bytes_left_to_read = bytes_left_to_read - next_bytes_read;
                    obj.FilePointer = obj.FilePointer + next_bytes_read;
                    if obj.FilePointer > obj.SizeOfCurrentCache
                        obj.ReadNextFileBlock;
                    end
                end

            end
        end
    end

    methods (Access = private)
        function data_bytes = ReadBytesFromCache(obj, number_of_bytes)
            bytes_left_to_read = uint32(number_of_bytes);
            bytes_left_in_cache = 1 + obj.SizeOfCurrentCache - obj.FilePointer;

            if bytes_left_in_cache >= bytes_left_to_read
                data_bytes = obj.FileCache(obj.FilePointer : obj.FilePointer + bytes_left_to_read - 1)';
                obj.FilePointer = obj.FilePointer + bytes_left_to_read;
            else
                data_bytes = zeros(1, number_of_bytes, 'uint8');
                data_bytes_pointer = uint32(1);

                while (bytes_left_to_read > 0) && (obj.MoreDataToRead)
                    bytes_left_in_cache = 1 + obj.SizeOfCurrentCache - obj.FilePointer;
                    next_bytes_read = min(bytes_left_in_cache, bytes_left_to_read);
                    data_bytes(data_bytes_pointer : data_bytes_pointer + next_bytes_read - 1) = obj.FileCache(obj.FilePointer : obj.FilePointer + next_bytes_read - 1);
                    data_bytes_pointer = data_bytes_pointer + next_bytes_read;
                    bytes_left_to_read = bytes_left_to_read - next_bytes_read;
                    obj.FilePointer = obj.FilePointer + next_bytes_read;
                    if obj.FilePointer > obj.SizeOfCurrentCache
                        obj.ReadNextFileBlock;
                    end
                end

                % If the end of the file has been reached, we may not have the full
                % number of bytes
                if bytes_left_to_read > 0
                    number_of_bytes_actually_read = number_of_bytes - bytes_left_to_read;
                    data_bytes = data_bytes(1 : number_of_bytes_actually_read);
                end
            end
        end

        function ReadNextFileBlock(obj)
            if obj.EofReached
                obj.FileCache = [];
            else
                obj.FileCache = fread(obj.FileId, obj.MaxFileCacheSize, 'uint8=>uint8');
                obj.SizeOfCurrentCache = uint32(numel(obj.FileCache));
                obj.FilePointer = uint32(1);
                if obj.SizeOfCurrentCache < obj.MaxFileCacheSize
                    obj.EofReached = true;
                    obj.Close;
                end
            end
        end
    end
end


function fn = tapas_physio_get_filename_from_id_philips(fileID, dirRaw, ext)
%searches for matching filename with fileID in dirRaw
%
%   output = get_filename_from_id(input)
%
% IN
%   fileID  e.g. 8
%   dirRaw  folder with raw files
%   ext     {'.nii'} file extension
% OUT
%
% EXAMPLE
%   get_filename_from_id
%
%   See also

% Author: Lars Kasper
% Created: 2013-11-04
% Copyright (C) 2013 Institute for Biomedical Engineering, ETH/Uni Zurich.

if nargin < 3
    ext = '.nii';
end

try
    fn = regexprep(regexprep(ls(fullfile(dirRaw ...
        ,['*_' num2str(fileID) '_1_*' ext])), [dirRaw filesep], ''),'\n','');
catch
    fn = regexprep(regexprep(ls(fullfile(dirRaw ...
        ,['*_' num2str(fileID) '_2_*' ext])), [dirRaw filesep], ''),'\n','');
end


classdef GroupClass < TreeNodeClass

    properties % (Access = private)
        version;
        subjs;
    end

    properties % (Access = private)
        outputFilename
        oldDerivedPaths
        derivedPathBidsCompliant
        initsaveflag
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Public methods
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    methods

        % ----------------------------------------------------------------------------------
        function obj = GroupClass(varargin)
            obj@TreeNodeClass(varargin);

            obj.InitVersion();
            obj.oldDerivedPaths = {obj.path, [obj.path, 'homerOutput']};
            obj.derivedPathBidsCompliant = 'derivatives/homer';
            obj.initsaveflag = false;

            obj.type    = 'group';
            obj.subjs   = SubjClass().empty;

            obj.outputFilename = obj.cfg.GetValue('Output File Name');
            if isempty(obj.outputFilename)
                obj.outputFilename = 'groupResults.mat';
            end

            if nargin==0
                return;
            end
            if nargin>0
                if ischar(varargin{1}) && strcmp(varargin{1},'copy')
                    return;
                elseif isa(varargin{1}, 'GroupClass')
                    obj.Copy(varargin{1});
                    return;
                end
                if isa(varargin{1}, 'FileClass')
                    obj.name = varargin{1}.ExtractNames();
                else
                    obj.name = varargin{1};
                end
            end
            if nargin>1
                obj.iGroup = varargin{2};
            end

            if isempty(obj.name)
                % Derive obj name from the name of the root directory
                curr_dir = pwd;
                k = sort([findstr(curr_dir,'/') findstr(curr_dir,'\')]); %#ok<*FSTR>
                obj.name = curr_dir(k(end)+1:end);
            end
        end

        % ----------------------------------------------------------------------------------
        function InitVersion(obj)
            obj.SetVersion(getVernum('DataTree'));
        end

        % ----------------------------------------------------------------------------------
        function SetVersion(obj, vernum)
            obj.version = vernum;
        end

        % ----------------------------------------------------------------------------------
        function vernum = GetVersion(obj)
            vernum = obj.version;
        end

        % ----------------------------------------------------------------------------------
        function filename = GetFilename(obj)
            filename = obj.outputFilename;
        end

        % ----------------------------------------------------------------------------------
        function res = CompareVersions(obj, obj2)
            v1 = versionstr2num(obj.version);
            v2 = versionstr2num(obj2.version);
            if v1 == v2
                res = 0;
            elseif v1 < v2
                res = 1;
            elseif v1 > v2
                res = -1;
            end

            % TBD: not sure how to handle this. For now just return 0
            res = 0;
        end

        % ----------------------------------------------------------------------------------
        % Groups obj1 and obj2 are considered equivalent if their names
        % are equivalent and their subject sets are equivalent.
        % ----------------------------------------------------------------------------------
        function B = equivalent(obj1, obj2)
            B=1;
            if ~strcmp(obj1.name, obj2.name)
                B=0;
                return;
            end
            for i=1:length(obj1.subjs)
                j = existSubj(obj1, i, obj2);
                if j==0 || (obj1.subjs(i) ~= obj2.subjs(j))
                    B=0;
                    return;
                end
            end
            for i=1:length(obj2.subjs)
                j = existSubj(obj2, i, obj1);
                if j==0 || (obj2.subjs(i) ~= obj1.subjs(j))
                    B=0;
                    return;
                end
            end
        end

        % ----------------------------------------------------------------------------------
        function Copy(obj, obj2, conditional)
            % Copy GroupClass object obj2 to GroupClass object obj. Conditional option applies
            % only to all the runs under this group. If == 'conditional' ONLY derived data,
            % that is, only from procStream but NOT from acquired data is copied for all the runs.
            %
            % Conversly unconditional copy copies all properties in the runs under this group
            if nargin==3 && strcmp(conditional, 'conditional')
                if obj.Mismatch(obj2)
                    return
                end
                for i = 1:length(obj.subjs)
                    j = obj.existSubj(i,obj2);
                    if j>0
                        obj.subjs(i).Copy(obj2.subjs(j), 'conditional');
                    elseif i<=length(obj2.subjs)
                        obj.subjs(i).Copy(obj2.subjs(i), 'conditional');
                    else
                        obj.subjs(i).Mismatch();
                    end
                end
                obj.Copy@TreeNodeClass(obj2, 'conditional');
            else
                for i=1:length(obj2.subjs)
                    obj.subjs(i) = SubjClass(obj2.subjs(i));
                end
                obj.Copy@TreeNodeClass(obj2);
            end
        end

        % --------------------------------------------------------------
        function CopyStims(obj, obj2)
            obj.CondNames = obj2.CondNames;
            for ii = 1:length(obj.subjs)
                obj.subjs(ii).CopyStims(obj2.subjs(ii));
            end
        end

        % ----------------------------------------------------------------------------------
        function CopyFcalls(obj, varargin)
            if isa(varargin{1},'TreeNodeClass')
                procStream  = varargin{1}.procStream;
                type        = varargin{1}.type;
            elseif isa(varargin{1},'ProcStreamClass')
                procStream  = varargin{1};
                type        = varargin{2};
            end

            % Copy default procStream function call chain to all uninitialized nodes
            % in the group
            switch(type)
                case 'group'
                    obj.procStream.CopyFcalls(procStream);
                case 'subj'
                    for jj = 1:length(obj.subjs)
                        obj.subjs(jj).procStream.CopyFcalls(procStream);
                    end
                case 'sess'
                    for ii = 1:length(obj.subjs)
                        for jj = 1:length(obj.subjs(ii).sess)
                            obj.subjs(ii).sess(jj).procStream.CopyFcalls(procStream);
                        end
                    end
                case 'run'
                    for ii = 1:length(obj.subjs)
                        for jj = 1:length(obj.subjs(ii).sess)
                            for kk = 1:length(obj.subjs(ii).sess(jj).runs)
                                obj.subjs(ii).sess(jj).runs(kk).procStream.CopyFcalls(procStream);
                            end
                        end
                    end
            end
        end

        % ----------------------------------------------------------------------------------
        function Add(obj, subj, sess, run)
            [~,f,e] = fileparts(subj.GetName());
            if strcmp(f, obj.name)
                msg{1} = sprintf('WARNING: The subject being added (%s) has the same name as the group (%s) containing it. ', [f,e], obj.name);
                msg{2} = sprintf('The subject names should not have the same name as the group folder, otherwise ');
                msg{3} = sprintf('it may cause incorrect results in processing.');
                obj.logger.Write('%s\n', [msg{:}]);
            end

            % Add subject to this group
            jj = 0;
            for ii = 1:length(obj.subjs)
                if strcmp(obj.subjs(ii).GetName(), subj.GetName())
                    jj=ii;
                    break;
                end
            end
            if jj==0
                jj = length(obj.subjs)+1;
                subj.SetIndexID(obj.iGroup, jj);
                subj.SetPath(obj.path);                      % Inherit root path from group
                obj.subjs(jj) = subj;
                obj.logger.Write('   Added subject  "%s"  to group  "%s" .\n', obj.subjs(jj).GetFileName, obj.GetFileName);
            end

            % Add sess to subj
            obj.subjs(jj).Add(sess, run);
            obj.children = obj.subjs;
        end

        % ----------------------------------------------------------------------------------
        function list = DepthFirstTraversalList(obj)
            list{1} = obj;
            for ii=1:length(obj.subjs)
                list = [list; obj.subjs(ii).DepthFirstTraversalList()];
            end
        end

        % #########################################################################

        % -----------------------------------------------------------------------------
        function [g, s, e, r] = GetInitialFuncCallChain(obj)
            g = obj;
            s = obj.subjs(1);
            e = obj.subjs(1).sess(1);
            r = obj.subjs(1).sess(1).runs(1);
            for ii = 1:length(obj.subjs)
                if ~obj.subjs(ii).procStream.IsEmpty()
                    s = obj.subjs(ii);
                end
                for jj = 1:length(obj.subjs(ii).sess)
                    if ~obj.subjs(ii).sess(jj).procStream.IsEmpty()
                        e = obj.subjs(ii).sess(jj);
                    end
                    for kk = 1:length(obj.subjs(ii).sess(jj).runs)
                        if ~obj.subjs(ii).sess(jj).runs(kk).procStream.IsEmpty()
                            r = obj.subjs(ii).sess(jj).runs(kk);
                        end
                    end
                end
            end

            % Generate procStream defaults at each level with which to initialize
            % any uninitialized procStream.input
            g.CreateProcStreamDefault();
        end

        % ----------------------------------------------------------------------------------
        function [fnameFull, status] = InitProcStreamLevel(obj, g, o, fnameFull)
            status = 0;

            procStreamDefault = o.GetProcStreamDefault();

            % If any of the tree nodes still have unintialized procStream input, ask
            % user for a config file to load it from
            if o.procStream.IsEmpty()

                if ~ispathvalid(fnameFull)
                    [fnameFull, autoGenDefaultFile] = g.procStream.GetConfigFileName(fnameFull, obj.path);
                else
                    autoGenDefaultFile = false;
                end

                % If user did not provide procStream config filename and file does not exist
                % then create a config file with the default contents
                if ~exist(fnameFull, 'file')
                    procStreamDefault.SaveConfigFile(fnameFull, o.type);
                end

                obj.logger.Write('Attempting to load %s-level proc stream from %s\n', o.type, fnameFull);

                % Load file to the first empty procStream in the dataTree at each processing level
                err = o.LoadProcStreamConfigFile(fnameFull);

                % If proc stream input is still empty it means the loaded config
                % did not have valid proc stream input. If that's the case we
                % Load a default proc stream input
                if err ~= 0
                    [~, fname, ext] = fileparts(fnameFull);
                    msg{1} = sprintf('Some functions at the %s-level failed to load from selected proc stream config file,  "%s".  ', o.type, [fname, ext]);
                    msg{2} = sprintf('The functions may be obsolete or contain errors.  Loading default %s proc stream ...\n', o.type);
                    obj.logger.Write([msg{:}]);
                    g.CopyFcalls(procStreamDefault, o.type);
                    status = 1;

                % Otherwise the non-default processing stream loaded from file to this group and to first subject
                % disseminate it to all subjects and all runs in this group
                else

                    obj.logger.Write('Loading proc stream from %s\n', fnameFull);
                    g.CopyFcalls(o.procStream, o.type);

                end
                obj.initsaveflag = true;

            end
        end

        % ----------------------------------------------------------------------------------
        function ErrorCheckInitErr(obj, procStreamCfgFile, status);
            if ~all(status==0)
                [~, fname, ext] = fileparts(procStreamCfgFile);
                levels = '';
                if status(1)~=0
                    levels = 'group';
                end
                if status(2)~=0
                    if isempty(levels)
                        levels = 'subject';
                    else
                        levels = [levels, ', subject'];
                    end
                end
                if status(3)~=0
                    if isempty(levels)
                        levels = 'session';
                    else
                        levels = [levels, ', session'];
                    end
                end
                if status(4)~=0
                    if isempty(levels)
                        levels = 'run';
                    else
                        levels = [levels, ', run'];
                    end
                end
                k = find(levels == ',');
                if ~isempty(k)
                    levels = sprintf('%s and %s levels', levels(1:k-1), levels(k+2:end));
                    procStreamLabelPlural = 'streams';
                else
                    levels = sprintf('%s level', levels);
                    procStreamLabelPlural = 'stream';
                end
                msg{1} = sprintf('\nWARNING: There were errors loading user functions from "%s" at the %s.\n', [fname, ext], levels);
                msg{2} = sprintf('These functions may have changed since this file was created or have errors in the help\n');
                msg{3} = sprintf('sections of the processing stream description. Replacing %s processing\n', levels);
                msg{4} = sprintf('%s with default processing %s ... \n', procStreamLabelPlural, procStreamLabelPlural);
                % if strcmpi(obj.cfg.GetValue('Include Archived User Functions'), 'No')
                %       MenuBox(msg, {'OK'});
                % end
                obj.logger.Write([msg{:}]);
            end
        end

        % ----------------------------------------------------------------------------------
        function InitProcStream(obj, procStreamCfgFile, options)
            if isempty(obj)
                return;
            end
            if ~exist('procStreamCfgFile','var')
                procStreamCfgFile = '';
            end
            if ~exist('options','var')
                options = '';
            end

            if optionExists(options, 'noloadconfig')
            	return
            end

            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            % Find out if we need to ask user for processing options
            % config file to initialize procStream.fcalls at the
            % run, subject or group level. First try to find the proc
            % input at each level from the saved derived data.
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            [g, s, e, r] = obj.GetInitialFuncCallChain();

            %
            [procStreamCfgFile, status(1)] = obj.InitProcStreamLevel(g, g, procStreamCfgFile);
            [procStreamCfgFile, status(2)] = obj.InitProcStreamLevel(g, s, procStreamCfgFile);
            [procStreamCfgFile, status(3)] = obj.InitProcStreamLevel(g, e, procStreamCfgFile);
            [~,                 status(4)] = obj.InitProcStreamLevel(g, r, procStreamCfgFile);

            obj.ErrorCheckInitErr(procStreamCfgFile, status);
        end

        % ---------------------------------------------------------------
        function PrintProcStream(obj)
            fcalls = obj.procStream.GetFuncCallChain();
            obj.logger.Write('Group processing stream:\n');
            for ii = 1:length(fcalls)
                obj.logger.Write('%s\n', fcalls{ii});
            end
            obj.logger.Write('\n');
            obj.subjs(1).PrintProcStream();
        end

       % ----------------------------------------------------------------------------------
        function FreeMemoryRecursive(obj)
            if isempty(obj)
                return
            end
            for ii = 1:length(obj.subjs)
                obj.subjs(ii).FreeMemoryRecursive();
            end
            obj.FreeMemory();
        end

        % ----------------------------------------------------------------------------------
        function LoadRecursive(obj)
            if isempty(obj)
                return
            end
            for ii = 1:length(obj.subjs)
                obj.subjs(ii).LoadRecursive();
            end
            obj.Load();
        end

        % ----------------------------------------------------------------------------------
        function LoadInputVars(obj, tHRF_common)
            obj.inputVars = [];
            for iSubj = 1:length(obj.subjs)
            % Set common tHRF: make sure size of tHRF, dcAvg and dcAvg is same for
            % all subjects. Use smallest tHRF as the common one.
                obj.subjs(iSubj).procStream.output.SettHRFCommon(tHRF_common, obj.subjs(iSubj).name, obj.subjs(iSubj).type);

                obj.inputVars.dodAvgSubjs{obj.subjs(iSubj).iSubj}    = obj.subjs(iSubj).procStream.output.GetVar('dodAvg');
                obj.inputVars.dodAvgStdSubjs{obj.subjs(iSubj).iSubj} = obj.subjs(iSubj).procStream.output.GetVar('dodAvgStd');
                obj.inputVars.dcAvgSubjs{obj.subjs(iSubj).iSubj}     = obj.subjs(iSubj).procStream.output.GetVar('dcAvg');
                obj.inputVars.dcAvgStdSubjs{obj.subjs(iSubj).iSubj}  = obj.subjs(iSubj).procStream.output.GetVar('dcAvgStd');
                obj.inputVars.tHRFSubjs{obj.subjs(iSubj).iSubj}      = obj.subjs(iSubj).procStream.output.GetTHRF();
                obj.inputVars.nTrialsSubjs{obj.subjs(iSubj).iSubj}   = obj.subjs(iSubj).procStream.output.GetVar('nTrials');

                obj.subjs(iSubj).FreeMemory();
        end
        end

        % ----------------------------------------------------------------------------------
        function Calc(obj, options)
            if ~exist('options','var') || isempty(options)
                options = 'overwrite';
            end

            if strcmpi(options, 'overwrite')
                % Recalculating result means deleting old results, if
                % option == 'overwrite'
                obj.procStream.output.Flush();
            end
            if obj.DEBUG
                obj.logger.Write('Calculating processing stream for group %d\n', obj.iGroup)
            end

            % Calculate all subjs in this session
            tHRF_common = {};
            for iSubj = 1:length(obj.subjs)
                obj.subjs(iSubj).Calc();

                % Find smallest tHRF among the subjs and make this the common one.
                tHRF_common = obj.subjs(iSubj).procStream.output.GeneratetHRFCommon(tHRF_common);
            end

            % Update call application GUI using it's generic Update function
            if ~isempty(obj.updateParentGui)
                obj.updateParentGui('DataTreeClass', [obj.iGroup, obj.iSubj, obj.iSess, obj.iRun]);
            end

            % Load all the output valiraibles that might be needed by procStream.Calc() to calculate proc stream for this group
            obj.LoadInputVars(tHRF_common);

            Calc@TreeNodeClass(obj);

            if obj.DEBUG
                obj.logger.Write('Completed processing stream for group %d\n', obj.iGroup);
                obj.logger.Write('\n');
            end

        end

        % ----------------------------------------------------------------------------------
        function Print(obj, indent)
            obj.logger.Write('\n');
            if ~exist('indent', 'var')
                indent = 0;
            end
            Print@TreeNodeClass(obj, indent);
            for ii = 1:length(obj.subjs)
                obj.subjs(ii).Print(indent);
            end
        end

        % ----------------------------------------------------------------------------------
        % Deletes derived data in procStream.output
        % ----------------------------------------------------------------------------------
        function Reset(obj, option)
            if ~exist('option','var')
                option = 'down';
            end
            if exist([obj.path, obj.outputDirname, obj.outputFilename],'file')
                delete([obj.path, obj.outputDirname, obj.outputFilename]);
            end
            if strcmp(option, 'down')
                for jj = 1:length(obj.subjs)
                    obj.subjs(jj).Reset();
                end
            end
            Reset@TreeNodeClass(obj);
        end

        % ----------------------------------------------------------------------------------
        function b = IsEmpty(obj)
            b = true;
            if isempty(obj)
                return;
            end
            for ii = 1:length(obj.subjs)
                if ~obj.subjs(ii).IsEmpty()
                    b = false;
                    break;
                end
            end
        end

        % ----------------------------------------------------------------------------------
        function b = IsEmptyOutput(obj)
            b = true;
            if isempty(obj)
                return;
            end
            for ii = 1:length(obj.subjs)
                if ~obj.subjs(ii).IsEmptyOutput()
                    b = false;
                    break;
                end
            end
        end

    end   % Public methods

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Public Save/Load methods
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    methods

        % ----------------------------------------------------------------------------------
        function nbytes = MemoryRequired(obj)
            nbytes = 0;
            for ii = 1:length(obj.subjs)
                nbytes = nbytes + obj.subjs(ii).MemoryRequired();
            end
            nbytes = nbytes + obj.procStream.MemoryRequired();
        end

        % ----------------------------------------------------------------------------------
        function err = LoadSubBranch(obj)
            err = -1;
            if isempty(obj)
                return;
            end
            err1 = obj.procStream.Load([obj.path, obj.GetOutputFilename()]);
            err2 = obj.subjs(1).LoadSubBranch();
            if err1==0 && err2==0
                err = 0;
            end
        end

        % ----------------------------------------------------------------------------------
        function FreeMemorySubBranch(obj)
            if isempty(obj)
                return;
            end
            obj.subjs(1).FreeMemorySubBranch()
        end

        % ----------------------------------------------------------------------------------
        function err = Load(obj, options)
            err = -1;
            if isempty(obj)
                return;
            end
            if ~exist('options','var')
                options = '';
            end

            % If this group has been loaded, then no need to go through the whole Load function. Instead
            % default to the generic TreeNodeClass.Load method.
            if ~optionExists(options, {'init','reload'})
                err = obj.Load@TreeNodeClass();
                return;
            end

            obj.BackwardCompatability();

            group = [];
            if ispathvalid([obj.path, obj.outputDirname, obj.outputFilename],'file')
                g = load([obj.path, obj.outputDirname, obj.outputFilename]);

                % Do some basic error checks on saved derived data contents
                if isproperty(g, 'group') && isa(g.group, 'GroupClass')
                    if isproperty(g.group, 'version')
                        if ismethod(g.group, 'GetVersion')
                            % obj.logger.Write('Saved group data, version %s exists\n', g.group.GetVersionStr());
                            group = g.group;
                        end
                    end
                end
            end

            % Copy saved group to current group if versions are compatible. obj.CompareVersions==0
            % means the versions of the saved group and current one are equal.
            if ~isempty(group) && obj.CompareVersions(group) >= 0
                % Do a conditional copy of group from saved processing output file. Conditional copy copies ONLY
                % derived data, that is, only from procStream but NOT acqruired. We do not want to
                % overwrite the real acquired data loaded from acquisition files
                hwait = waitbar(0,'Loading group');
                obj.Copy(group, 'conditional');
                close(hwait);
            else
                obj.initsaveflag = true;
            end
            err = 0;
        end

        % ----------------------------------------------------------------------------------
        function Save(obj, hwait)
            if ~exist('hwait','var')
                hwait = [];
            end
            if obj.initsaveflag == false
                obj.initsaveflag = true;
                return
            end

            obj.logger.Write('Saving processed data in %s\n', [obj.path, obj.outputDirname, obj.outputFilename]);

            if ishandle(hwait)
                obj.logger.Write('Auto-saving processing results ...\n', obj.logger.ProgressBar(), hwait);
            end

            group = GroupClass(obj);
            try
                obj.CreateOutputDir();
                save([obj.pathOutputAlt, obj.outputDirname, obj.outputFilename], 'group');
            catch ME
                MessageBox(ME.message);
                obj.logger.Write(ME.message);
            end
            obj.initsaveflag = true;
        end

        % ----------------------------------------------------------------------------------
        function CreateOutputDir(obj)
            if ispathvalid([obj.pathOutputAlt, obj.outputDirname])
                return;
            end
            mkdir([obj.pathOutputAlt, obj.outputDirname]);
            for ii = 1:length(obj.subjs)
                obj.subjs(ii).CreateOutputDir();
            end
        end

        % ----------------------------------------------------------------------------------
        function SaveAcquiredData(obj)
            for ii = 1:length(obj.subjs)
                obj.subjs(ii).SaveAcquiredData();
            end
        end

        % ----------------------------------------------------------------------------------
        function b = AcquiredDataModified(obj)
            b = false;
            for ii = 1:length(obj.subjs)
                if obj.subjs(ii).AcquiredDataModified()
                    b = true;
                end
            end
        end

        % ----------------------------------------------------------------------------------
        function varval = GetVar(obj, varname)
            % First call the common code for all levels
            varval = obj.GetVar@TreeNodeClass(varname);

            % Now call the group specific part
            if isempty(varval)
                varval = obj.subjs(1).GetVar(varname);
            end
        end

    end  % Public Save/Load methods

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Public Set/Get methods
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    methods

        % ----------------------------------------------------------------------------------
        function probe = GetProbe(obj)
            probe = obj.subjs(1).GetProbe();
        end

        % ----------------------------------------------------------------------------------
        function SD = GetSDG(obj,option)
            if exist('option','var')
                SD = obj.subjs(1).GetSDG(option);
            else
                SD = obj.subjs(1).GetSDG();
            end
        end

        % ----------------------------------------------------------------------------------
        function bbox = GetSdgBbox(obj)
            bbox = obj.subjs(1).GetSdgBbox();
        end

        % ----------------------------------------------------------------------------------
        function wls = GetWls(obj)
            wls = obj.subjs(1).GetWls();
        end

        % ----------------------------------------------------------------------------------
        function [iDataBlks, ich] = GetDataBlocksIdxs(obj, ich)
            if nargin<2
                ich = [];
            end
            [iDataBlks, ich] = obj.subjs(1).GetDataBlocksIdxs(ich);
        end

        % ----------------------------------------------------------------------------------
        function n = GetDataBlocksNum(obj)
            n = obj.subjs(1).GetDataBlocksNum();
        end

        % ----------------------------------------------------------------------------------
        function aux = GetAuxiliary(obj) %#ok<MANU>
            aux = [];
        end

    end      % Public Set/Get methods

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Conditions related methods
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    methods

        % ----------------------------------------------------------------------------------
        function SetConditions(obj)
            if isempty(obj)
                return;
            end

            % First get global et of conditions across all runs and
            % subjects
            CondNames = {};
            for ii=1:length(obj.subjs)
                obj.subjs(ii).SetConditions();
                CondNames = [CondNames, obj.subjs(ii).GetConditions()];
            end
            obj.CondNames    = unique(CondNames);

            % Now that we have all conditions, set the conditions across
            % the whole group to these
            for ii=1:length(obj.subjs)
                obj.subjs(ii).SetConditions(obj.CondNames);
            end
        end

        % ----------------------------------------------------------------------------------
        function [fn_error, missing_args, prereqs] = CheckProcStreamOrder(obj)
            missing_args = {};
            fn_error = 0;
            prereqs = '';
            for i = 1:length(obj.subjs)
                [fn_error, missing_args, prereqs] = obj.subjs(i).CheckProcStreamOrder;
                if ~isempty(missing_args)
                    return
                end
            end
        end

        % ----------------------------------------------------------------------------------
        function CondNames = GetConditionsActive(obj)
            CondNames = obj.CondNames;
            for ii=1:length(obj.subjs)
                CondNamesSubj = obj.subjs(ii).GetConditionsActive();
                for jj=1:length(CondNames)
                    k = find(strcmp(['-- ', CondNames{jj}], CondNamesSubj));
                    if ~isempty(k)
                        CondNames{jj} = ['-- ', CondNames{jj}];
                    end
                end
            end
        end

    end

    methods

        % ----------------------------------------------------------------------------------
        function r = ListOutputFilenames(obj, options)
            if ~exist('options','var')
                options = '';
            end
            r = obj.GetOutputFilename(options);
            fprintf('%s %s\n', obj.path, r);
            for ii = 1:length(obj.subjs)
                obj.subjs(ii).ListOutputFilenames(options);
            end
        end

        % ---------------------------------------------------------------
        function CleanUpOutput(obj, filesObsolete)
            for jj = 1:length(filesObsolete)
                renameFlag = false;
                for ii = 1:length(filesObsolete(jj).files)
                    if isempty(filesObsolete(jj).files(ii).namePrev)
                        continue;
                    end
                    renameFlag = true;
                end

                % If something changed in the folder structure
                if renameFlag
                    msg{1} = sprintf('Previous Homer3 processing output exists but is now inconsistent with the current ');
                    msg{2} = sprintf('data files. This output should be regenerated in the new Homer3 session to reflect the new file/folder names. ');
                    msg{3} = sprintf('The existing Homer processing output will be moved to %s. Is this okay?', obj.GetArchivedOutputDirname());
                    q = MenuBox(msg, {'YES','NO'});
                    if q==1
                        if isempty(obj.outputDirname)
                            movefile('*.mat', obj.GetArchivedOutputDirname())
                            movefile('*.txt', obj.GetArchivedOutputDirname())
                        else
                            movefile(obj.outputDirname, obj.GetArchivedOutputDirname())
                        end
                        obj.Save();
                    end
                end
            end
        end

        % -----------------------------------------------------------------
        function name = GetArchivedOutputDirname(obj)
            n = 1;
            addon = '_old';
            if isempty(obj.outputDirname)
                base = 'homerOutput';
            else
                base = filesepStandard(obj.outputDirname, 'file');
            end
            name = sprintf('%s%s%d', base, addon, n);
            while ispathvalid(name)
                n = n+1;
                name = sprintf('%s%s%d', base, addon, n);
            end
        end

        % --------------------------------------------------------------------------
        function ApplyParamEditsToAllSubjects(obj, iFcall, iParam, val)
            for jj = 1:length(obj.subjs)
                obj.subjs(jj).procStream.EditParam(iFcall, iParam, val);
            end
        end

        % --------------------------------------------------------------------------
        function ApplyParamEditsToAllSessions(obj, iFcall, iParam, val)
            for jj = 1:length(obj.subjs)
                obj.subjs(jj).ApplyParamEditsToAllSessions(iFcall, iParam, val);
            end
        end

        % --------------------------------------------------------------------------
        function ApplyParamEditsToAllRuns(obj, iFcall, iParam, val)
            for jj = 1:length(obj.subjs)
                obj.subjs(jj).ApplyParamEditsToAllRuns(iFcall, iParam, val);
            end
        end

    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Private methods
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    methods (Access = public)

        % ----------------------------------------------------------------------------------
        % Check whether subject k'th subject from this group exists in group G and return
        % its index in G if it does exist. Else return 0.
        % ----------------------------------------------------------------------------------
        function j = existSubj(obj, k, G)
            j=0;
            for i=1:length(G.subjs)
                if strcmp(obj.subjs(k).name, G.subjs(i).name)
                    j=i;
                    break;
                end
            end
        end

        % ----------------------------------------------------------------------------------
        function BackwardCompatability(obj)
            for jj = 1:length(obj.oldDerivedPaths)
                oldDerivedPath = filesepStandard(obj.oldDerivedPaths{jj});
                if ispathvalid([oldDerivedPath, 'groupResults.mat'])
                    try
                        g = load([oldDerivedPath, 'groupResults.mat']);
                    catch
                        g = [];
                    end

                    % Do not try to restore old data older than Homer3
                    if isempty(g)
                        return;
                    end
                    if ~isproperty(g,'group')
                        return;
                    end
                    if ~isa(g.group, 'GroupClass')
                        return;
                    end

                    % Do not try to restore old data if there is already data
                    % in the new format
                    if obj.HaveOutput()
                        return;
                    end

                    oldDerivedPathRel = pathsubtract_startup(oldDerivedPath, obj.path);
                    if isempty(oldDerivedPathRel)
                        return
                    end
                    msg{1} = sprintf('Detected derived data in older Homer3 folder "%s" ', oldDerivedPathRel);
                    if pathscompare(obj.derivedPathBidsCompliant, obj.outputDirname, 'nameonly')
                        msg{2} = sprintf('The current derived output folder, "%s", is BIDS compliant. ', ...
                            filesepStandard(obj.derivedPathBidsCompliant, 'filesepwide:nameonly'));
                    else
                        msg{2} = '.';
                    end
                    msg = [msg{:}];
                    obj.logger.Write('Backward Compatability:   %s\n', msg);

                    % If we're here it means that old format homer3 data exists
                    % AND NO new homer3 format data exists
                    q = MenuBox(sprintf('%s Do you want to move %s to the new folder?', msg, oldDerivedPathRel), {'Yes','No'});
                    if q==1
                        if ispathvalid([obj.path, obj.outputDirname])
                            try
                                rmdir([obj.path, obj.outputDirname], 's')
                            catch
                                MenuBox(sprintf('ERROR:  Could not remove new derived folder'), 'OK');
                                return
                            end
                        end
                        obj.logger.Write('Moving %s to %s\n', oldDerivedPath, [obj.path, obj.outputDirname]);
                        if ~ispathvalid([obj.path, obj.outputDirname])
                            mkdir([obj.path, obj.outputDirname]);
                        end

                        try
                            movefile(oldDerivedPath, [obj.path, obj.outputDirname])
                        catch
                        end

                        if ispathvalid([obj.path, obj.outputDirname, obj.outputFilename])
                            if ~strcmp(obj.outputFilename, 'groupResults.mat')
                                obj.logger.Write('Moving %s to %s\n', [obj.path, obj.outputDirname, 'groupResults.mat'], ...
                                    [obj.path, obj.outputDirname, obj.outputFilename])
                                movefile([obj.path, obj.outputDirname, 'groupResults.mat'], [obj.path, obj.outputDirname, obj.outputFilename])
                            end
                        end
                    end
                    break
                end

            end
        end

    end  % Private methods

end % classdef GroupClass < TreeNodeClass


function lockfiles = check_for_lock_files(results_directory)
%Uses the unix find command to see if there are any lock files
%(directories which end in ".lock") inside the directory specified
%by results_directory
%
%Returns a cell array of files, potentially of length 0
%Tomasz Malisiewicz (tomasz@csail.mit.edu)

[a,b] = unix(sprintf('find %s -name "*.lock"',results_directory));
if a==1 || length(b) == 0
  lockfiles = {};
else
  b=textscan(b,'%s');
  lockfiles = b{1};
end


function result = arg_report(type,func,args)
% Report information of a certain Type about the given Function.
% Result = arg_report(Type,Function,Arguments)
%
% Functions that declare their arguments via arg_define() make their parameter specification
% accessible to outside functions. This can be used to display auto-generated settings dialogs, to
% record function calls, and so on. Some other functions can enable reports, as well (like
% declare_properties() and expose_handles()).
%
% In:
%   Type : Type of information to report. The currently defined report types are as follows:
%
%          'vals' : Report the values of the function's arguments as a struct, possibly with
%                   sub-structs, after assignment of Arguments. (provided by arg_define)
%          'nvps' : Report the values of the function's arguments as cell array of name-value pairs.
%                   (provided by arg_define)
%          'lean' : Report a lean specification of the function's arguments as a struct array, with
%                   fields as in arg_specifier, including help text, etc. This is after assignment
%                   of Arguments. (provided by arg_define)
%          'rich' : Report a rich specification of the function's arguments as a struct array, with
%                   fields as in arg_specifier. In addition to lean this includes information about
%                   alternative (non-default) settings, for use in GUI generation. (provided by
%                   arg_define)
%
%          'properties' : Report declared properties of the function, if any. Arguments must be empty.
%                         (provided by declare_properties)
%
%          'handle': Report function handles to scoped and nested functions within the Function. The
%                    names of those functions are given as a cell array in Arguments, and the result
%                    is a cell array of associated function handles (or one handle if only one
%                    function was requested).
%
%   Function : Handle to a function that supports the given report type.
%
%   Arguments : Cell array of inputs to be passed to the function.
%
% Out:
%   Result : the reported data.
%
% Examples:
%   % for a function call with some arguments assigned, obtain a struct with all parameter
%   % names and values, including defaults
%   params = arg_report('vals',@myfunction,{4,10,true,'option1','xxx','option5',10})
%
%   % obtain a specification of all function arguments, with defaults, help text, type, shape, and other
%   % meta-data (with a subset of settings customized according to arguments)
%   spec = arg_report('rich',@myfunction,myarguments)
%
%   % obtain a report of properties of the function (declared via declared_properties() within the
%   % function)
%   props = arg_report('properties',@myfunction)
%
% See also:
%   arg_define, declare_properties, expose_handles
%
%                                Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2010-09-24

% Copyright (C) Christian Kothe, SCCN, 2010, christian@sccn.ucsd.edu
%
% This program is free software; you can redistribute it and/or modify it under the terms of the GNU
% General Public License as published by the Free Software Foundation; either version 2 of the
% License, or (at your option) any later version.
%
% This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
% even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
% General Public License for more details.
%
% You should have received a copy of the GNU General Public License along with this program; if not,
% write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
% USA

% check inputs
if ischar(func)
    func = str2func(func); end
if ~isa(func,'function_handle')
    error('The given Function argument must be a function handle.'); end
if ~ischar(type)
    error('The given Type argument must be a string.'); end
if nargin < 3
    if strcmp(type,'properties')
        % for the properties report we implicitly pad the arguments with blanks to allow functions
        % to define up to this number of traditional non-varargin arguments prior to the varargin
        args(1:15) = {[]};
    else
        args = {};
    end
elseif isequal(args,[])
    args = {};
elseif ~iscell(args)
    error('Arguments must be a cell array, if given.');
end

% disable the expression features of functions called by arg_report
persistent handle_expressions;
if isempty(handle_expressions)
    handle_expressions = exist('exp_eval','file'); end

result = {};
try
    % evaluate the funtion with two special arguments appended
    if handle_expressions
        hlp_scope({'disable_expressions',1},func,args{:},'__arg_report__',type);
    else
        func(args{:},'__arg_report__',type);
    end
catch report
    if strcmp(report.identifier,'BCILAB:arg:report_args')
        global tracking; %#ok<TLEV>
        % get the ticket of the report
        ticket = sscanf(report.message(end-4:end),'%u');
        % read out the payload and return the ticket
        result = tracking.arg_sys.reports{ticket};
        tracking.arg_sys.tickets.addLast(ticket);
    elseif ~strcmp(type,'properties')
        % got a genuine error
        settings = dbstatus;
        if any(strcmp({settings.cond},'error')) && ~hlp_resolve('disable_dbstop_if_error_msg',false)
            % rerun the code to propagate it properly (we're not using rethrow here to not confuse dbstop if error)
            disp_once('arg_report: caught error while in "dbstop if error" mode; re-running offending code to get break point...\n  error traceback was: %s\n',hlp_handleerror(report));
            if handle_expressions
                hlp_scope({'disable_expressions',1},func,args{:},'__arg_report__',type);
            else
                func(args{:},'__arg_report__',type);
            end
        else
            rethrow(report);
        end
    end
end


function varargout = metabolites_in_database(varargin)
% m-file for metabolites_in_database.fig
% metabolites_in_database, by itself, creates a new object or raises the existing singleton*.
%
% USAGE:
%
%    varargout = metabolites_in_database(varargin)
%
% INPUTS:
%    varargin:    various input arguments
%
% OUTPUTS:
%    varargout:   various output arguments
%
% EXAMPLE:
%
%    H = metabolites_in_database() returns the handle to a new metabolites_in_database or the handle to
%    the existing singleton*.
%
%    metabolites_in_database('CALLBACK',hObject,eventData,handles,...) calls the local
%    function named CALLBACK in metabolites_in_database.M with the given input arguments.
%
%    metabolites_in_database('Property','Value',...) creates a new metabolites_in_database or raises the
%    existing singleton*.  Starting from the left, property value pairs are
%    applied to the GUI before `metabolites_in_database_OpeningFcn` gets called.  An
%    unrecognized property name or invalid value makes property application
%    stop.  All inputs are passed to `metabolites_in_database_OpeningFcn` via `varargin`.
%
% .. Author: - Stefan G. Thorleifsson 2011
%
% NOTE:
%    See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%    instance to run (singleton)".
%    See also: GUIDE, GUIDATA, GUIHANDLES
% .. Edit the above text to modify the response to help metabolites_in_database
% .. Last Modified by GUIDE v2.5 31-Aug-2010 18:09:02
%
% .. rBioNet is published under GNU GENERAL PUBLIC LICENSE 3.0+
% .. Thorleifsson, S. G., Thiele, I., rBioNet: A COBRA toolbox extension for
% .. reconstructing high-quality biochemical networks, Bioinformatics, Accepted.
% .. rbionet@systemsbiology.is
gui_Singleton = 1; % Begin initialization code - DO NOT EDIT
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @metabolites_in_database_OpeningFcn, ...
                   'gui_OutputFcn',  @metabolites_in_database_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before metabolites_in_database is made visible.
function metabolites_in_database_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to metabolites_in_database (see VARARGIN)
data = varargin{1};
set(handles.uitable1,'data',data);
% Choose default command line output for metabolites_in_database
handles.output = 0;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes metabolites_in_database wait for user response (see UIRESUME)
 uiwait(handles.figure1);

% --- Outputs from this function are returned to the command line.
function varargout = metabolites_in_database_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;
delete(gcf)

% --- Executes on button press in act_continue.
function act_continue_Callback(hObject, eventdata, handles)
% hObject    handle to act_continue (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
handles.output = 1;
guidata(hObject,handles)
uiresume;

% --- Executes on button press in act_cancel.
function act_cancel_Callback(hObject, eventdata, handles)
% hObject    handle to act_cancel (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
uiresume;

% --- Executes when user attempts to close figure1.
function figure1_CloseRequestFcn(hObject, eventdata, handles)
% hObject    handle to figure1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: delete(hObject) closes the figure
uiresume


classdef MivContextDef < handle
    % MivContextDef. Defines contexts for MIV
    %
    %
    %     There are a number of contexts, which each represent particular
    %     regions of the lung. For example, the OriginalImage context is the
    %     entire image, whereas the LungROI is the parrallipiped region
    %     containing the lungs and airways. The LeftLung and RightLung comprise
    %     just the voumes of the left and right lung respectively.
    %
    %     Context sets describe a collection of related contexts. For example,
    %     the SingleLung context set contains LeftLung and RightLung.
    %
    %     Each plugin specifies its context set, which is the domain of the
    %     results produced by the plugin. Some plugins operate over the whole
    %     LungROI region, while some operate on individual lungs.
    %
    %     This class manages the situations where a result is requested for a
    %     particualar context (e.g. LungROI) but the plugin defines a different
    %     context set (e.g. SingleLung). The LungROI can be built from the two
    %     contexts in the SingleLung set. Therefore in this case, the plugin is run twice,
    %     once for the left and once for the right lung. Then the resutls are
    %     combined to produce the result for the LungROI context.
    %
    %     Thie class defines this heirarchy of contexts and context sets. In
    %     this way plugins can operate on whichever context is appropriate,
    %     while results can be requested for any context, and the conversions
    %     are handled automatically.
    %
    %     Licence
    %     -------
    %     Part of the TD MIM Toolkit. https://github.com/tomdoel
    %     Author: Tom Doel, Copyright Tom Doel 2014.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    properties (Access = private)
        Contexts
        ContextSets
    end

    methods
        function obj = MivContextDef
            obj.CreateContexts;
        end

        function context = GetContexts(obj)
            context = obj.Contexts;
        end

        function context_sets = GetContextSets(obj)
            context_sets = obj.ContextSets;
        end

        function context = GetDefaultContext(~)
            context = PTKContext.OriginalImage;
        end

        function context = GetDefaultContextSet(~)
            context = PTKContextSet.OriginalImage;
        end

        function matches = ContextSetMatches(~, plugin_context_set, requested_context_set)
            % Returns true if the plugin_context_set can be used to
            % generate the context_set without conversion

            matches = (plugin_context_set == requested_context_set) || (plugin_context_set == PTKContextSet.Any);
        end

        function output_context = ChooseOutputContext(~, context)
            % If a specific context has been specified in the plugin, we use
            % this (note this is not normally the case, as plugins usually
            % specify a PTKContextSet rather than a PTKContext)
            if isa(context, 'PTKContext')
                output_context = plugin_info.Context;

                % If the plugin specifies a PTKContextSet of type
                % PTKContextSet.OriginalImage, then we choose to return a context
                % of PTKContext.OriginalImage
            elseif context == PTKContextSet.OriginalImage
                output_context = PTKContext.OriginalImage;

            % In all other cases we choose a default context of the lung ROI
            else
                output_context = PTKContext.OriginalImage;
            end
        end

    end

    methods (Access = private)
        function CreateContexts(obj)
            % Create the hierarchy of context types
            obj.ContextSets = containers.Map;
            full_set =  MimContextSetMapping(PTKContextSet.OriginalImage, []);
            any_set = MimContextSetMapping(PTKContextSet.Any, []);
            obj.ContextSets(char(PTKContextSet.OriginalImage)) = full_set;
            obj.ContextSets(char(PTKContextSet.Any)) = any_set;

            % Create the hierarchy of contexts
            obj.Contexts = containers.Map;
            full_context =  MimContextMapping(PTKContext.OriginalImage, full_set, 'PTKGetContextForOriginalImage', 'PTKOriginalImage', []);

            obj.Contexts(char(PTKContext.OriginalImage)) = full_context;
        end
    end
end


%TestSuiteTest Unit tests for mtest command-line test runner.

classdef MtestTest < TestCaseInDir

   methods

       function self = MtestTest(name)
           self = self@TestCaseInDir(name, ...
               fullfile(fileparts(which(mfilename)), 'cwd_test'));
       end

      function test_noInputArgs(self)
          [T, did_pass] = evalc('mtest');
          % The cwd_test directory contains some test cases that fail,
          % so output of mtest should be false.
          assertFalse(did_pass);
      end

      function test_oneInputArg(self)
          [T, did_pass] = evalc('mtest(''testFoobar'')');
          % cwd_test/testFoobar.m is supposed to pass.
          assertTrue(did_pass);
      end

      function test_oneInputArgWithFilter_passing(self)
          [T, did_pass] = evalc('mtest(''TestCaseSubclass:testA'')');
          assertTrue(did_pass);
      end

      function test_oneInputArgWithFilter_failing(self)
          [T, did_pass] = evalc('mtest(''TestCaseSubclass:testB'')');
          assertFalse(did_pass);
      end

   end

end


function var = kWaveGPUsingle(var)
%KWAVEGPUSINGLE   GPU datacasting wrapping for GPUmat library
%
% USAGE:
%       var = kWaveGPUsingle(var)
%
% ABOUT:
%       author: Bradley E. Treeby
%       date: 21st January 2010
%       last update: 21st January 2010
%
% This function is part of the k-Wave Toolbox (http://www.k-wave.org)
% Copyright (C) 2009-2014 Bradley Treeby and Ben Cox

% This file is part of k-Wave. k-Wave is free software: you can
% redistribute it and/or modify it under the terms of the GNU Lesser
% General Public License as published by the Free Software Foundation,
% either version 3 of the License, or (at your option) any later version.
%
% k-Wave is distributed in the hope that it will be useful, but WITHOUT ANY
% WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
% FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
% more details.
%
% You should have received a copy of the GNU Lesser General Public License
% along with k-Wave. If not, see <http://www.gnu.org/licenses/>.

% only cast non scalar variables
if ~isscalar(var)
    var = GPUsingle(var);
end


classdef HBox < uix.Box
    %uix.HBox  Horizontal box
    %
    %  b = uix.HBox(p1,v1,p2,v2,...) constructs a horizontal box and sets
    %  parameter p1 to value v1, etc.
    %
    %  A horizontal box lays out contents from left to right.
    %
    %  See also: uix.VBox, uix.Grid, uix.HButtonBox, uix.HBoxFlex

    %  Copyright 2009-2016 The MathWorks, Inc.
    %  $Revision: 1436 $ $Date: 2016-11-17 17:53:29 +0000 (Thu, 17 Nov 2016) $

    properties( Access = public, Dependent, AbortSet )
        Widths % widths of contents, in pixels and/or weights
        MinimumWidths % minimum widths of contents, in pixels
    end

    properties( Access = protected )
        Widths_ = zeros( [0 1] ) % backing for Widths
        MinimumWidths_ = zeros( [0 1] ) % backing for MinimumWidths
    end

    methods

        function obj = HBox( varargin )
            %uix.HBox  Horizontal box constructor
            %
            %  b = uix.HBox() constructs a horizontal box.
            %
            %  b = uix.HBox(p1,v1,p2,v2,...) sets parameter p1 to value v1,
            %  etc.

            % Set properties
            if nargin > 0
                try
                    assert( rem( nargin, 2 ) == 0, 'uix:InvalidArgument', ...
                        'Parameters and values must be provided in pairs.' )
                    set( obj, varargin{:} )
                catch e
                    delete( obj )
                    e.throwAsCaller()
                end
            end

        end % constructor

    end % structors

    methods

        function value = get.Widths( obj )

            value = obj.Widths_;

        end % get.Widths

        function set.Widths( obj, value )

            % For those who can't tell a column from a row...
            if isrow( value )
                value = transpose( value );
            end

            % Check
            assert( isa( value, 'double' ), 'uix:InvalidPropertyValue', ...
                'Property ''Widths'' must be of type double.' )
            assert( all( isreal( value ) ) && ~any( isinf( value ) ) && ...
                ~any( isnan( value ) ), 'uix:InvalidPropertyValue', ...
                'Elements of property ''Widths'' must be real and finite.' )
            assert( isequal( size( value ), size( obj.Contents_ ) ), ...
                'uix:InvalidPropertyValue', ...
                'Size of property ''Widths'' must match size of contents.' )

            % Set
            obj.Widths_ = value;

            % Mark as dirty
            obj.Dirty = true;

        end % set.Widths

        function value = get.MinimumWidths( obj )

            value = obj.MinimumWidths_;

        end % get.MinimumWidths

        function set.MinimumWidths( obj, value )

            % For those who can't tell a column from a row...
            if isrow( value )
                value = transpose( value );
            end

            % Check
            assert( isa( value, 'double' ), 'uix:InvalidPropertyValue', ...
                'Property ''MinimumWidths'' must be of type double.' )
            assert( all( isreal( value ) ) && ~any( isinf( value ) ) && ...
                all( value >= 0 ), 'uix:InvalidPropertyValue', ...
                'Elements of property ''MinimumWidths'' must be non-negative.' )
            assert( isequal( size( value ), size( obj.Widths_ ) ), ...
                'uix:InvalidPropertyValue', ...
                'Size of property ''MinimumWidths'' must match size of contents.' )

            % Set
            obj.MinimumWidths_ = value;

            % Mark as dirty
            obj.Dirty = true;

        end % set.MinimumWidths

    end % accessors

    methods( Access = protected )

        function redraw( obj )
            %redraw  Redraw
            %
            %  c.redraw() redraws the container c.

            % Compute positions
            bounds = hgconvertunits( ancestor( obj, 'figure' ), ...
                [0 0 1 1], 'normalized', 'pixels', obj );
            widths = obj.Widths_;
            minimumWidths = obj.MinimumWidths_;
            padding = obj.Padding_;
            spacing = obj.Spacing_;
            c = numel( widths );
            xSizes = uix.calcPixelSizes( bounds(3), widths, ...
                minimumWidths, padding, spacing );
            xPositions = [cumsum( [0; xSizes(1:c-1,:)] ) + padding + ...
                spacing * transpose( 0:c-1 ) + 1, xSizes];
            yPositions = [padding + 1, max( bounds(4) - 2 * padding, 1 )];
            yPositions = repmat( yPositions, [c 1] );
            positions = [xPositions(:,1), yPositions(:,1), ...
                xPositions(:,2), yPositions(:,2)];

            % Set positions
            children = obj.Contents_;
            for ii = 1:numel( children )
                uix.setPosition( children(ii), positions(ii,:), 'pixels' )
            end

        end % redraw

        function addChild( obj, child )
            %addChild  Add child
            %
            %  c.addChild(d) adds the child d to the container c.

            % Add to sizes
            obj.Widths_(end+1,:) = -1;
            obj.MinimumWidths_(end+1,:) = 1;

            % Call superclass method
            addChild@uix.Box( obj, child )

        end % addChild

        function removeChild( obj, child )
            %removeChild  Remove child
            %
            %  c.removeChild(d) removes the child d from the container c.

            % Remove from sizes
            tf = obj.Contents_ == child;
            obj.Widths_(tf,:) = [];
            obj.MinimumWidths_(tf,:) = [];

            % Call superclass method
            removeChild@uix.Box( obj, child )

        end % removeChild

        function reorder( obj, indices )
            %reorder  Reorder contents
            %
            %  c.reorder(i) reorders the container contents using indices
            %  i, c.Contents = c.Contents(i).

            % Reorder
            obj.Widths_ = obj.Widths_(indices,:);
            obj.MinimumWidths_ = obj.MinimumWidths_(indices,:);

            % Call superclass method
            reorder@uix.Box( obj, indices )

        end % reorder

    end % template methods

end % classdef


%% OPTI MEX Install Script

% This file enables me to quickly rebuild all solvers - it is not intended
% to be called by the user!

% My build platform:
% - Windows 8 x64
% - Visual Studio 2012
% - Intel Compiler XE (C++ & FORTRAN)
% - Intel Math Kernel Library

% YOU MUST BE IN THE BASE DIRECTORY OF THE OPTI TOOLBOX!

%% -- Intel C++ Solvers --
clc
fprintf(2,'Please Specify Intel C++ as your Compiler with VS2012 Linker (Option 3, Don''t Look for Installed Compilers)...\n\n');
mex -setup
%% CLP
opti_CLP_Install

%% -- VS2012 Solvers --
clc
fprintf(2,'Please Specify Visual Studio 2012 as your Compiler...\n\n');
mex -setup
%% BONMIN
opti_BONMIN_Install

%% CBC
opti_CBC_Install

%% CSDP
opti_CSDP_Install

%% DSDP
opti_DSDP_Install

%% FILTERSD
opti_FILTERSD_Install

%% GLPK
opti_GLPK_Install

%% HYBRJ
opti_HYBRJ_Install

%% IPOPT
opti_IPOPT_Install

%% L-BFGS-B
opti_LBFGSB_Install

%% LEVMAR
opti_LEVMAR_Install

%% LIPSOL
opti_LIPSOL_Install

%% LMDER
opti_LMDER_Install

%% LP_SOLVE
opti_LPSOLVE_Install

%% M1QN3
opti_M1QN3_Install

%% MKL TR NLS
opti_MKLTRNLS_Install

%% MUMPS
opti_MUMPS_Install

%% NL2SOL
opti_NL2SOL_Install

%% NLOPT
opti_NLOPT_Install

%% NOMAD
opti_NOMAD_Install

%% OOQP
opti_OOQP_Install

%% PSWARM
opti_PSWARM_Install

%% QSOPT
opti_QSOPT_Install

%% SCIP
opti_SCIP_Install

%% -- Utilities --
%% MKL JAC
opti_MKLJAC_Install

%% CoinUtils
opti_COINUTILS_Install

%% AMPL
opti_AMPL_Install


function scanSummationMenu(command)
%"scanSummationMenu"
%   Create the GUI used to sum scans.
%
%   02/15/08  APA Based on scanSummationMenu
%
%Usage:
%   scanSummationMenu()
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

global planC;
global stateS;
indexS = planC{end};

if nargin == 0
    command = 'init';
end

hFig = findobj('tag', 'CERRScanSummationFigure');

switch upper(command)
    case 'INIT'
        if ~isempty(hFig)
            delete(hFig);
        end
        screenSize = get(0,'ScreenSize');
        units = 'pixels';
        y = 480;
        x = 480;

        dx = 20;
        dy = 20;

        hFig = figure('Name', 'Scan Summation', 'units', 'pixels', 'position',[(screenSize(3)-x)/2 (screenSize(4)-y)/2 x y], 'MenuBar', 'none', 'NumberTitle', 'off', 'resize', 'off', 'Tag', 'CERRScanSummationFigure');
        stateS.handle.scanSummationMenuFig = hFig;

        bartop = 80;
        loadbot = y-65-10;

        ud.handles.instruction = uicontrol('units',units,'HorizontalAlignment','left','Position',[dx y-dy-60 x-2*dx 20],'String', 'Select the scans to be included in the sum scan.', 'Style','text','Tag','text1');
        ud.handles.labelname = uicontrol('units',units,'HorizontalAlignment','left','Position',[dx y-dy-10 100 15],'String', 'New Scan Name:', 'Style','text','Tag','text2');
        ud.handles.newScanName = uicontrol('units',units,'Position',[dx y-dy-35 120 20],'BackgroundColor',[1 1 1],'HorizontalAlignment','left','String', '', 'Style','edit','Tag','scanName');
        ud.handles.assocname = uicontrol('units',units,'HorizontalAlignment','left','Position',[x-dx-250 y-dy-10 140 15],'String', 'Prefer Images from:', 'Style','text','Tag','scanAssoc');
        for i=1:length(planC{indexS.scan})
            scanStr{i} = [num2str(i), '. ', planC{indexS.scan}(i).scanType];
        end
        ud.handles.scanSelect = uicontrol('units',units,'Position',[x-dx-250 y-dy-35 120 20],'BackgroundColor',[1 1 1],'HorizontalAlignment','left','String', scanStr, 'Style','popup','value',1,'Tag','scanSelect');

        %Make CANCEL and SUM buttons
        ud.handles.cancelButton = uicontrol(hFig, 'callback', 'scanSummationMenu(''CANCEL'');', 'units',units,'Position',[x-dx-70 y-dy-35 70 20],'String','Cancel', 'Style','pushbutton','Tag','cancelButton');
        ud.handles.sumButton = uicontrol(hFig, 'callback', 'scanSummationMenu(''SUM'');', 'units',units, 'Position',[x-dx-70 y-dy-10 70 20],'String','Sum', 'Style','pushbutton','Tag','sumButton');

        %Plans frame and label
        planFrame  = uicontrol(hFig, 'units',units,'Position',[dx dy x-2*dx y-dy-bartop], 'style', 'frame');
        frameColor = get(planFrame, 'BackgroundColor');

        %Create scrollbar on right side. Inactive to start.
        ud.df.handles.scroll = uicontrol(hFig, 'units',units,'Position',[x-dx-20 dy 20 y-dy-bartop], 'style', 'slider', 'enable', 'off','tag','planSlider', 'callback', 'scanSummationMenu(''SLIDER'')');

        %Create plan UICONTROLS.
        uicontrol(hFig, 'units',units,'Position',[30 loadbot-46 15 15], 'style', 'text', 'String', 'No.', 'fontweight', 'bold', 'backgroundcolor', frameColor);
        %uicontrol(hFig, 'units',units,'Position',[40 loadbot-46 100 15], 'style', 'text', 'String', 'Plan Name', 'fontweight', 'bold', 'backgroundcolor', frameColor);
        uicontrol(hFig, 'units',units,'Position',[dx+100 loadbot-46 70 15], 'style', 'text', 'String', 'Assoc Scan', 'fontweight', 'bold', 'backgroundcolor', frameColor);
        uicontrol(hFig, 'units',units,'Position',[dx+210 loadbot-46 60 15], 'style', 'text', 'String', 'Select', 'fontweight', 'bold', 'backgroundcolor', frameColor);
        uicontrol(hFig, 'units',units,'Position',[dx+270 loadbot-46 100 15], 'style', 'text', 'String', 'Weighting Factor', 'fontweight', 'bold', 'backgroundcolor', frameColor);

        numRows = 50;
        for i=1:numRows
            ud.handles.scanNum(i)   = uicontrol(hFig, 'units',units,'Position',[30 359-i*20 10 15], 'style', 'text', 'String', num2str(i), 'backgroundcolor', frameColor, 'visible', 'off');
            ud.handles.scanName(i)  = uicontrol(hFig, 'units',units,'Position',[dx+100 359-i*20 40 15], 'style', 'text', 'String', 'Scan', 'backgroundcolor', frameColor, 'visible', 'off');
            ud.handles.scanCheck(i) = uicontrol(hFig, 'units',units,'Position',[dx+210 359-i*20 25 15], 'style', 'checkbox', 'backgroundcolor', frameColor, 'horizontalAlignment', 'center', 'userdata', i, 'Tag', 'ScanCheck', 'callback', 'scanSummationMenu(''Check'')', 'visible', 'off');
            ud.handles.wtfactor(i)  = uicontrol(hFig, 'units',units,'Position',[dx+270 359-i*20 45 15], 'Style','edit', 'String', '1.0', 'BackgroundColor',[1 1 1],'horizontalAlignment', 'center','Tag','wtfactor', 'callback', 'scanSummationMenu(''Check'')', 'visible', 'off');
        end
        ud.numScanRows = numRows;

        ud.firstVisScan     = 1;

        set(hFig, 'userdata', ud);

        nScans = length(planC{indexS.scan});
        ud.checkedScans = zeros(nScans, 1);

        %Set range of currently displayed scans.
        ud.df.range = 1:min(16, nScans);

        set(hFig, 'userdata', ud);
        scanSummationMenu('refresh');

    case 'REFRESH'
        ud = get(hFig, 'userdata');
        indexS = planC{end};

        %Number of visible scans.
        nvScans = length(ud.df.range);

        %Refresh scan UIelements.
        set(ud.handles.scanNum,  'visible', 'off');
        set(ud.handles.scanName,  'visible', 'off');
        set(ud.handles.scanCheck, 'visible', 'off');
        set(ud.handles.wtfactor, 'visible', 'off');
        nScans = length(ud.checkedScans);
        ud.firstVisScan = min(ud.df.range);
        for i=1:min(length(ud.handles.scanName), nvScans)
            scanNum  = ud.firstVisScan+i-1;
            scanName = [num2str(scanNum),'. ',planC{indexS.scan}(scanNum).scanType];
            set(ud.handles.scanNum(scanNum),'visible', 'on')
            set(ud.handles.scanName(scanNum), 'string', scanName, 'visible', 'on', 'Position',[20+100 359-i*20 80 15]);
            set(ud.handles.scanCheck(scanNum), 'visible', 'on', 'Position',[20+240 359-i*20 25 15]);
            set(ud.handles.wtfactor(scanNum), 'visible', 'on', 'Position',[20+300 359-i*20 45 15]);
        end

        if nScans > 16
            set(ud.df.handles.scroll, 'min', 0, 'max', nScans-nvScans, 'value', nScans-nvScans+1-min(ud.df.range), 'enable', 'on', 'sliderstep', [1/(nScans-nvScans), nvScans/(nScans-nvScans)]);
        else
            set(ud.df.handles.scroll, 'enable', 'off');
        end

        set(hFig, 'userdata', ud);

    case 'CHECK'
        checkNum = get(gcbo, 'userdata');
        type     = get(gcbo, 'Tag');
        value    = get(gcbo, 'value');

        ud = get(hFig, 'userdata');

        switch upper(type)
            case 'SCANCHECK'
                ud.checkedScans(checkNum+ud.firstVisScan-1) = value;
                if value == 1
                    set(ud.handles.newScanName,'string',planC{indexS.scan}(checkNum).scanType)
                    set(ud.handles.scanSelect,'value',checkNum)
                end
%             case 'WTFACTOR'
%                 factor = str2num(get(ud.handles.wtfactor(i), 'String'));
        end

        set(hFig, 'userdata', ud);

    case 'SLIDER'
        %Slider was clicked, move ud.df.range.
        ud = get(hFig, 'userdata');
        val = round(get(gcbo, 'value'));

        nRows = 16;
        nScans  = length(planC{indexS.scan});

        lastScan = nScans - val;
        ud.df.range = max(1, lastScan-nRows+1):lastScan;
        set(hFig, 'userdata', ud);
        scanSummationMenu('REFRESH');

    case 'SUM'
        hFig = findobj('tag', 'CERRScanSummationFigure');
        ud = get(hFig, 'userdata');
        checkedScans = find(ud.checkedScans);
        if length(checkedScans) < 2
			warndlg('You must select atleast two scans','Incorrect Selection','modal')
            return
        end

        % Check for duplicate or blank name.
        newScanName = get(ud.handles.newScanName, 'String');
        if isempty(newScanName)
            warndlg('Please enter a name for the new scan.', 'Warning','modal');
            return;
        end

        %Check that no checked plan has a weighting factor that is blank.
        for i = 1:length(planC{indexS.scan})
            factor = str2num(get(ud.handles.wtfactor(i), 'String'));
            if isempty(factor) && ~isempty(find(checkedScans == i))
                warndlg('Please enter a weighting factor for all selected scans.', 'Warning','modal');
                return
            elseif isempty(factor)
                factor = 0;
            end
            wtfactor(i) = factor;
        end

        %% APA code begins
        assocScan = get(ud.handles.scanSelect,'value');
        [xAssocV, yAssocV, zAssocV] = getScanXYZVals(planC{indexS.scan}(assocScan));

        if assocScan > 0
            assocScanUID = planC{indexS.scan}(assocScan).scanUID;
            %Get associated transM
            assocTransM = planC{indexS.scan}(assocScan).transM;
            if isempty(assocTransM)
                assocTransM = eye(4);
            end
        else %No Association
            assocScanUID = '';
            assocTransM = eye(4);
        end

        scanNums = checkedScans;

        %Get the x,y,z grid for new scan
        for i = 1:length(scanNums)
            scanNum = scanNums(i);
            %Get x,y,z values for scanNum
            [xV, yV, zV] = getScanXYZVals(planC{indexS.scan}(scanNum));

            %Get the corners of the original dataset.
            [xCorn, yCorn, zCorn] = meshgrid([min(xV) max(xV)], [min(yV) max(yV)], [min(zV) max(zV)]);

            %Add ones to the corners so we can apply a transformation matrix.
            corners = [xCorn(:) yCorn(:) zCorn(:) ones(prod(size(xCorn)), 1)];

            %Apply transform to corners, so we know boundary of the slice.
            transM = getTransM(planC{indexS.scan}(scanNum),planC);
            if isempty(transM) || isequal(transM,eye(4))
                [xV,yV,zV] = getScanXYZVals(planC{indexS.scan}(scanNum));
                xGrid{scanNum} = xV(:)';
                yGrid{scanNum} = yV(:)';
                zGrid{scanNum} = zV(:)';
            else
                newCorners = inv(assocTransM) * transM * corners';
                xGrid{scanNum} = linspace(min(newCorners(1,:)), max(newCorners(1,:)), length(xV));
                yGrid{scanNum} = linspace(max(newCorners(2,:)), min(newCorners(2,:)), length(yV));
                zGrid{scanNum} = linspace(min(newCorners(3,:)), max(newCorners(3,:)), length(zV));
            end
            xRes{scanNum} = length(xV);
            yRes{scanNum} = length(yV);
            zRes{scanNum} = length(zV);

            %Get associated scan
            assocScanV{scanNum} = scanNum;
        end
        newXgrid = linspace(min(cell2mat(xGrid)),max(cell2mat(xGrid)),max(cell2mat(xRes)));
        newYgrid = linspace(max(cell2mat(yGrid)),min(cell2mat(yGrid)),max(cell2mat(yRes)));
        newZgrid = linspace(min(cell2mat(zGrid)),max(cell2mat(zGrid)),round(max(cell2mat(zRes))*1.5));

%         %Obtain scans with same grid
%         if isempty(assocTransM)
%             assocTransM = eye(4);
%         end
%         scanIndC = {};
%         scanNumsTmp = scanNums;
%         for iSortAll = 1:length(scanNums)
%             iSort = scanNums(iSortAll);
%             indRemaining = scanNums;
%             indRemaining(iSortAll) = [];
%             scanSortM = [iSort];
%             if ~ismember(iSort,[scanIndC{:}])
%                 for jSortAll = 1:length(indRemaining)
%                     jSort = indRemaining(jSortAll);
%                     if ~isempty(getTransM('scan',iSort,planC))
%                         scanITM = inv(assocTransM) * getTransM('scan',iSort,planC);
%                     else
%                         scanITM = inv(assocTransM);
%                     end
%                     if ~isempty(getTransM('scan',jSort,planC))
%                         scanJTM = inv(assocTransM) * getTransM('scan',jSort,planC);
%                     else
%                         scanJTM = inv(assocTransM);
%                     end
%                     if isequal([xRes{iSort},yRes{iSort},zRes{iSort}],[xRes{jSort},yRes{jSort},zRes{jSort}]) && isequal(scanITM,scanJTM)
%                         scanSortM(end+1) = jSort;
%                         indJsort = find(scanNumsTmp == jSort);
%                         scanNumsTmp(indJsort) = [];
%                     end
%                 end
%             end
%             scanIndC{iSort} = scanSortM;
%         end
%
%         scanNums = scanNumsTmp;

        %Loop over scans and add over new grid
        hWait = waitbar(0,['Appending one scans to Scan # ',num2str(assocScan)]);
        scanSumM = zeros([length(newYgrid),length(newXgrid),length(newZgrid)],'single');
        scanEmptyM = zeros([length(newYgrid),length(newXgrid)],'single');

        for i = 1:length(scanNums)

            scanNum = scanNums(i);

            %Check for transM
            if ~isempty(assocTransM) && ~isequal(assocTransM,eye(4))
                scanTtransM = getTransM('scan',scanNum,planC);
                if isempty(scanTtransM)
                    scanTtransM = eye(4);
                end
                inputTM = inv(assocTransM) * scanTtransM;
            else
                inputTM = getTransM('scan',scanNum,planC);
                if isempty(inputTM)
                    inputTM = eye(4);
                end
            end

%             %Get the summation for this grid
%             scanCombinedM = [];
%             for iScanAll = 1:length(scanIndC{scanNum})
%                 iScan = scanIndC{scanNum}(iScanAll);
%                 if ~isempty(scanCombinedM)
%                     scanCombinedM = scanCombinedM + wtfactor(iScan) * single(getScanArray(planC{indexS.scan}(iScan)));
%                 else
%                     scanCombinedM = wtfactor(iScan) * single(getScanArray(planC{indexS.scan}(iScan)));
%                 end
%             end

            %Check if this scan is on same grid as the new one
            %if isequal(xGrid{scanNum},newXgrid) && isequal(yGrid{scanNum},newYgrid) && isequal(zGrid{scanNum},newZgrid)
            chkLength = length(xGrid{scanNum})==length(newXgrid) && length(yGrid{scanNum})==length(newYgrid) && length(zGrid{scanNum})==length(newZgrid);
            if 0 && sum(sum((inputTM-eye(4)).^2)) < 1e-5 && chkLength && max(abs(xGrid{scanNum}-newXgrid)) < 1e-6 && max(abs(yGrid{scanNum}-newYgrid)) < 1e-6 && max(abs(zGrid{scanNum}-newZgrid)) < 1e-6

                scanSumM = scanSumM + scanCombinedM;
                waitbar((i-1)/length(scanNums),hWait,['Calculating contribution from Scan ', num2str(scanNum)])

            else %interpolation required

                %Transform this scan
                scanTmpM = [];

                for slcNum=1:length(newZgrid)
                    [xV, yV, zV] = getScanXYZVals(planC{indexS.scan}(scanNum));
                    if min(zAssocV)<newZgrid(slcNum) && newZgrid(slcNum)<max(zAssocV) && scanNum ~= assocScan
                        scanTmp = [];
                    else
                        scanTmp = slice3DVol(planC{indexS.scan}(scanNum).scanArray, xV, yV, zV, newZgrid(slcNum), 3, 'linear', inputTM, [], newXgrid, newYgrid);
                    end
                    if isempty(scanTmp)
                        scanTmpM(:,:,slcNum) = scanEmptyM;
                    else
                        scanTmpM(:,:,slcNum) = scanTmp;
                    end
                    waitbar((i-1)/length(scanNums) + (slcNum-1)/length(newZgrid)/length(scanNums) ,hWait,['Calculating contribution from Scan ', num2str(scanNum)])
                end

                scanSumM = scanSumM + wtfactor(scanNum) * scanTmpM;

            end

        end

        delete(hWait)

        %Create new scan distribution
        newScanNum = length(planC{indexS.scan}) + 1;
        newScanS = initializeCERR('scan');
        newScanS(1).scanArray = scanSumM;
        newScanS(1).scanType = newScanName;
        newScanS(1).scanUID = createUID('scan');
        newScanS(1).transM = planC{indexS.scan}(assocScan).transM;
        scanInfoS = planC{indexS.scan}(assocScan).scanInfo(1);
        scanInfoS.grid1Units = abs(newYgrid(1)-newYgrid(2));
        scanInfoS.grid2Units = abs(newXgrid(1)-newXgrid(2));
        scanInfoS.scanFileName = '';
        scanInfoS.DICOMHeaders = '';
        scanInfoS.sliceThickness =  abs(newZgrid(1)-newZgrid(2));
        scanInfoS.voxelThickness =  abs(newZgrid(1)-newZgrid(2));
        scanInfoS.sizeOfDimension1 = size(scanSumM,1);
        scanInfoS.sizeOfDimension2 = size(scanSumM,2);
        clear scanSumM
        for sInfoNum = 1:length(newZgrid)
            scanInfoNewS = scanInfoS;
            scanInfoNewS.zValue = newZgrid(sInfoNum);
            newScanS(1).scanInfo(sInfoNum) = scanInfoNewS;
        end
        planC{indexS.scan} = dissimilarInsert(planC{indexS.scan},newScanS,newScanNum);
        planC = setUniformizedData(planC);

        % Save scan statistics for fast image rendering
        for scanNum = newScanNum
            scanUID = ['c',repSpaceHyp(planC{indexS.scan}(scanNum).scanUID(max(1,end-61):end))];
            %stateS.scanStats.minScanVal.(scanUID) = single(min(planC{indexS.scan}(scanNum).scanArray(:)));
            %stateS.scanStats.maxScanVal.(scanUID) = single(max(planC{indexS.scan}(scanNum).scanArray(:)));
            minScan = single(min(planC{indexS.scan}(scanNum).scanArray(:)));
            maxScan = single(max(planC{indexS.scan}(scanNum).scanArray(:)));
            scanDiff = maxScan - minScan;
            scanCenter = (minScan + maxScan - 2*CTOffset) / 2;
            stateS.scanStats.CTLevel.(scanUID) = scanCenter;
            stateS.scanStats.CTWidth.(scanUID) = scanDiff;
            stateS.scanStats.Colormap.(scanUID) = 'gray256';
            stateS.scanStats.windowPresets.(scanUID) = 1;
        end

        %switch to new scan, with a short pause to let the dialogue clear.
        pause(.1);
        sliceCallBack('selectScan', num2str(newScanNum));

        %Refresh this GUI to include new scan distribution
        ud.df.range = [ud.df.range ud.df.range(end)+1];
        if length(ud.df.range)>16
            ud.df.range = ud.df.range(2:17);
        end
        set(hFig, 'userdata', ud);
        scanSummationMenu('refresh')

        %% APA code ends

    case 'CANCEL'
        hFig = findobj('tag', 'CERRScanSummationFigure');
        delete(hFig);
end


function gui_l (x, y)
%
% This file is needed by FASTICAG

% The load dialog for loading new data
% and new initial guess.

% @(#)$Id: gui_l.m,v 1.4 2004/07/27 13:09:26 jarmo Exp $

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Global variables

% Handle to the window
global hf_FastICA_Load;

% Handles to some of the controls in window
global he_FastICA_file;

% What is the load type of load dialog
global g_FastICA_loadType;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Configuration options
FIGURENAME = 'FastICA: Load';
FIGURETAG = 'f_FastICALoad';
FIGURESIZE = [x y 450 150];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Check to see if this figure is already open - it should not!
% Can't have more than one copy - otherwise the global
% variables and handles can get mixed up.
if ~isempty(findobj('Tag',FIGURETAG))
  error('Error: load dialog already open!');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Initialize some of the controls' values

% What are we loading - who is calling?
caller = get(gcf, 'CurrentObject');

switch get(caller, 'Tag')
 case 'b_LoadData'                             % Do we load new data...
  loadString = 'Load data from variable in Matlab.';
  g_FastICA_loadType = 'data';
  FIGURENAME = 'FastICA: Load data';

 case 'b_LoadGuess'                            % ... or new initial guess?
  loadString = 'Load initial guess for mixing matrix A from variable in Matlab.';
  g_FastICA_loadType = 'guess';
  FIGURENAME = 'FastICA: Load initial guess';
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create the figure
a = figure('Color',[0.8 0.8 0.8], ...
	   'PaperType','a4letter', ...
	   'Name', FIGURENAME, ...
	   'NumberTitle', 'off', ...
	   'Tag', FIGURETAG, ...
	   'Position', FIGURESIZE, ...
	   'MenuBar', 'none');
set (a, 'Resize', 'off');

hf_FastICA_Load = a;

set(hf_FastICA_Load, 'HandleVisibility', 'callback');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% From here on it get's ugly as I have not had time to clean it up

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Create the frames
pos_l=2;
pos_w=FIGURESIZE(3)-4;
pos_h=FIGURESIZE(4)-4;
pos_t=2;
h_f_load_background = uicontrol('Parent',a, ...
  'BackgroundColor',[0.701961 0.701961 0.701961], ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'Style','frame', ...
  'Tag','f_load_background');

pos_w=120;
pos_l=FIGURESIZE(3)-(pos_w+2+2);
pos_h=FIGURESIZE(4)-2*4;
pos_t=4;
h_f_load_side = uicontrol('Parent',a, ...
  'BackgroundColor',[0.701961 0.701961 0.701961], ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'Style','frame', ...
  'Tag','f_load_side');

pos_l=4;
pos_w=FIGURESIZE(3)-8-pos_w-2;
pos_h=FIGURESIZE(4)-8;
pos_t=4;
h_f_load = uicontrol('Parent',a, ...
  'BackgroundColor',[0.701961 0.701961 0.701961], ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'Style','frame', ...
  'Tag','f_load');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Controls in f_load
bgc = get(h_f_load, 'BackgroundColor');

pos_w=230;

pos_frame=get(h_f_load, 'Position');
pos_h = 40;
pos_t = pos_frame(2) + pos_frame(4) - pos_h - 6;
pos_l = pos_frame(1) + 6;

b = uicontrol('Parent',a, ...
  'BackgroundColor',bgc, ...
  'HorizontalAlignment','left', ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'String',loadString, ...
  'Style','text', ...
  'Tag','t_93');

pos_h = 20;
pos_t = pos_t - pos_h - 10;
pos_l = pos_frame(1) + 6;

b = uicontrol('Parent',a, ...
  'BackgroundColor',bgc, ...
  'HorizontalAlignment','left', ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'String','Name of the variable:', ...
  'Style','text', ...
  'Tag','t_92');

pos_w = 200;
pos_l = pos_l + 30;
pos_t = pos_t - pos_h;
he_FastICA_file = uicontrol('Parent',a, ...
  'BackgroundColor',[1 1 1], ...
  'HorizontalAlignment','left', ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'String','', ...
  'Style','edit', ...
  'Tag','e_file');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Controls in f_load_side
pos_vspace = 6;
pos_hspace = 10;
pos_frame = get(h_f_load_side, 'Position');
pos_w = 100;
pos_h = 30;
pos_l = pos_frame(1) + pos_hspace;
pos_t = pos_frame(2) + pos_frame(4) - pos_h - pos_vspace;
b = uicontrol('Parent',a, ...
  'BackgroundColor',[0.701961 0.701961 0.701961], ...
  'Callback','gui_lc Load', ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'String','Load', ...
  'Tag','b_lLoad');

pos_t=pos_t-pos_h-pos_vspace;
b = uicontrol('Parent',a, ...
  'BackgroundColor',[0.701961 0.701961 0.701961], ...
  'Callback','gui_lc Cancel', ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'String','Cancel', ...
  'Tag','b_lCancel');

pos_t = pos_frame(2) + pos_vspace;
b = uicontrol('Parent',a, ...
  'BackgroundColor',[0.701961 0.701961 0.701961], ...
  'Callback','gui_lc Help', ...
  'Position',[pos_l pos_t pos_w pos_h], ...
  'String','Help', ...
  'Tag','b_lHelp');


function frame = getframe_nosteal_focus(fig, resolution, dpi)
%GETFRAME_NOSTEAL_FOCUS Same as getframe, but does not focus figure
%
%  GETFRAME_NOSTEAL_FOCUS captures the current figure at 1200x900
%  resolution and 96 dpi
%
%  GETFRAME_NOSTEAL_FOCUS(FIG) captures the figure FIG at 1200x900
%  resolution and 96 dpi
%
%  GETFRAME_NOSTEAL_FOCUS(FIG, RESOLUTION) captures the figure FIG
%  at the resolution RESOLUTION, e.g. RESOLUTION = [1200 900], and
%  96 dpi
%
%  GETFRAME_NOSTEAL_FOCUS(FIG, RESOLUTION, DPI) captures the figure FIG
%  at the resolution RESOLUTION, and DPI dots per inch.
%
%See also: getframe
%
%Written by Erik Sällström

    % Set current figure to the figure to capture if not specified
    if (~exist('fig', 'var'))
        fig = gcf;
    end

    % Set default resolution if not set
    if (~exist('resolution', 'var'))
        resolution = [1200, 900];
    end

    % Set default dpi if not set
    if (~exist('dpi', 'var'))
       dpi = 96;
    end

    % Get a filename for a temporary file
    tempfilename = [tempname '.tif'];

    % Set the figure size on paper!
    set(fig, 'PaperPosition', [1 1 resolution/dpi]);

    % Print figure to a file
    print('-dtiffnocompression', ['-r' num2str(dpi)], ['-f' ...
                        num2str(fig)], tempfilename);

    % Load picture
    frame.cdata = imread(tempfilename);
    frame.colormap = [];

    % Delete temporary file
    delete(tempfilename);

end


function yourReturns = fName(arguments)
%Initialize a new vista function
%
%  fName(arguments)
%
%
% INPUTS
%
% RETURNS
%
% Web Resources
%
% Example:
%   vistaEditFunction('writeMe');
%
% Copyright Stanford team, mrVista, 2011

%% Check inputs