classdef MimContextHierarchy < CoreBaseClass
    % MimContextHierarchy. Part of the internal framework of the TD MIM Toolkit.
    %
    %     This class is used to switch beteen different contexts.
    %
    %     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 manages 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
        ContextSets
        Contexts
        ContextDef

        DatasetDiskCache
        ImageTemplates
        Pipelines
        FrameworkAppDef % Framework configuration
        PluginCache % Used to check plugin version numbers
    end

    methods
        function obj = MimContextHierarchy(context_def, dataset_disk_cache, image_templates, pipelines, framework_app_def, plugin_cache)
            obj.DatasetDiskCache = dataset_disk_cache;
            obj.ImageTemplates = image_templates;
            obj.Pipelines = pipelines;
            obj.FrameworkAppDef = framework_app_def;
            obj.PluginCache = plugin_cache;

            obj.ContextDef = context_def;
            obj.Contexts = context_def.GetContexts;
            obj.ContextSets = context_def.GetContextSets;
        end

        function context_list = GetContextList(obj, output_context, plugin_info, reporting)
            % Parses a list of Contexts, expands out any ContextSets into
            % Contexts, and returns an error if a Context is not known

            % Determines the context and context type requested by the calling function
            if isempty(output_context)
                output_context = obj.ContextDef.ChooseOutputContext(plugin_info.Context);
            end

            context_list = [];

            for next_output_context_set = CoreContainerUtilities.ConvertToSet(output_context)
                next_output_context = next_output_context_set{1};
                if obj.Contexts.isKey(char(next_output_context))
                    % Note that if the enum name of the context set matches
                    % the enum name of a context, we need to be sure the
                    % contet gets added, not the context set
                    context_list{end + 1} = obj.Contexts(char(next_output_context)).Context;
                elseif obj.ContextSets.isKey(char(next_output_context))
                    context_set_mapping = obj.ContextSets(char(next_output_context));
                    context_mapping_list = context_set_mapping.ContextList;
                    context_list = [context_list, CoreContainerUtilities.GetFieldValuesFromSet(context_mapping_list, 'Context')];
                else
                    if obj.DatasetDiskCache.ManualSegmentationExists(char(next_output_context), reporting)
                        context_list{end + 1} = char(next_output_context);
                    else
                        % Allow contexts with specific label indices
                        [context_prefix, context_suffix] = CoreTextUtilities.SplitAtLastDelimiter(char(next_output_context), '.');
                        if obj.DatasetDiskCache.ManualSegmentationExists(context_prefix, reporting)
                            context_list{end + 1} = char(next_output_context);
                        else
                            reporting.Error('MimContextHierarchy:UnknownOutputContext', 'I do not understand the requested output context.');
                        end
                    end
                end
            end
        end

        function value = GetParameter(obj, name, dataset_stack, reporting)
            value = dataset_stack.GetParameterAndAddDependenciesToPluginsInStack(name, reporting);
        end

        function combined_result = GetResultRecursive(obj, plugin_name, output_context, parameters, linked_dataset_chooser, plugin_info, plugin_class, dataset_uid, dataset_stack, force_generate_image, memory_cache_policy, disk_cache_policy, reporting)

            % Records that there has been an attempt to call this plugin,
            % so that we can detect if a plugin call failed
            obj.ImageTemplates.NoteAttemptToRunPlugin(plugin_name, output_context, reporting);

            [plugin_context_set, plugin_context_set_mapping] = obj.GetContextSetMappings(plugin_info.Context);
            [output_context, output_context_set, output_context_mapping, output_context_set_mapping] = obj.GetContextMaps(output_context);

            % If the input and output contexts are of the same type, or if the
            % plugin context is of type 'Any', then proceed to call the plugin
            if isempty(output_context_set) || obj.ContextDef.ContextSetMatches(plugin_context_set, output_context_set)

                % Code moved from PluginDependencyTracker

                % Fetch plugin result from the disk cache
                result = [];

                edited_result_exists = obj.DatasetDiskCache.EditedResultExists(plugin_name, output_context, reporting);

                % We can skip fetching the result if an edited result exists
                % and does not depend on the automated result
                if ~edited_result_exists || plugin_info.EditRequiresPluginResult

                    if ~plugin_info.AlwaysRunPlugin

                        [result, cache_info] = obj.DatasetDiskCache.LoadPluginResult(plugin_name, output_context, memory_cache_policy, reporting);

                        % Check dependencies of the result. If they are invalid, set the
                        % result to null to force a re-run of the plugin
                        if ~isempty(cache_info)
                            dependencies = cache_info.DependencyList;
                            if ~obj.CheckPluginVersion(cache_info.InstanceIdentifier, reporting)
                                reporting.ShowWarning('MimContextHierarchy:InvalidDependency', ['The plugin ' plugin_name ' has changed since the cache was generated. I am forcing this plugin to re-run to generate new results.'], []);
                                result = [];
                            end

                            if ~obj.CheckDependenciesValid(linked_dataset_chooser, dependencies, dataset_stack, parameters, reporting)
                                reporting.ShowWarning('MimContextHierarchy:InvalidDependency', ['The cached value for plugin ' plugin_name ' is no longer valid since some of its dependencies have changed. I am forcing this plugin to re-run to generate new results.'], []);
                                result = [];
                            end
                        end

                        % Add the dependencies of the cached result to any other
                        % plugins in the callstack
                        if ~isempty(result) && ~isempty(cache_info)
                            dependencies = cache_info.DependencyList;
                            dataset_stack.AddDependenciesToAllPluginsInStack(dependencies, reporting);

                            dependency = cache_info.InstanceIdentifier;
                            dependency_list_for_this_plugin = PTKDependencyList();
                            dependency_list_for_this_plugin.AddDependency(dependency, reporting);
                            dataset_stack.AddDependenciesToAllPluginsInStack(dependency_list_for_this_plugin, reporting);
                        end

                    end

                    % Run the plugin
                    if isempty(result)
                        plugin_has_been_run = true;

                        % At present we ignore dependency checks if the results are
                        % not permanently cached to disk. This is to ensure we
                        % don't get dependency check errors when a plugin is
                        % fetched twice (by two different plugins) and has to be
                        % generated twice becase the result is not cached.
                        ignore_dependency_checks = plugin_info.DiskCachePolicy ~= MimCachePolicy.Permanent;

                        % Pause the self-timing of the current plugin
                        dataset_stack.PauseTiming();

                        % Create a new dependency. The dependency relates to the plugin
                        % being called (plugin_name) and the UID of the dataset the
                        % result is being requested from; however, the stack belongs to
                        % the primary dataset
                        plugin_version = plugin_info.PluginVersion;
                        dataset_stack.CreateAndPush(plugin_name, output_context, parameters, dataset_uid, ignore_dependency_checks, false, obj.FrameworkAppDef.TimeFunctions, plugin_version, reporting);

                        dataset_callback = MimDatasetCallback(linked_dataset_chooser, dataset_stack, output_context, reporting);

                        try
                            % This is the actual call which runs the plugin
                            if strcmp(plugin_info.PluginInterfaceVersion, '1')
                                result = plugin_class.RunPlugin(dataset_callback, reporting);
                            else
                                result = plugin_class.RunPlugin(dataset_callback, output_context, reporting);
                            end

                            new_cache_info = dataset_stack.Pop();

                            if obj.FrameworkAppDef.TimeFunctions()
                                dataset_stack.ResumeTiming();
                            end

                            if ~strcmp(plugin_name, new_cache_info.InstanceIdentifier.PluginName)
                                reporting.Error('MimContextHierarchy:GetResult', 'Inconsistency in plugin call stack. To resolve this error, try deleting the cache for this dataset.');
                            end

                            % Get the newly calculated list of dependencies for this
                            % plugin
                            dependencies = new_cache_info.DependencyList;

                            % Cache the plugin result according to the specified cache policies
                            obj.DatasetDiskCache.SavePluginResult(plugin_name, result, new_cache_info, output_context, disk_cache_policy, memory_cache_policy, reporting);

                            dataset_stack.AddDependenciesToAllPluginsInStack(dependencies, reporting);

                            dependency = new_cache_info.InstanceIdentifier;
                            dependency_list_for_this_plugin = PTKDependencyList();
                            dependency_list_for_this_plugin.AddDependency(dependency, reporting);
                            dataset_stack.AddDependenciesToAllPluginsInStack(dependency_list_for_this_plugin, reporting);

                            cache_info = new_cache_info;
                        catch ex
                                % For certain plugins we throw a special exception
                                % which indicates that the user should be offered
                                % the ability to create a manual edit
                                if plugin_info.SuggestManualEditOnFailure
                                    throw(MimSuggestEditException(plugin_name, output_context, ex, CoreTextUtilities.RemoveHtml(plugin_class.ButtonText)));
                                else
                                    rethrow(ex);
                                end
                        end

                    else
                        plugin_has_been_run = false;
                    end

                else
                    cache_info = [];
                    plugin_has_been_run = false;
                end

                % Fetch the edited result, if it exists
                if edited_result_exists

                    [edited_result, edited_cache_info] = obj.DatasetDiskCache.LoadEditedPluginResult(plugin_name, output_context, reporting);

                    % If the edited result does not depend on the automated
                    % result, we won't have (and don't need) cache info for the
                    % plugin result so just use the edited result
                    if isempty(cache_info)
                        cache_info = edited_cache_info;
                    end

                    % In case the cache is out of sync with the existance of
                    % the edited result, this will update the cache
                    obj.DatasetDiskCache.UpdateEditedResults(plugin_name, edited_cache_info, output_context, reporting);

                    % Call the plugin to create an edited output
                    result = plugin_class.GetEditedResult(result, edited_result, reporting);

                    % Get the dependency for this edit and add to calling functions
                    edited_dependency = edited_cache_info.InstanceIdentifier;
                    dependency_list_for_edit = PTKDependencyList();
                    dependency_list_for_edit.AddDependency(edited_dependency, reporting);
                    dataset_stack.AddDependenciesToAllPluginsInStack(dependency_list_for_edit, reporting);
                    cache_info.MarkEdited();
                else
                    % In case the cache is out of sync with the existance of
                    % the edited result, this will delete the edited result entry from the cache
                    obj.DatasetDiskCache.UpdateEditedResults(plugin_name, [], output_context, reporting);

                end

                % End of code moved from PluginDependencyTracker

                % If the plugin has been re-run, then we will generate an output
                % image, in order to create a new preview image
                if (plugin_info.GeneratePreview && plugin_has_been_run)
                    force_generate_image = true;
                end

                % We generate an output image if requested, or if the plugin has been re-run (indictaing that we will need to generate a new preview image)
                if force_generate_image
                    output_image = obj.GenerateImageFromResults(result, plugin_class, linked_dataset_chooser, dataset_stack, reporting);
                else
                    output_image = [];
                end

                combined_result = MimCombinedPluginResult(result, output_image, plugin_has_been_run, cache_info);

            % Otherwise, if the plugin's context set is higher in the hierarchy
            % than the requested output, then get the result for the higher
            % context and then extract out the desired context
            elseif output_context_set_mapping.IsOtherContextSetHigher(plugin_context_set_mapping)
                combined_result = MimContextResultCombiner(obj.ImageTemplates);
                higher_context_mapping = output_context_mapping.Parent;
                if isempty(higher_context_mapping)
                    reporting.Error('MimContextHierarchy:UnexpectedSituation', 'The requested plugin call cannot be made as I am unable to determine the relationship between the plugin context and the requested result context.');
                end
                parent_context = higher_context_mapping.Context;
                this_context_results = obj.GetResultRecursive(plugin_name, parent_context, parameters, linked_dataset_chooser, plugin_info, plugin_class, dataset_uid, dataset_stack, force_generate_image, memory_cache_policy, disk_cache_policy, reporting);
                combined_result.AddParentResult(parent_context, this_context_results, output_context, output_context_mapping, dataset_stack, reporting);

            % If the plugin's context set is lower in the hierarchy, then get
            % the plugin result for all lower contexts and concatenate the results
            elseif plugin_context_set_mapping.IsOtherContextSetHigher(output_context_set_mapping)
                combined_result = MimContextResultCombiner(obj.ImageTemplates);
                child_context_mappings = output_context_mapping.Children;

                for child_mapping = child_context_mappings
                    child_context = child_mapping{1}.Context;
                    this_context_results = obj.GetResultRecursive(plugin_name, child_context, parameters, linked_dataset_chooser, plugin_info, plugin_class, dataset_uid, dataset_stack, force_generate_image, memory_cache_policy, disk_cache_policy, reporting);

                    combined_result.AddChildResult(child_context, this_context_results, output_context, output_context_mapping, dataset_stack, reporting);
                end

            else
                reporting.Error('MimContextHierarchy:UnexpectedSituation', 'The requested plugin call cannot be made as I am unable to determine the relationship between the plugin context and the requested result context.');
            end

            % Note that the plugin completed successfully
            obj.ImageTemplates.NoteSuccessRunPlugin(plugin_name, output_context, reporting);

            % Allow pipelines to be run if required
            obj.Pipelines.RunPipelines(plugin_name, output_context, parameters, combined_result.GetPluginHasBeenRun, dataset_stack, dataset_uid, reporting);
        end

        function SaveEditedResultRecursive(obj, plugin_name, input_context, edited_result_image, plugin_info, dataset_stack, dataset_uid, reporting)
            % This function saves a manually edited result which plugins
            % may use to modify their results

            % Determines the context and context type requested by the calling function
            if isempty(input_context)
                reporting.Error('MimContextHierarchy:NoContextSpecified', 'When calling SaveEditedResult(), the contex of the input image must be specified.');
                input_context = obj.ContextDef.GetDefaultContext;
            end

            [plugin_context_set, plugin_context_set_mapping] = obj.GetContextSetMappings(plugin_info.Context);

            [input_context, input_context_set, input_context_mapping, input_context_set_mapping] = obj.GetContextMaps(input_context);

            % If the input and output contexts are of the same type, or if the
            % plugin context is of type 'Any', then proceed to save the results
            % for this context.
            if obj.ContextDef.ContextSetMatches(plugin_context_set, input_context_set)
                plugin_version = plugin_info.PluginVersion;
                obj.SaveEditedResult(plugin_name, input_context, edited_result_image, dataset_uid, plugin_version, reporting);

            % Otherwise, if the input's context set is lower in the hierarchy
            % than that of the plugin, then resize the input to match the plugin
            elseif input_context_set_mapping.IsOtherContextSetHigher(plugin_context_set_mapping)

                higher_context_mapping = input_context_mapping.Parent;
                if isempty(higher_context_mapping)
                    reporting.Error('MimContextHierarchy:UnexpectedSituation', 'The requested plugin call cannot be made as I am unable to determine the relationship between the plugin context and the requested result context.');
                end
                parent_context = higher_context_mapping.Context;
                parent_image_template = obj.ImageTemplates.GetTemplateImage(parent_context, dataset_stack, reporting);
                new_edited_image_for_context_image = edited_result_image.Copy;
                new_edited_image_for_context_image.ResizeToMatch(parent_image_template);
                obj.SaveEditedResultRecursive(plugin_name, parent_context, new_edited_image_for_context_image, plugin_info, dataset_stack, dataset_uid, reporting);

            % If the plugin's context set is lower in the hierarchy, then get
            % reduce the edited image input to each lower context in turn and save to each
            elseif plugin_context_set_mapping.IsOtherContextSetHigher(input_context_set_mapping)

                child_context_mappings = input_context_mapping.Children;

                for child_mapping = child_context_mappings
                    child_context = child_mapping{1}.Context;

                    % Create a new image from the edited result, reduced to this
                    % context
                    new_edited_image_for_context_image = MimReduceResultToContext(edited_result_image, child_mapping{1}.Context, obj.ImageTemplates, dataset_stack, reporting);

                    % Save this new image
                    obj.SaveEditedResultRecursive(plugin_name, child_context, new_edited_image_for_context_image, plugin_info, dataset_stack, dataset_uid, reporting);
                end

            else
                reporting.Error('MimContextHierarchy:UnexpectedSituation', 'The requested plugin call cannot be made as I am unable to determine the relationship between the plugin context and the requested result context.');
            end
        end

        function [valid, edited_result_exists] = CheckDependencyValid(obj, next_dependency, reporting)
            % Checks a given dependency against the cached values to
            % determine if it is valid (ie it depends on the most recent
            % computed results)

            plugin_results_info = obj.DatasetDiskCache.GetPluginResultsInfo();

            if isfield(next_dependency.Attributes, 'IsParameter')
                is_parameter = next_dependency.Attributes.IsParameter;
            else
                is_parameter = false;
            end
            % ToDo: process dependency values

            if isfield(next_dependency.Attributes, 'IsEditedResult')
                is_edited_result = next_dependency.Attributes.IsEditedResult;
            else
                is_edited_result = false;
            end

            if isfield(next_dependency.Attributes, 'IsManualSegmentation')
                is_manual = next_dependency.Attributes.IsManualSegmentation;
            else
                is_manual = false;
            end

            if isfield(next_dependency.Attributes, 'IsMarkerSet')
                is_marker = next_dependency.Attributes.IsMarkerSet;
            else
                is_marker = false;
            end

            if is_manual
                type_of_dependency = 'manual segmentation';
            else
                type_of_dependency = 'plugin';
            end

            edited_result_exists = plugin_results_info.CachedInfoExists(next_dependency.PluginName, next_dependency.Context, MimCacheType.Edited);

            if is_edited_result
                cache_type = MimCacheType.Edited;
            elseif is_manual
                cache_type = MimCacheType.Manual;
            elseif is_marker
                cache_type = MimCacheType.Markers;
            else
                cache_type = MimCacheType.Results;
            end

            % The full list should always contain the most recent dependency
            % uid, unless the dependencies file was deleted
            if ~plugin_results_info.CachedInfoExists(next_dependency.PluginName, next_dependency.Context, cache_type)
                reporting.Log(['No dependency record for this ' type_of_dependency ' - forcing re-run.']);
                valid = false;
                return;
            end

            current_info = plugin_results_info.GetCachedInfo(next_dependency.PluginName, next_dependency.Context, cache_type);
            current_dependency = current_info.InstanceIdentifier;

            if current_info.IgnoreDependencyChecks
                reporting.LogVerbose(['Ignoring dependency checks for ' type_of_dependency ' ' next_dependency.PluginName '(' char(next_dependency.Context) ')']);
            else
                % Sanity check - this case should never occur
                if ~strcmp(next_dependency.DatasetUid, current_dependency.DatasetUid)
                    reporting.Error('MimPluginResultsInfo:DatsetUidError', 'Code error - not matching dataset UID during dependency check');
                end

                if ~strcmp(next_dependency.Uid, current_dependency.Uid)
                    reporting.Log('Mismatch in dependency version uids - forcing re-run');
                    valid = false;
                    return;
                else
                    reporting.LogVerbose(['Dependencies Ok for ' type_of_dependency ' ' next_dependency.PluginName]);
                end
            end

            valid = true;

        end

    end

    methods (Access = private)

        function valid = CheckDependenciesValid(obj, linked_dataset_chooser, dependencies, dataset_stack, parameters_for_next_plugin_call, reporting)
            % Checks the dependencies in this result with the current dependency
            % list, and determine if the dependencies are still valid

            dependency_list = dependencies.DependencyList;

            % Separate dependencies into parameters and plugin
            % dependencies, and also create list of dependencies which are
            % edited values
            plugin_dependencies = {};
            known_edited_values = containers.Map();
            parameter_list = {};
            for index = 1 : length(dependency_list)
                next_dependency = dependency_list(index);
                dataset_uid = next_dependency.DatasetUid;
                if ~known_edited_values.isKey(dataset_uid)
                    known_edited_values(dataset_uid) = {};
                end
                if isfield(next_dependency.Attributes, 'IsParameter') && (next_dependency.Attributes.IsParameter)
                    parameter_list{end + 1} = next_dependency;
                else
                    plugin_dependencies{end + 1} = next_dependency;
                    if ~obj.CheckPluginVersion(next_dependency, reporting)
                        valid = false;
                        reporting.Log(['A newer version of plugin ' next_dependency.PluginName ' has been found. This result must be regenerated.']);
                        return;
                    end
                    if isfield(next_dependency.Attributes, 'IsEditedResult') && (next_dependency.Attributes.IsEditedResult)
                        edited_list = known_edited_values(dataset_uid);
                        edited_list{end + 1} = next_dependency.PluginName;
                        known_edited_values(dataset_uid) = edited_list;
                    end
                end
            end

            if ~dataset_stack.CheckParameterDependencies(parameter_list, parameters_for_next_plugin_call, reporting)
                valid = false;
                return;
            end

            % Iterate through plugin dependencies
            for index = 1 : length(plugin_dependencies)
                next_dependency = plugin_dependencies{index};

                dataset_uid = next_dependency.DatasetUid;
                [valid, edited_result_exists] = linked_dataset_chooser.GetDataset(reporting, dataset_uid).CheckDependencyValid(next_dependency, reporting);
                if ~valid
                    valid = false;
                    return;
                end

                % If the dependency is based on a non-edited result, but we have an edited
                % result in the cache, then this plugin result is invalid
                if edited_result_exists && ~ismember(next_dependency.PluginName, known_edited_values(dataset_uid))
                    reporting.Log(['The result for dependency ' next_dependency.PluginName '(' char(next_dependency.Context) ') has been edited - forcing re-run for plugin.']);
                    valid = false;
                    return;
                end
            end

            valid = true;
        end

        function valid = CheckPluginVersion(obj, next_dependency, reporting)
            if isfield(next_dependency.Attributes, 'PluginVersion')
                dependency_version = next_dependency.Attributes.PluginVersion;
            else
                dependency_version = 1;
            end

            plugin_info = obj.PluginCache.GetPluginInfo(next_dependency.PluginName, [], reporting);
            valid = plugin_info.PluginVersion == dependency_version;
        end

        function [context_set, context_set_mapping] = GetContextSetMappings(obj, context)
            % Determines the type of context supported by the plugin

            context_set = context;
            if isempty(context_set)
                    context_set = obj.ContextDef.GetDefaultContextSet();
            end
            context_set_mapping = obj.ContextSets(char(context_set));
        end

        function [context, context_set, context_mapping, context_set_mapping] = GetContextMaps(obj, context)
            % Determines the context and context type requested by the calling function

            if isempty(context)
                context = obj.ContextDef.GetDefaultContext();
            end
            if obj.Contexts.isKey(char(context))
                context_mapping = obj.Contexts(char(context));
                context_set_mapping = context_mapping.ContextSet;
                context_set = context_set_mapping.ContextSet;
            else
                context_mapping = [];
                context_set_mapping = [];
                context_set = [];
            end
        end

        function output_image = GenerateImageFromResults(obj, result, plugin_class, linked_dataset_chooser, dataset_stack, reporting)
            template_callback = MimTemplateCallback(linked_dataset_chooser, dataset_stack, reporting);

            if isa(result, 'PTKImage')
                output_image = plugin_class.GenerateImageFromResults(result.Copy, template_callback, reporting);
            else
                output_image = plugin_class.GenerateImageFromResults(result, template_callback, reporting);
            end
        end

        function edited_cached_info = SaveEditedResult(obj, plugin_name, context, edited_result, dataset_uid, plugin_version, reporting)
            % Saves the result of a plugin after semi-automatic editing

            attributes = [];
            attributes.IgnoreDependencyChecks = false;
            attributes.IsEditedResult = true;
            attributes.PluginVersion = plugin_version;
            instance_identifier = PTKDependency(plugin_name, context, CoreSystemUtilities.GenerateUid, dataset_uid, attributes);
            edited_cached_info = obj.FrameworkAppDef.GetClassFactory.CreateDatasetStackItem(instance_identifier, PTKDependencyList(), false, false, reporting);
            edited_cached_info.MarkEdited();

            obj.DatasetDiskCache.SaveEditedResult(plugin_name, context, edited_result, edited_cached_info, reporting);
        end
    end
end


function encoder_save(encoder, filePath)
if isfield(encoder, 'net')
  encoder.net = vl_simplenn_move(encoder.net, 'cpu') ;
  encoder.net.useGpu = false ;
end
save(filePath, '-struct', 'encoder') ;


function defaultOptions = prtOptionsGetFactory()
% prtOptionsGetFactory  Get the factory options for the PRT
%   PRT factory options are hard coded in MATLAB class m files stored
%   within the prtOptions package. prtOptionsGetFactory returns a structure
%   with each of these classes loaded into a structure with field names
%   equal to the class names
%
%   defaultOptions = prtOptionsGetFactory()
%
% See also. prtOptionsGet, prtOptionsSet, prtOptionsSetDefault

optionsPackageInfo = meta.package.fromName('prtOptions');

if isempty(optionsPackageInfo)
    error('Package prtOptions was not found on path');
end

for iClass = 1:length(optionsPackageInfo.Classes)
    defaultOptions.(strrep(optionsPackageInfo.Classes{iClass}.Name,'prtOptions.','')) = feval(optionsPackageInfo.Classes{iClass}.Name);
end


function result = file_exist(file_name)

    result = (exist(file_name, 'file') == 2);

end


function [pathstr,name,ext] = filepartsVector(filename)

pathstr = [];
name = [];
ext = [];
for i=1:length(filename)
    [pathstr{i},name{i},ext{i}] = fileparts(filename{i});
end


function planC = createIMuids(planC)
% function planC = createIMuids(planC)
%
% APA, 10/21/2014

if ~exist('planC','var')
    global planC
end

indexS = planC{end};

nIM = length(planC{indexS.IM});
for i = 1:nIM
    % Copy beams, goals, solution, params fields from IMsetup to IMDosimetry
    if ~isfield(planC{indexS.IM}(i),'IMDosimetry') && isfield(planC{indexS.IM}(i),'IMSetup')
        planC{indexS.IM}(i).IMDosimetry = planC{indexS.IM}(i).IMSetup;
    else
        %do nothing asuming IMDosimerty was properly populated
    end

    % check for empty dosimetry and assign default name
    if ~isempty(planC{indexS.IM}(i).IMDosimetry)
        % Assign a default name 'IM doseSet'
        planC{indexS.IM}(i).IMDosimetry.name = 'IM doseSet';
        % Assume Dosimetry (beamlets) is fresh (1=fresh, 2=stale)
        planC{indexS.IM}(i).IMDosimetry.isFresh = 1;
    end

    % check for empty IMUID field assign default IMUID
    if isfield(planC{indexS.IM}(i),'IMUID') && isempty(planC{indexS.IM}(i).IMUID)
        planC{indexS.IM}(i).IMUID = createUID('IM');
    end

    % check for empty beamUID field assign default beamUID
    if (isfield(planC{indexS.IM}(i).IMDosimetry,'beams') && ~isempty(planC{indexS.IM}(i).IMDosimetry.beams)) ...
            && ((isfield(planC{indexS.IM}(i).IMDosimetry.beams(1),'beamUID') && isempty(planC{indexS.IM}(i).IMDosimetry.beams(1).beamUID)) || ~isfield(planC{indexS.IM}(i).IMDosimetry.beams(1),'beamUID'))
        for iBeam = 1:length(planC{indexS.IM}(i).IMDosimetry.beams)
            planC{indexS.IM}(i).IMDosimetry.beams(iBeam).beamUID = createUID('BEAM');
        end
    end

    % Link structure UID to goals
    if isfield(planC{indexS.IM}(i).IMDosimetry,'goals')
        for j = 1:length(planC{indexS.IM}(i).IMDosimetry.goals)
            structNum = planC{indexS.IM}(i).IMDosimetry.goals(j).structNum;
            if isempty(planC{indexS.IM}(i).IMDosimetry.goals(j).strUID)
                planC{indexS.IM}(i).IMDosimetry.goals(j).strUID = planC{indexS.structures}(structNum).strUID;
            end
        end

        % Link scan UID to IM
        if isempty(planC{indexS.IM}(i).IMDosimetry.assocScanUID)
            planC{indexS.IM}(i).IMDosimetry.assocScanUID = planC{indexS.scan}(1).scanUID;
        end

        % put beamlets under its parent beam
        if isfield(planC{indexS.IM}(i).IMDosimetry,'beamlets')
            structPresentV = ~cellfun('isempty',squeeze({planC{indexS.IM}(i).IMDosimetry.beamlets.beamNum}));
            structPresentM = reshape(structPresentV,size(planC{indexS.IM}(i).IMDosimetry.beamlets));
            beamletTotal = 0;
            for beamNum = 1:length(planC{indexS.IM}(i).IMDosimetry.beams)
                numBeamlets = length(planC{indexS.IM}(i).IMDosimetry.beams(beamNum).xPBPosV);
                planC{indexS.IM}(i).IMDosimetry.beams(beamNum).beamlets = planC{indexS.IM}(i).IMDosimetry.beamlets(structPresentM(:,1),beamletTotal+1:beamletTotal+numBeamlets);
                beamletTotal = beamletTotal + numBeamlets;
            end

            % assign strUID
            count = 0;
            strPresentV = find(structPresentM(:,1));
            for strNum = 1:length(strPresentV)
                count = count + 1;
                for beamNum = 1:length(planC{indexS.IM}(i).IMDosimetry.beams)
                    [planC{indexS.IM}(i).IMDosimetry.beams(beamNum).beamlets(count,:).strUID] = deal(planC{indexS.structures}(strPresentV(strNum)).strUID);
                end
            end

            % remove beamlets field from IMDosimetry since it is a part of beams now
            planC{indexS.IM}(i).IMDosimetry = rmfield(planC{indexS.IM}(i).IMDosimetry,'beamlets');

        end

        %rename solution to solutions
        if isfield(planC{indexS.IM}(i).IMDosimetry,'solution')
            planC{indexS.IM}(i).IMDosimetry.solutions =  planC{indexS.IM}(i).IMDosimetry.solution;
            planC{indexS.IM}(i).IMDosimetry = rmfield(planC{indexS.IM}(i).IMDosimetry,'solution');
        end

    end
end


function labels=cookLabels(labelsRaw)
% Make sure the labels only contains the fields we want from the raw labels.

% ALTODO: remove me or put in Labels

nLabels=length(labelsRaw);
labels = ...
  struct('t0s',cell(1,nLabels), ...
         't1s',cell(1,nLabels), ...
         'names',cell(1,nLabels), ...
         'flies',cell(1,nLabels), ...
         'off',cell(1,nLabels), ...
         'timestamp',cell(1,nLabels), ...
         'imp_t0s',cell(1,nLabels), ...
         'imp_t1s',cell(1,nLabels));
fieldNames=fieldnames(labels);
for i=1:nLabels
  for j=1:length(fieldNames)
    fieldName=fieldNames{j};
    labels(i).(fieldName)=labelsRaw(i).(fieldName);
  end
end

end


function [tmpTrace] = plotSignalsGraph(IcaTraces,varargin)
	% Plots signals, offsetting by a fixed amount.
	% Biafra Ahanonu
	% started: 2013.11.02
	% inputs
		%
	% outputs
		%

	[tmpTrace] = ciapkg.view.plotSignalsGraph(IcaTraces,'passArgs', varargin);
end


classdef nme_load_acc < mp.nme_load_ac & mp.form_acc

%   MATPOWER
%   Copyright (c) 2019-2020, Power Systems Engineering Research Center (PSERC)
%   by Ray Zimmerman, PSERC Cornell
%
%   This file is part of MATPOWER.
%   Covered by the 3-clause BSD License (see LICENSE file for details).
%   See https://matpower.org for more info.

%     properties
%     end     %% properties

%     methods
%     end     %% methods
end         %% classdef


function out = cf(func,varargin)
%CF Convenience wrapper for cellfun with non-uniform output.
% Usage:
%   out = cf(func, C); % equivalent to out = cellfun(func, C, 'UniformOutput, false)

out = cellfun(func, varargin{:}, 'UniformOutput', false);

end


function installSegmentation(query, keepAllNodes, filePaths, numGrayLayers)
%
% function installSegmentation(query, keepAllNodes, filePaths, numGrayLayers)
%
% Rebuild coords after a new segmentation.
%
% Note: could automatically rebuild Gray/corAnals by xforming from inplane, but we
% would have to do this for each dataType.
%
% 12/8/00 Wandell and Huk
% djh, 2/14/2001
%    Uses hiddenGray and hiddenFlat structures rather than opening windows.
%    Uses fullfile rather than cd'ing into the directory
% ras, dy, al 01/09: added option to keep all nodes from each hemisphere.
% ras 06/09: eliminated a redundant set of file requests. Streamlined the
% logic, so it doesn't call a large series of nested files. Condensed file
% selection to a single dialog, which guesses reasonable defaults.

if ~exist('query','var')
	% query only if Gray, Volume, or Flat files are found
	global HOMEDIR %#ok<TLEV> %
	w1 = dir( fullfile(HOMEDIR, 'Volume*') );
	w2 = dir( fullfile(HOMEDIR, 'Gray*') );
	w3 = dir( fullfile(HOMEDIR, 'Flat*') );
	if (~isempty(w1) || ~isempty(w2) || ~isempty(w3))
		query = 1;
	else
		query = 0;
	end
end

% if keepAllNodes is true, we store coordinates for all gray voxels. If it
% is false, then we only store gray voxels within the functional field of
% view. The latter is more resource efficient. The former has greater
% flexibility, for example to visualize ROIs on a mesh that extend beyond
% the field of view from a particular session.
if ~exist('keepAllNodes','var'), keepAllNodes=0; end

if notDefined('filePaths')
	% get a set of file paths in a dialog
	filePaths = segmentationFilesDialog;
    if isempty(filePaths), return; end
end

if ~exist('numGrayLayers', 'var')
    resp = inputdlg('number of gray layers?', 'enter a number', 1, {'3'});
    numGrayLayers = str2double(resp);
end

if query
    resp = questdlg('Delete Gray and all Flat data files and close all Gray and Flat windows?');
else
    resp = 'Yes';
end

% delete coords and rebuild
if ~strcmp(resp,'Yes')
	disp('Coords, corAnal, and parameter map files not deleted.');
    return;
end
closeAllGrayWindows;
closeAllFlatWindows;

% Deletes coords, corAnal, and other parameter map files
cleanGray;
cleanAllFlats;

% ras 06/09: initially the logic was different here. The function would
% call 'initHiddenGray', which in turn would call 'switch2Gray', which
% would call 'getGrayCoords', which would detect that you wanted to
% rebuild, then call 'buildGrayCoords'. This was a little confusing, but
% moreover didn't work if you wanted to keep all nodes (most of the
% intermediate functions don't allow such a parameter, and it wouldn't make
% much sense most of the time). So, I make it more direct here.

% build the gray coordinates fields (this saves the coords.mat file)
if keepAllNodes==1
	% the gray nodes/edges are either loaded or built in the call to
	% initHiddenGray above. It is awkward to pass a flag to this
	% function to load all nodes, so we recompute the nodes/edges here.
    if prefsVerboseCheck >= 1
        fprintf('[%s]: Rebuilding Gray coordinates with ALL nodes. \n', ...
            mfilename);
    end
else
    if prefsVerboseCheck >= 1
        fprintf(['[%s]: Rebuilding Gray coordinates with nodes only ' ...
            'where the inplanes have data. \n'], mfilename);
    end
end
buildGrayCoords([], [], keepAllNodes, filePaths, numGrayLayers);

disp('Rebuilt Gray coords. Deleted old corAnal and parameter map files.');

return;
% /-----------------------------------------------------------/ %

% /-----------------------------------------------------------/ %
function filePaths = segmentationFilesDialog
% dialog to get the file paths for installing a segmentation.

%% first, guess default paths
defaultClass = '';

try

    pattern = fullfile(pwd, '3DAnatomy', '*class*nii*');
	w = dir(pattern);
	if ~isempty(w),
		defaultClass = fullfile(pwd, '3DAnatomy', w(1).name);
	end

catch ME
    warning(ME.identifier, ME.mesage);
	% can't get it? don't worry...

end

%% now build the dialog structure
dlg(1).fieldName	= 'classFile';
dlg(end).style		= 'filename';
dlg(end).string		= 'Classification File (NIFTI)?';
dlg(end).value		= defaultClass;

%% put the dialog to the user
[resp, ok] = generalDialog(dlg, 'Install Gray Segmentation');
if ~ok
	filePaths = [];
    fprintf('User aborted.\n');
    return;
end

%% parse the response
filePaths = resp.classFile;

return


function [ fileList, fileFormat, fileFilter ] = java_getfile( DialogType, WindowTitle, DefaultDir, SelectionMode, FilesOrDir, Filters, defaultFilter)
% JAVA_GETFILE: Java-based file selection for opening and saving.
%
% USAGE: [fileList, fileFormat, fileFilter] = java_getfile(DialogType,WindowTitle,DefaultDir,SelectionMode, FilesOrDir,Filters,defaultFilter)
%
% INPUT :
%    - DialogType    : {'open', 'save'}
%    - WindowTitle   : String
%    - DefaultDir    : To ignore, set to []
%    - SelectionMode : {'single', 'multiple'}
%    - FilesOrDir    : {'files', 'dirs', 'files_and_dirs'}
%    - Filters       : {NbFilters x 2} cell array
%                      Filters(i,:) = {{'.ext1', '.ext2', '_tag1'...}, Description}
%    - defaultFilter : can be 1) the index of the default file filter
%                             2) the name of the filer to be used
% OUTPUT:
%    - fileList      : Cell-array of strings, full paths to the files that were selected
%    - fileFormat    : String that represents the format of the files that were selected
%    - fileFilter    : File filter that was selected when selecting the files

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2008-2014

import org.brainstorm.file.*;

global GlobalData FileSelectorStatus;

%% ===== CONFIGURE DIALOG =====
% Initialize returned variables
fileList   = {};
fileFormat = '';
fileFilter = [];

% DialogType
if strcmpi(DialogType, 'save')
    DialogType = BstFileSelector.TYPE_SAVE;
else
    DialogType = BstFileSelector.TYPE_OPEN;
end
% SelectionMode
if strcmpi(SelectionMode, 'multiple')
    SelectionMode = BstFileSelector.SELECTION_MULTIPLE;
else
    SelectionMode = BstFileSelector.SELECTION_SINGLE;
end
% Files and/or directories
switch lower(FilesOrDir)
    case 'dirs'
        FilesOrDir = BstFileSelector.DIRECTORIES_ONLY;
    case 'files_and_dirs'
        FilesOrDir = BstFileSelector.FILES_AND_DIRECTORIES;
    otherwise
        FilesOrDir = BstFileSelector.FILES_ONLY;
end
% Default folder: user folder
if isempty(DefaultDir)
    DefaultDir = bst_get('UserDir');
end

% Filters
iDefaultFileFilter = 1;
for i=1:size(Filters, 1)
    % Filters cell array has the following format:
    %   - One row per filter,
    %   - A filter row can be {{'extensions_list'}, 'Description', 'FormatName'}
    %                      or {{'extensions_list'}, 'Description'}
    if (size(Filters, 2) == 3)
        fileFilters(i) = java_create('org.brainstorm.file.BstFileFilter', '[Ljava.lang.String;Ljava.lang.String;Ljava.lang.String;', Filters{i,1}, Filters{i,2}, Filters{i,3});
    else
        fileFilters(i) = java_create('org.brainstorm.file.BstFileFilter', '[Ljava.lang.String;Ljava.lang.String;', Filters{i,1}, Filters{i,2});
    end
    % If it is default file filter
    if ~isempty(defaultFilter) && (isnumeric(defaultFilter) && (i == defaultFilter)) || ...
            (ischar(defaultFilter) && (size(Filters, 2) == 3) && strcmpi(Filters{i,3}, defaultFilter))
        iDefaultFileFilter = i;
    end
end

% If a progress bar is displayed : hide it while displaying the file selector
pBar = GlobalData.Program.ProgressBar;
if ~isempty(pBar) && isfield(pBar, 'jWindow') && java_call(pBar.jWindow, 'isVisible')
    pBarHidden = 1;
    bst_progress('hide');
else
    pBarHidden = 0;
end

%% ===== HIDE MODAL WINDOWS =====
% Get brainstorm frame
jBstFrame = bst_get('BstFrame');
% If the frame is defined
if ~isempty(jBstFrame)
    jDialogModal = [];
    jDialogAlwaysOnTop = [];
    for i=1:length(GlobalData.Program.GUI.panels)
        panelContainer = get(GlobalData.Program.GUI.panels(i), 'container');
        panelContainer = panelContainer.handle{1};
        if isa(panelContainer, 'javax.swing.JDialog') && java_call(panelContainer, 'isModal')
            % A modal JDialog is found => Set it non non-modal
            jDialogModal = panelContainer;
            java_call(jDialogModal, 'setModal', 'Z', 0);
        end
        if (isa(panelContainer, 'javax.swing.JDialog') || isa(panelContainer, 'javax.swing.JFrame')) && java_call(panelContainer, 'isAlwaysOnTop')
            % An AlwaysOnTop frame is found => Remove always on top attribute
            jDialogAlwaysOnTop = panelContainer;
            java_call(jDialogAlwaysOnTop, 'setAlwaysOnTop', 'Z', 0);
        end
    end
end

%% ===== CREATE SELECTION DIALOG =====
% Initialize dialog status
FileSelectorStatus = 0;
% Create object
jBstSelector = java_create('org.brainstorm.file.BstFileSelector', 'ILjava.lang.String;Ljava.lang.String;II[Lorg.brainstorm.file.BstFileFilter;I', ...
                           DialogType, WindowTitle, DefaultDir, SelectionMode, FilesOrDir, fileFilters, iDefaultFileFilter - 1);
% Initialize a mutex (a figure that will be closed in the BstFileSelector close callback)
bst_mutex('create', 'FileSelector');
% Get JFileChooser dialog
jFileChooser = java_call(jBstSelector, 'getJFileChooser');
% Set dialog callback
java_setcb(jFileChooser, 'ActionPerformedCallback', @FileSelectorAction, ...
                         'PropertyChangeCallback',  @FileSelectorPropertyChanged);
drawnow;
% Display file selector
java_call(jBstSelector, 'showSameThread');
% MAGIC: Print something to the console output to get it to flush something, if not it crashes on MacOS 10.9.2
drawnow;
fprintf(1, ' \b');
% Wait for the file selector to be closed by the user
if ~isempty(bst_mutex('get', 'FileSelector'))
    bst_mutex('waitfor', 'FileSelector');
end

%% ===== PROCESS SELECTED FILES =====
% If user clicked OK after having selected a valid file
if FileSelectorStatus
    % Get file filter => file format
    fileFilter = java_call(jFileChooser, 'getFileFilter');
    fileFormat = char(java_call(fileFilter, 'getFormatName'));

    % If multiple selection
    if (SelectionMode == BstFileSelector.SELECTION_MULTIPLE)
        % Get selected files
        fs = java_call(jFileChooser, 'getSelectedFiles');
        % Convert them to a cell array of filenames
        fileList = cell(length(fs), 1);
        for i=1:length(fs)
            fileList{i} = char(java_call(fs(i), 'getAbsolutePath'));
        end
    % Else: single selection
    else
        % Get selected file
        fileList = char(java_call(jFileChooser, 'getSelectedFile'));

        % If SAVE dialog
        if (DialogType == BstFileSelector.TYPE_SAVE)
            % Get required extension
            suffix = fileFilter.getSuffixes();
            suffix = char(suffix(1));
            % Replace current extension with required extension (ONLY IF SUFFIX IS EXTENSION)
            if (suffix(1) == '.') && ~isequal(suffix, '.folder')
                [selPath, selBase, selExt] = bst_fileparts(fileList);
                fileList = bst_fullfile(selPath, [selBase, suffix]);
            end

            % If file already exist
            if file_exist(fileList) && ~isequal(suffix, '.folder')
                if ~java_dialog('confirm', sprintf('File already exist.\nDo you want to overwrite it?'), 'Save file')
                    fileList = [];
                    fileFormat = [];
                    fileFilter = [];
                end
            end
        end
    end
else
    fileList = [];
end

% Restore modal panels
if ~isempty(jBstFrame)
    if ~isempty(jDialogModal)
        java_call(jDialogModal, 'setModal', 'Z', 1);
    end
    if ~isempty(jDialogAlwaysOnTop)
        java_call(jDialogAlwaysOnTop, 'setAlwaysOnTop', 'Z', 1);
    end
end
% Restore progress bar
if pBarHidden
    bst_progress('show');
end

%% ===== CALLBACK FUNCTION =====
    function FileSelectorAction(h, ev)
        switch (char(java_call(ev, 'getActionCommand')))
            case 'ApproveSelection'
                FileSelectorStatus = 1;
            otherwise
                FileSelectorStatus = 0;
        end
        % Release mutex
        bst_mutex('release', 'FileSelector');
    end

    function FileSelectorPropertyChanged(h, ev)
        import org.brainstorm.file.*;
        % Only when saving
        if (DialogType == BstFileSelector.TYPE_SAVE)
            switch char(java_call(ev, 'getPropertyName'))
                case 'fileFilterChanged'
                    % Get new filter
                    newFilter = java_call(ev, 'getNewValue');
                    % New suffix
                    newSuffix = java_call(newFilter, 'getSuffixes');
                    newSuffix = char(newSuffix(1));
                    if isequal(newSuffix, '.folder')
                        newSuffix = '';
                    end
                    % Get old filename
                    selFile = java_call(jFileChooser, 'getSelectedFile');
                    if isempty(selFile)
                        oldFilename = DefaultDir;
                    else
                        jSelFile = java_call(jFileChooser, 'getSelectedFile');
                        oldFilename = char(java_call(jSelFile, 'getAbsolutePath'));
                    end

                    % Replace old extension by new one
                    [fPath, fBase, fExt] = bst_fileparts(oldFilename);
                    % Brainstorm or external file
                    if ~isempty(newSuffix) && (newSuffix(1) == '_')
                        fBase = strrep(fBase, ['_' newSuffix(2:end)], '');
                        fBase = strrep(fBase, [newSuffix(2:end) '_'], '');
                        fBase = [newSuffix(2:end) '_' fBase];
                        fExt  = '.mat';
                    else
                        fExt = newSuffix;
                    end
                    newFilename = bst_fullfile(fPath, [fBase, fExt]);
                    % Update default filename
                    java_call(jFileChooser, 'setSelectedFile', 'Ljava.io.File;', java_create('java.io.File', 'Ljava.lang.String;', newFilename));

                case 'directoryChanged'
                    DefaultDir = strrep(DefaultDir, char(java_call(ev, 'getOldValue')), char(java_call(ev, 'getNewValue')));
            end
        end
    end
end


function camPDSanityCheck(pds_filename,fa_filename,model_type)

if notDefined('model_type')
    model_type = 'dteig';
end

cmd = ['pdview -inputmodel ' model_type ' `analyzeheader -printprogargs ' fa_filename ' pdview` -scalarfile ' fa_filename ' < ' pds_filename];
display(cmd);
system(cmd,'-echo');


% Uncomment below if "cannot figure out class error"
% http://in.mathworks.com/matlabcentral/answers/137332-error-using-matlab-compiler-app-applicationcompiler-dependency-analysis

% f = dir(fullfile(matlabroot, 'toolbox', 'slvnv'));
% for i=1:length(f)
% rmpath(fullfile(matlabroot, 'toolbox', 'slvnv', f(i).name));
% end
%

mcc -o computeFeaturesCompiled -W main:computeFeaturesCompiled ...
  -T link:exe -d /home/mayank/work/FlySpaceTime/code/ ...
  -v /home/mayank/work/FlySpaceTime/code/computeFeaturesCompiled.m ...
  -a /home/mayank/work/FlySpaceTime/code/deepmatching/deepmex.mexa64 ...
  -a /home/mayank/work/FlySpaceTime/code/filehandling ...
  -a /home/mayank/work/FlySpaceTime/code/misc ...
  -a /home/mayank/work/FlySpaceTime/code/optflow_deqing ...
  -a /home/mayank/work/FlySpaceTime/code/toolbox

delete('readme.txt')
delete('mccExcludedFiles.log')
delete('requiredMCRProducts.txt')
delete('PackagingLog.txt')


function string = user_string(string_name, string)
%USER_STRING  Get/set a user specific string
%
% Examples:
%   string  = user_string(string_name)
%   isSaved = user_string(string_name, new_string)
%
% Function to get and set a string in a system or user specific file. This
% enables, for example, system specific paths to binaries to be saved.
%
% The specified string will be saved in a file named <string_name>.txt,
% either in a subfolder named .ignore under this file's folder, or in the
% user's prefdir folder (in case this file's folder is non-writable).
%
% IN:
%   string_name - String containing the name of the string required, which
%                 sets the filename storing the string: <string_name>.txt
%   new_string  - The new string to be saved in the <string_name>.txt file
%
% OUT:
%   string  - The currently saved string. Default: ''
%   isSaved - Boolean indicating whether the save was succesful

% Copyright (C) Oliver Woodford 2011-2014, Yair Altman 2015-

% This method of saving paths avoids changing .m files which might be in a
% version control system. Instead it saves the user dependent paths in
% separate files with a .txt extension, which need not be checked in to
% the version control system. Thank you to Jonas Dorn for suggesting this
% approach.

% 10/01/2013 - Access files in text, not binary mode, as latter can cause
%              errors. Thanks to Christian for pointing this out.
% 29/05/2015 - Save file in prefdir if current folder is non-writable (issue #74)

    if ~ischar(string_name)
        error('string_name must be a string.');
    end
    % Create the full filename
    fname = [string_name '.txt'];
    dname = fullfile(fileparts(mfilename('fullpath')), '.ignore');
    file_name = fullfile(dname, fname);
    if nargin > 1
        % Set string
        if ~ischar(string)
            error('new_string must be a string.');
        end
        % Make sure the save directory exists
        %dname = fileparts(file_name);
        if ~exist(dname, 'dir')
            % Create the directory
            try
                if ~mkdir(dname)
                    string = false;
                    return
                end
            catch
                string = false;
                return
            end
            % Make it hidden
            try
                fileattrib(dname, '+h');
            catch
            end
        end
        % Write the file
        fid = fopen(file_name, 'wt');
        if fid == -1
            % file cannot be created/updated - use prefdir if file does not already exist
            % (if file exists but is simply not writable, don't create a duplicate in prefdir)
            if ~exist(file_name,'file')
                file_name = fullfile(prefdir, fname);
                fid = fopen(file_name, 'wt');
            end
            if fid == -1
                string = false;
                return;
            end
        end
        try
            fprintf(fid, '%s', string);
        catch
            fclose(fid);
            string = false;
            return
        end
        fclose(fid);
        string = true;
    else
        % Get string
        fid = fopen(file_name, 'rt');
        if fid == -1
            % file cannot be read, try to read the file in prefdir
            file_name = fullfile(prefdir, fname);
            fid = fopen(file_name, 'rt');
            if fid == -1
                string = '';
                return
            end
        end
        string = fgetl(fid);
        fclose(fid);
    end
end


%  Start a subsubsection
%
%  ::
%
%     document.subsubsection('option_name',option_value);
%
%  Args:
%
%     varargin: arguments need to come in pairs
%
%        - **title** : title of the subsubsection
%        - **numbering** : [{true}|false] whether to include the subsubsection in numbering of the table of contents
%
%


function quer(str);
% function quer(str);
% Query user
% if str=='c' Continue or not
% if str=='g' close Graphs or not
str=upper(str);
switch str
case 'C'

    button=questdlg('Continue? Y/N',...
        'Continue Program',...
        'Yes','No','Yes');
    switch button
    case 'No'
        error('Program execution stopped');
    case 'Yes'
        fprintf('%-30%s \n','  ');
    end
case 'G'
    button=questdlg('Close All Graphs Y/N?','Graphs','No','Yes','Yes');
    switch button
    case 'No'
        fprintf('%-30%s \n','  ');
    case 'Yes'
        close all;
    end
end


function ft_sourcewrite(cfg, source)

% FT_SOURCEWRITE exports source-reconstructed results to gifti or nifti format file.
% The appropriate output file depends on whether the source locations are described by
% on a cortically constrained sheet (gifti) or by a regular 3D lattice (nifti).
%
% Use as
%  ft_sourcewrite(cfg, source)
% where source is a source structure obtained from FT_SOURCEANALYSIS and
% cfg is a structure that should contain
%
%  cfg.filename  = string, filename without the extension
%  cfg.filetype  = string, can be 'nifti', 'gifti' or 'cifti' (default is automatic)
%  cfg.parameter = string, functional parameter to be written to file
%  cfg.precision = string, can be 'single', 'double', etc.
%
% To facilitate data-handling and distributed computing you can use
%   cfg.inputfile   =  ...
% If you specify this the input data will be read from a *.mat
% file on disk. This mat file should contain only a single variable,
% corresponding with the input data structure.
%
% See also FT_SOURCEANALYSIS, FT_SOURCEDESCRIPTIVES, FT_VOLUMEWRITE

% Copyright (C) 2011, Jan-Mathijs Schoffelen
% Copyright (C) 2011-2014, Jan-Mathijs Schoffelen, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip 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.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

% these are used by the ft_preamble/ft_postamble function and scripts
ft_revision = '$Id$';
ft_nargin   = nargin;
ft_nargout  = nargout;

% do the general setup of the function
ft_defaults
ft_preamble init
ft_preamble debug
ft_preamble loadvar source
ft_preamble provenance source
ft_preamble trackconfig

% the ft_abort variable is set to true or false in ft_preamble_init
if ft_abort
  return
end

% ensure that the required options are present
cfg = ft_checkconfig(cfg, 'required', {'parameter', 'filename'});

% get the options
cfg.parameter      = ft_getopt(cfg, 'parameter');
cfg.filename       = ft_getopt(cfg, 'filename');
cfg.filetype       = ft_getopt(cfg, 'filetype');        % the default is determined further down
cfg.brainstructure = ft_getopt(cfg, 'brainstructure');  % is used for cifti
cfg.parcellation   = ft_getopt(cfg, 'parcellation');    % is used for cifti
cfg.precision      = ft_getopt(cfg, 'precision');       % is used for cifti

% check if the input data is valid for this function
if strcmp(cfg.filetype, 'cifti')

  % keep the transformation matrix
  if isfield(source, 'transform')
    transform = source.transform;
  elseif isfield(source, 'brainordinate') && isfield(source.brainordinate, 'transform')
    transform = source.brainordinate.transform;
  else
    transform = [];
  end

  if isfield(source, 'brainordinate')
    % it is a parcellated source representation, i.e. the main structure one channel for each parcel
    brainordinate = source.brainordinate;
    source = rmfield(source, 'brainordinate');

    % split them and check individually
    source        = ft_checkdata(source, 'datatype', {'timelock', 'freq', 'chan'}, 'feedback', 'yes');
    brainordinate = ft_checkdata(brainordinate, 'datatype', 'parcellation', 'parcellationstyle', 'indexed', 'hasunit', 'yes');

    % merge them again
    source = copyfields(brainordinate, source, setdiff(fieldnames(brainordinate), {'cfg'}));
  else
    source = ft_checkdata(source, 'datatype', 'source', 'hasunit', true, 'feedback', 'yes');
  end

  % keep the transformation matrix
  if ~isempty(transform)
    source.transform = transform;
  end

end % if cifti

if isempty(cfg.filetype)
  if isfield(source, 'dim')
    % source positions are on a regular 3D lattice, save as nifti
    cfg.filetype = 'nifti';
  elseif isfield(source, 'tri')
    % there is a specification of a 2D cortical sheet, save as gifti
    cfg.filetype = 'gifti';
  else
    ft_error('the input data does not look like a 2D sheet, nor as a 3D regular volume');
  end
end

switch (cfg.filetype)
  case 'nifti'
    if numel(cfg.filename)<=4 || ~strcmp(cfg.filename(end-3:end), '.nii');
      cfg.filename = cat(2, cfg.filename, '.nii');
    end

    % convert functional data into 4D
    dat = getsubfield(source, cfg.parameter);
    dat = reshape(dat, source.dim(1), source.dim(2), source.dim(3), []);

    if ~isfield(source, 'transform')
      source.transform = pos2transform(source.pos);
    end

    % this is a bit of a kludge, but ft_write_mri can write 3D and 4D nifti
    ft_write_mri(cfg.filename, dat, 'dataformat', 'nifti', 'transform', source.transform);

  case 'gifti'
    if numel(cfg.filename)<=4 || ~strcmp(cfg.filename(end-3:end), '.gii');
      cfg.filename = cat(2, cfg.filename, '.gii');
    end

    % this is a bit of a kludge, but ft_write_headshape can write gifti including data
    ft_write_headshape(cfg.filename, source, 'data', getsubfield(source, cfg.parameter), 'format', 'gifti');

  case 'cifti'
    % brainstructure should represent the global anatomical structure, such as CortexLeft, Thalamus, etc.
    % parcellation should represent the detailled parcellation, such as BA1, BA2, BA3, etc.
    ft_write_cifti(cfg.filename, source, 'parameter', cfg.parameter, 'brainstructure', cfg.brainstructure, 'parcellation', cfg.parcellation, 'precision', cfg.precision);

  otherwise
    ft_error('unsupported output format "%s"', cfg.filetype);
end % switch filetype

ft_postamble debug
ft_postamble trackconfig
ft_postamble previous source
ft_postamble provenance


%% set up path

[~,computername] = system('hostname');
computername = strtrim(computername);

switch computername,

  case 'bransonk-lw1',

    JCtrax_path = 'E:\Code\JCtrax';
    %FlyBowlAnalysis_path = 'E:\Code\FlyBowlAnalysis';
    %rootdatadir = 'E:\Code\Jdetect\larva\fly_data\TrainingData';
    %settingsdir = 'E:\Code\FlyBowlAnalysis\settings';
    configfilename = 'params\JLabelParams.xml';
    npool = 4;

  case 'bransonk-lw2',

    JCtrax_path = 'C:\Code\JCtrax';
    %FlyBowlAnalysis_path = 'C:\Code\FlyBowlAnalysis';
    %rootdatadir = 'C:\Code\Jdetect\larva\fly_data\TrainingData';
    %settingsdir = 'C:\Code\FlyBowlAnalysis\settings';
    configfilename = 'params\JLabelParamsKristinChase.xml';
    npool = 4;

  case 'bransonk-desktop',

    JCtrax_path = '/groups/branson/home/bransonk/tracking/code/JCtrax';
    %FlyBowlAnalysis_path = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis';
    %rootdatadir = '/groups/branson/home/bransonk/behavioranalysis/code/Jdetect/Jdetect/larva/fly_data/TrainingData/';
    %settingsdir = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis/settings';
    configfilename = 'params/JLabelParams_bransonk-desktop.xml';
    npool = 8;

  case 'kabram-ws.janelia.priv',

    JCtrax_path = '/groups/branson/home/bransonk/tracking/code/JCtrax';
    %FlyBowlAnalysis_path = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis';
    %rootdatadir = '/groups/branson/home/bransonk/behavioranalysis/code/Jdetect/Jdetect/larva/fly_data/TrainingData/';
    %settingsdir = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis/settings';
    configfilename = 'params/JLabelParamsMayank.xml';
    npool = 8;

  case 'robiea-ws'
    JCtrax_path = '/groups/branson/home/bransonk/tracking/code/JCtrax';
    %FlyBowlAnalysis_path = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis';
    %rootdatadir = '/groups/sciserv/flyolympiad/Olympiad_Screen/fly_bowl/bowl_data';
    %settingsdir = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis/settings';
    configfilename = '/groups/branson/home/robiea/Projects_data/JLabel/JLabelParams.xml';
    npool = 8;

  otherwise

    warning('Unknown computer %s. Paths may not be setup correctly',computername);
    JCtrax_path = '/groups/branson/home/bransonk/tracking/code/JCtrax';
    %FlyBowlAnalysis_path = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis';
    %rootdatadir = '/groups/branson/home/bransonk/behavioranalysis/code/Jdetect/Jdetect/larva/fly_data/TrainingData/';
    %settingsdir = '/groups/branson/bransonlab/projects/olympiad/FlyBowlAnalysis/settings';
    configfilename = 'params/JLabelParams_bransonk-desktop.xml';
    npool = 1;

end

addpath(genpath(fullfile(JCtrax_path,'pdollar_toolbox')));
addpath(fullfile(JCtrax_path,'misc'));
addpath(fullfile(JCtrax_path,'filehandling'));
jlabelpath = fileparts(which('JLabel'));
addpath(fullfile(jlabelpath,'compute_perframe_features'));
%addpath(FlyBowlAnalysis_path);

%% parameters

rootdatadir = '/groups/branson/bransonlab/projects/olympiad/HackHitData';
perframe_params = struct;
perframe_params.fov = pi;
perframe_params.thetafil = [.0625,.25,.375,.25,.0635];
perframe_params.nbodylengths_near = 2.5;
perframe_params.max_dnose2ell_anglerange = 127;

experiment_names = {
  'GMR_65C11_AE_01_TrpA_Rig2Plate14BowlD_20110407T083514'
  'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110707T085804'
  'GMR_71G01_AE_01_TrpA_Rig2Plate14BowlC_20110707T154934'
  'GMR_26F09_AE_01_TrpA_Rig2Plate17BowlD_20110817T133217'
  'pBDPGAL4U_TrpA_Rig2Plate14BowlD_20110615T164545'
  'pBDPGAL4U_TrpA_Rig1Plate15BowlB_20110922T145928'
  'GMR_53B02_AE_01_TrpA_Rig1Plate15BowlC_20110930T140347'
  'GMR_94B10_AE_01_TrpA_Rig1Plate15BowlC_20111007T155325'
  };

perframefns = {'dnose2ell_angle_30tomin30'
  'dnose2ell_angle_min20to20'
  'dnose2ell_angle_min30to30'
  'dnose2tail'
  'nflies_close'
  'angleonclosestfly'};

%%

parfor i = 1:numel(experiment_names),
  expdir = fullfile(rootdatadir,experiment_names{i});
  fprintf('%s...\n',experiment_names{i});
  trx = Trx('trxfilestr','registered_trx.mat','perframe_params',perframe_params);
  trx.AddExpDir(expdir);
  for j = 1:numel(perframefns),
    fprintf('  %s...\n',perframefns{j});
    trx.(perframefns{j}); %#ok<VUNUS>
  end
end


function startup()

curdir = fileparts(mfilename('fullpath'));

% set to edge_boxes_path the path where the edge boxes code
% (https://github.com/pdollar/edges) is installed
edge_boxes_path = '../edges/';
if exist(edge_boxes_path,'dir') > 0
    addpath(edge_boxes_path)
else
    warning('The Edge Boxes installation directory "%s" is not valid. Please install the Edge boxes code (https://github.com/pdollar/edges) and set the path to its installation directory in the edge_boxes_path variable of the startup.m file if you want use the Edge Box proposals', edge_boxes_path)
end

edge_boxes_link_path = fullfile(curdir, 'external', 'edges');
if exist(edge_boxes_link_path, 'dir') == 0
    warning('A link to the edge box installation directory is missing from external/edges; See README.md');
end

% set to pdollar_toolbox_path the path where the Piotr's Matlab Toolbox
% (http://vision.ucsd.edu/~pdollar/toolbox/doc/index.html) is installed
pdollar_toolbox_path = '../pdollar-toolbox/';
if exist(pdollar_toolbox_path,'dir') > 0
    addpath(genpath(pdollar_toolbox_path))
else
    warning('The installation directory "%s" to Piotrs image processing toolbox (http://vision.ucsd.edu/~pdollar/toolbox/doc/index.html) is not valid. Please install the toolbox and set the installation directory path to the pdollar_toolbox_path variable of the startup.m file if you to want use the Edge Box proposals', pdollar_toolbox_path)
end

% set to selective_search_boxes_path the path where the Selective Search code
% (http://huppelen.nl/publications/SelectiveSearchCodeIJCV.zip) is installed
selective_search_boxes_path = '../selective_search/';
if exist(selective_search_boxes_path,'dir') > 0
    addpath(genpath(selective_search_boxes_path))
else
    warning('The installation directory "%s" to the Selective Serach code (http://huppelen.nl/publications/SelectiveSearchCodeIJCV.zip) is not valid. Please install the Selective Search code and set the installation directory path to the selective_search_boxes_path variable of the startup.m file if you want to use the Selective Search proposals', selective_search_boxes_path)
end

addpath(genpath(fullfile(curdir, 'code')));
addpath(fullfile(curdir, 'bin'));

mkdir_if_missing(fullfile(curdir, 'external'));
caffe_path = fullfile(curdir, 'external', 'caffe', 'matlab');
if exist(caffe_path, 'dir') == 0
    error('matcaffe is missing from external/caffe/matlab; See README.md');
end
addpath(genpath(caffe_path));

mkdir_if_missing(fullfile(curdir, 'models-exps'));
mkdir_if_missing(fullfile(curdir, 'feat_cache'));
mkdir_if_missing(fullfile(curdir, 'data'));
mkdir_if_missing(fullfile(curdir, 'bin'));

end


function varargout = threshGui(varargin)
% THRESHGUI M-file for threshGui.fig
%      THRESHGUI, by itself, creates a new THRESHGUI or raises the existing
%      singleton*.
%
%      H = THRESHGUI returns the handle to a new THRESHGUI or the handle to
%      the existing singleton*.
%
%      THRESHGUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in THRESHGUI.M with the given input arguments.
%
%      THRESHGUI('Property','Value',...) creates a new THRESHGUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before threshGui_OpeningFunction gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to threshGui_OpeningFcn via varargin.
%
%      *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 threshGui

%   Copyright 1984-2010 The MathWorks, Inc.
% Last Modified by GUIDE v2.5 30-Sep-2005 11:03:36

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @threshGui_OpeningFcn, ...
                   'gui_OutputFcn',  @threshGui_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 threshGui is made visible.
function threshGui_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 threshGui (see VARARGIN)

% Choose default command line output for threshGui
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

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

% --- Outputs from this function are returned to the command line.
function varargout = threshGui_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;

% --- Executes on slider movement.
function slider1_Callback(hObject, eventdata, handles)
% hObject    handle to slider1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider

hMainGui = getappdata(0, 'hMainGui');
fhUpdateAxes = getappdata(hMainGui, 'fhUpdateAxes');

thresh = get(hObject,'Value');
setappdata(hMainGui, 'thresh', thresh);
feval(fhUpdateAxes);

% --- Executes during object creation, after setting all properties.
function slider1_CreateFcn(hObject, eventdata, handles)
% hObject    handle to slider1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

hMainGui = getappdata(0, 'hMainGui');
thresh   = getappdata(hMainGui, 'thresh');

set(hObject, 'value', thresh)


function [structOut, errors] = checkPrepDefaults(structIn, structOut, defaults)
% Check structIn input parameters against defaults fields of structOut
%
% Parameters:
%    structIn     Parameter structure to be checked
%    structOut    Base output structure for parameters.
%    defaults     Default information
%
% Note:  structOut contains fields that will always be there.
errors = cell(0);
fNames = fieldnames(defaults);
for k = 1:length(fNames)
    try
       nextValue = getStructureParameters(structIn, fNames{k}, ...
                                          defaults.(fNames{k}).value);
       validateattributes(nextValue, defaults.(fNames{k}).classes, ...
                         defaults.(fNames{k}).attributes);
       structOut.(fNames{k}) = nextValue;
    catch mex
        errors{end+1} = [fNames{k} ' parameter value invalid: ' mex.message]; %#ok<AGROW>
    end
end


function extOut = fileExtension(filename)
%
%
%        extOut = fileExtension(filename)
%
%
%        Description: return the extension of a file
%
%        Input:
%           -filename: the name of the file
%
%        Output:
%           -extOut: the extension of the file
%
%     Copyright (C) 2011-2016  Francesco Banterle
%
%     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 3 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, see <http://www.gnu.org/licenses/>.
%

k = strfind(filename, '.');

%there is no extension
if(isempty(k))
    extOut = [];
else
    %get the real extension
    k = k(end);
    extOut = filename((k + 1):max(size(filename)));
end

end


function str = convertCell2Str(cellStrArray)
%% Convert a cell array of strings to a single char array
%
%  Parameters:
%      cellStrArray   A char array or cell array containing char
%      str            (output) A single string representation of input

%% Test cellStrArray and convert
if isempty(cellStrArray)
    str = '';
elseif ischar(cellStrArray)
    str = ['[' cellStrArray ']'];
else
    str = ['[' cellStrArray{1} ']'];
    for k = 2:length(cellStrArray)
        str = [str ' [' cellStrArray{k} ']']; %#ok<*AGROW>
    end
end


function T= opt_substruct(S, fld_list)
%OPT_SUBSTRUCT - Create substruct of specified fields
%
%Synopsis:
%  T= opt_substruct(S, <FLD_LIST>)
%
%Arguments:
%  S:  STRUCT - Source, from which fields are taken
%  FLD_LIST: CELL of CHAR - Names of the fields that should be copied from
%      S into the newly generated substruct T
%
%Returns:
%  T: STRUCT - Substruct of S with specified fields

% Let us be gracious:
if ischar(fld_list),
  fld_list= {fld_list};
elseif iscell(fld_list) && ismember(size(fld_list,2), [2 3]),
  fld_list= fld_list(:,1);
end

fldS= fieldnames(S);
[dmy, dmy, fld_idx]= intersect(lower(fld_list), lower(fldS), 'legacy');
fld_list= fldS(fld_idx);

T= [];
for ii= 1:length(fld_list),
  fld= fld_list{ii};
  [T.(fld)]= S.(fld);
end


function imdb = setup_imdb_imagenet(dataDir, varargin)
% CNN_IMAGENET_SETUP_DATA  Initialize ImageNet ILSVRC CLS-LOC challenge data
%    This function creates an IMDB structure pointing to a local copy
%    of the ILSVRC CLS-LOC data.
%
%    The ILSVRC data ships in several TAR archives that can be
%    obtained from the ILSVRC challenge website. You will need:
%
%    ILSVRC2012_img_train.tar
%    ILSVRC2012_img_val.tar
%    ILSVRC2012_img_test.tar
%    ILSVRC2012_devkit.tar
%
%    Note that images in the CLS-LOC challenge are the same for the 2012, 2013,
%    and 2014 edition of ILSVRC, but that the development kit
%    is different. However, all devkit versions should work.
%
%    In order to use the ILSVRC data with these scripts, please
%    unpack it as follows. Create a root folder <DATA>, by default
%
%    data/ILSVRC2012
%
%    (note that this can be a simlink). Use the 'dataDir' option to
%    specify a different path.
%
%    Within this folder, create the following hierarchy:
%
%    <DATA>/images/train/ : content of ILSVRC2012_img_train.tar
%    <DATA>/images/val/ : content of ILSVRC2012_img_val.tar
%    <DATA>/images/test/ : content of ILSVRC2012_img_test.tar
%    <DATA>/ILSVRC2012_devkit : content of ILSVRC2012_devkit.tar
%
%    In order to speedup training and testing, it may be a good idea
%    to preprocess the images to have a fixed size (e.g. 256 pixels
%    high) and/or to store the images in RAM disk (provided that
%    sufficient RAM is available). Reading images off disk with a
%    sufficient speed is crucial for fast training.
opts.datasetName = 'ILSVRC2012';
opts.seed = 1 ;
opts = vl_argparse(opts, varargin) ;

if ischar(dataDir) && ~isempty(dataDir), opts.dataDir = dataDir;
else opts.dataDir = fullfile('data', opts.datasetName) ; end
opts.lite = false ;
opts = vl_argparse(opts, varargin) ;

% -------------------------------------------------------------------------
%                                                  Load categories metadata
% -------------------------------------------------------------------------

d = dir(fullfile(opts.dataDir, '*devkit*')) ;
if numel(d) == 0
  error('Make sure that ILSVRC data is correctly installed in %s', ...
    opts.dataDir) ;
end
devkitPath = fullfile(opts.dataDir, d(1).name) ;

% find metadata
mt = dir(fullfile(devkitPath, 'data', 'meta_clsloc.mat')) ;
if numel(mt) == 0
  mt = dir(fullfile(devkitPath, 'data', 'meta.mat')) ;
end
metaPath = fullfile(devkitPath, 'data', mt(1).name) ;

% find validation images labels
tmp = dir(fullfile(devkitPath, 'data', '*_validation_ground_truth*')) ;
valLabelsPath = fullfile(devkitPath, 'data', tmp(1).name) ;

% find validation images blacklist
tmp = dir(fullfile(devkitPath, 'data', '*_validation_blacklist*')) ;
if numel(tmp) > 0
  valBlacklistPath = fullfile(devkitPath, 'data', tmp(1).name) ;
else
  valBlacklistPath = [] ;
  warning('Could not find validation images blacklist file');
end

fprintf('using devkit %s\n', devkitPath) ;
fprintf('using metadata %s\n', metaPath) ;
fprintf('using validation labels %s\n', valLabelsPath) ;
fprintf('using validation blacklist %s\n', valBlacklistPath) ;

meta = load(metaPath) ;
cats = {meta.synsets(1:1000).WNID} ;
descrs = {meta.synsets(1:1000).words} ;

imdb.classes.name = cats ;
imdb.classes.description = descrs ;
imdb.imageDir = fullfile(opts.dataDir, 'images') ;

% -------------------------------------------------------------------------
%                                                           Training images
% -------------------------------------------------------------------------

fprintf('searching training images ...\n') ;
names = {} ;
labels = {} ;
for d = dir(fullfile(opts.dataDir, 'images', 'train', 'n*'))'
  [~,lab] = ismember(d.name, cats) ;
  ims = dir(fullfile(opts.dataDir, 'images', 'train', d.name, '*.JPEG')) ;
  names{end+1} = strcat([d.name, filesep], {ims.name}) ;
  labels{end+1} = ones(1, numel(ims)) * lab ;
  fprintf('.') ;
  if mod(numel(names), 50) == 0, fprintf('\n') ; end
  %fprintf('found %s with %d images\n', d.name, numel(ims)) ;
end
names = horzcat(names{:}) ;
labels = horzcat(labels{:}) ;

if numel(names) ~= 1281167
  warning('Found %d training images instead of 1,281,167. Dropping training set.', numel(names)) ;
  names = {} ;
  labels =[] ;
end

names = strcat(['train' filesep], names) ;

imdb.images.id = 1:numel(names) ;
imdb.images.name = names ;
imdb.images.set = ones(1, numel(names)) ;
imdb.images.label = labels ;

% -------------------------------------------------------------------------
%                                                         Validation images
% -------------------------------------------------------------------------

ims = dir(fullfile(opts.dataDir, 'images', 'val', '*.JPEG')) ;
names = sort({ims.name}) ;
labels = textread(valLabelsPath, '%d') ;

if numel(ims) ~= 50e3
  warning('Found %d instead of 50,000 validation images. Dropping validation set.', numel(ims))
  names = {} ;
  labels =[] ;
else
  if ~isempty(valBlacklistPath)
    black = textread(valBlacklistPath, '%d') ;
    fprintf('blacklisting %d validation images\n', numel(black)) ;
    keep = setdiff(1:numel(names), black) ;
    names = names(keep) ;
    labels = labels(keep) ;
  end
end

names = strcat(['val' filesep], names) ;

imdb.images.id = horzcat(imdb.images.id, (1:numel(names)) + 1e7 - 1) ;
imdb.images.name = horzcat(imdb.images.name, names) ;
imdb.images.set = horzcat(imdb.images.set, 2*ones(1,numel(names))) ;
imdb.images.label = horzcat(imdb.images.label, labels') ;

% -------------------------------------------------------------------------
%                                                               Test images
% -------------------------------------------------------------------------

ims = dir(fullfile(opts.dataDir, 'images', 'test', '*.JPEG')) ;
names = sort({ims.name}) ;
labels = zeros(1, numel(names)) ;

if numel(labels) ~= 100e3
  warning('Found %d instead of 100,000 test images', numel(labels))
end

names = strcat(['test' filesep], names) ;

imdb.images.id = horzcat(imdb.images.id, (1:numel(names)) + 2e7 - 1) ;
imdb.images.name = horzcat(imdb.images.name, names) ;
imdb.images.set = horzcat(imdb.images.set, 3*ones(1,numel(names))) ;
imdb.images.label = horzcat(imdb.images.label, labels) ;

% -------------------------------------------------------------------------
%                                                            Postprocessing
% -------------------------------------------------------------------------

% sort categories by WNID (to be compatible with other implementations)
[imdb.classes.name,perm] = sort(imdb.classes.name) ;
imdb.classes.description = imdb.classes.description(perm) ;
relabel(perm) = 1:numel(imdb.classes.name) ;
ok = imdb.images.label >  0 ;
imdb.images.label(ok) = relabel(imdb.images.label(ok)) ;

if opts.lite
  % pick a small number of images for the first 10 classes
  % this cannot be done for test as we do not have test labels
  clear keep ;
  for i=1:10
    sel = find(imdb.images.label == i) ;
    train = sel(imdb.images.set(sel) == 1) ;
    val = sel(imdb.images.set(sel) == 2) ;
    train = train(1:256) ;
    val = val(1:40) ;
    keep{i} = [train val] ;
  end
  test = find(imdb.images.set == 3) ;
  keep = sort(cat(2, keep{:}, test(1:1000))) ;
  imdb.images.id = imdb.images.id(keep) ;
  imdb.images.name = imdb.images.name(keep) ;
  imdb.images.set = imdb.images.set(keep) ;
  imdb.images.label = imdb.images.label(keep) ;
end


function bool = hasTestFailed(status)
    % returns true when the test has failed

    if iscell(status) % allow for vectorization of the call
        bool = cellfun(@hasTestFailed, status, 'UniformOutput', true);
    else
        stages = getStagesFromStatus(status);
        bool = false;
        for jStage = 1:numel(stages)
            bool = bool || status.(stages{jStage}).error;
        end
    end
end


classdef (Abstract) DisplayItem < handle
    % Abstract class for items in frost.Animator.Display
    %
    % @author omar @date 2017-06-01
    %
    % Copyright (c) 2017, UMICH Biped Lab
    % All right reserved.
    %
    % Redistribution and use in source and binary forms, with or without
    % modification, are permitted only in compliance with the BSD 3-Clause
    % license, see
    % http://www.opensource.org/licenses/BSD-3-Clause

    properties (SetAccess = private, GetAccess = protected)
        ax
        model
    end

    properties (SetAccess = private, GetAccess = public)
        name
    end

    methods
        function obj = DisplayItem(ax, model, name)
            obj.ax = ax;
            obj.model = model;
            obj.name = name;
        end
    end

    methods (Abstract)
        update(obj, x);
    end
end


function display(w)
   %DISPLAY Waveform Display overloaded operator

   % VERSION: 1.0 of waveform objects
   % AUTHOR: Celso Reyes (celso@gi.alaska.edu)
   % LASTUPDATE: 2/6/2007

   if isequal(get(0,'FormatSpacing'),'compact')
      disp([inputname(1) ' =']);
      disp(w);
   else
      disp(' ');
      disp([inputname(1) ' =']);
      disp(' ');
      disp(w);
   end
end


function [ebsd,interface,options] = loadEBSD(fname,varargin)

warning('loadEBSD is depreciated. Please use instead EBSD.load');
[ebsd,interface,options] = EBSD.load(fname,varargin{:});


function obj = setName(obj, name)
    % Specifies the name of the NLP function
    %
    % Parameters:
    % name: the name character @type char

    assert(ischar(name), 'NlpFunction:invalidNameStr', ...
        'The name must be a string.');

    % validate name string
    assert(isempty(regexp(name, '\W', 'once')),...
        'NlpFunction:invalidNameStr', ...
        'Invalid name string, can NOT contain special characters.');

    obj.Name = name;

end


function vw = viewSetROI(vw,param,val,varargin)
%Organize methods for setting view parameters.
%
% This function is wrapped by viewSet. It should not be called by anything
% else other than viewSet.
%
% This function retrieves information from the view that relates to a
% specific component of the application.
%
% We assume that input comes to us already fixed and does not need to be
% formatted again.

if notDefined('vw'),  error('No view defined.'); end
if notDefined('param'), error('No parameter defined'); end
if notDefined('val'),   val = []; end

mrGlobals;

switch param

    case 'roi'
        vw = loadROI(vw, val);
    case 'rois'
        % Set ROI field in view struct. ROIs should be a struct.
        % Example: vw = viewSet(vw, 'ROIs', rois);
        vw.ROIs = val;
    case 'selectedroi'
        vw = selectROI(vw, val);
    case 'selroicolor'
        % Set the color of the currently selected or the requested ROI.
        % This can be a Matlab character for a color ('c', 'w', 'b', etc)
        % or an RGB triplet.
        %   vw = viewSet(vw, 'Selected ROI color', [1 0 0]);
        %   roi = 1; col = 'r'; vw = viewSet(vw, 'Selected ROI color', col, roi);
        if isempty(varargin) || isempty(varargin{1}),
            roi = vw.selectedROI;
        else
            roi = varargin{1};
        end
        vw.ROIs(roi).color = val;
    case 'roioptions'
        if ~isempty(val) && isstruct(val)
            vw = roiSetOptions(vw,val);
        else
            vw = roiSetOptions(vw);
        end
    case 'filledperimeter'
        vw.ui.filledPerimeter = val;
    case 'maskrois'
        vw.ui.maskROIs = val;
    case 'roivertinds'
        msh  = viewGet(vw, 'currentmesh');
        if isempty(msh), return; end

        % Parse varargin for ROIs and prefs
        if isempty(varargin) || isempty(varargin{1}),
            roi = vw.selectedROI;
        else
            roi = varargin{1};
            if isstruct(varargin{end}) && isfield(varargin{end}, 'layerMapMode');
                prefs = varargin{end};
            else
                prefs = mrmPreferences;
            end
        end
        % get ROI mapMode
        if isequal(prefs.layerMapMode, 'layer1'), roiMapMode = 'layer1';
        else roiMapMode = 'any';  end
        vw.ROIs(roi).roiVertInds.(msh.name).(roiMapMode) = val;

    case 'showrois'
        % Select one or more ROIs to show on meshes
        %   -2 = show all ROIs
        %   -1 = show selected ROIs
        %    0 = hide all ROIs
        %   >0 = show those ROIs (e.g., if showROIs = [1 3], then show ROIs
        %           1 and 3).
        % Examples:
        %   vw = viewSet(vw, 'Show ROIs', [1 2]) % show ROIs 1 and 2
        %   vw = viewSet(vw, 'Show ROIs', -2)    % show all ROIs
        if ~checkfields(vw, 'ui'), vw.ui = []; end;
        vw.ui.showROIs = val;

    case 'hidevolumerois'
        % Specifiy whether to show ROIs in volume or gray view. We
        % sometimes choose not to show them because if we click around in
        % the GUI, redrawing the ROIs can be slow.
        %
        % Examples:
        %   vw = viewSet(vw, 'Hide Volume ROIs', true)
        %   vw = viewSet(vw, 'Hide Volume ROIs', false)
        if ~checkfields(vw, 'ui'), vw.ui = []; end
        vw.ui.hideVolumeROIs = val;

    case 'roidrawmethod'
        % Specify how the ROIs will be visualized.
        % Options:
        % 'perimeter'               % outlined ROI
        % 'filled perimeter'        % outlined ROI, but thicker
        % 'boxes'                   % filled in ROI
        % 'patches'                 % translucent patches
        %
        % Examples:
        %   vw = viewSet(vw, 'roidrawmethod', 'filled perimeter')
        if ~checkfields(vw, 'ui'), vw.ui = []; end
        vw.ui.roiDrawMethod = val;
    case 'roiname'
        if isempty(varargin) || isempty(varargin{1})
            roi = vw.selectedROI;
        else
            roi = varargin{1};
        end
        vw.ROIs(roi).name = val;
    case 'roicoords'
        if isempty(varargin)||isempty(varargin{1}), roi = vw.selectedROI;
        else                                        roi = varargin{1}; end

        vw.ROIs(roi).coords = val;

    case 'roimodified'
        if isempty(varargin)||isempty(varargin{1}), roi = vw.selectedROI;
        else                                        roi = varargin{1}; end
        vw.ROIs(roi).modified = val;

    case 'roicomments'
        if isempty(varargin) || isempty(varargin{1})
            roi = vw.selectedROI;
        else
            roi = varargin{1};
        end
        vw.ROIs(roi).comments = val;

    otherwise
        error('Unknown view parameter %s.', param);

end %switch

return


classdef (Abstract) ZmapResultsPlugin
    % base class for displaying results
    properties
       Parent
    end

    properties(Dependent)
        Data
        PlotTag
    end

    properties(Abstract)
    end

    methods(Abstract)
    end

    methods
        function r = get.Data(obj)
            r = obj.Parent.Result.values;
        end
        function r = get.PlotTag(obj)
            r = obj.Parent.PlotTag;
        end
    end
end


function [metabolite_structure,IDsAdded] = getCas2Echa(metabolite_structure)
%
% The input file was downloaded from https://echa.europa.eu/documents/10162/13629/ec_inventory_en.xlsx
%
%
% INPUT
% metabolite_structure  metabolite structure
%
% OUTPUT
% metabolite_structure  Updated metabolite structure
%
%
% Ines Thiele, 2020-2021
% first column contains echa_id,4th col is cas registry
[NUM,TXT,RAW]=xlsread('ec_inventory_en.xlsx');

annotationSource = 'Echa_id mapping from CasRegistry';
annotationType = 'automatic';

Mets = fieldnames(metabolite_structure);
for i = 1 : length(Mets)
    Cas{i,1} = Mets{i};
    Cas{i,2} = num2str(metabolite_structure.(Mets{i}).casRegistry);
end

for i = 4 : size(RAW,1)
    casRAW{i-3,1} = RAW{i,4};
    casRAWList{i-3,1} = RAW{i,1};
end
a = 1;
IDsAdded = '';

for i = 1 : size(Cas,1)
    % no keggId exists
    if ~isempty(metabolite_structure.(Cas{i,1}).casRegistry) && isempty(find(isnan(metabolite_structure.(Cas{i,1}).casRegistry),1))
        if isempty(metabolite_structure.(Cas{i,1}).echa_id) || ~isempty(find(isnan(metabolite_structure.(Cas{i,1}).echa_id),1))
            match = strmatch(Cas{i,2},casRAW,'exact');
            if ~isempty(match)
                metabolite_structure.(Cas{i,1}).echa_id = casRAWList{match};
                metabolite_structure.(Cas{i,1}).echa_id_source =  [annotationSource,':',annotationType,':',datestr(now)];
                IDsAdded{a,1} = Cas{i,1};
                IDsAdded{a,2} = 'echa_id';
                IDsAdded{a,3} =  metabolite_structure.(Cas{i}).echa_id;
                a = a + 1;
            end
        end
    end
end
[metabolite_structure] = cleanUpMetabolite_structure(metabolite_structure);


% Packs an object of any complexity (structure, cell array ect.)
% into a serialized form.
%
% mex-function, written by Dima Mihaylov (dmih@in-solve.ru)
%
% See also DESERIALIZE


function saveplots(fmri_model, varargin)

if isempty(varargin) % Output dir
    savedir = pwd;
else
savedir = varargin{1};
end

if ~exist(savedir, 'dir'), mkdir(savedir); end

% Register of possible plot names associated with this object type

plotnames = {'basis sets' ...
    'design matrix image' ...
    'design matrix' ...
    };

for j = 1:length(plotnames)

    han = findobj('Name', plotnames{j});
    if ~isempty(han) && ishandle(han) && strcmp(get(han, 'Type'), 'figure')

        fprintf('Saving figure: %s\n', plotnames{j});
        figure(han);
        scn_export_papersetup(500);

        name = get(han, 'Name');
        name(name == ' ') = '_';

        name = fullfile(savedir, name);

        saveas(han, name, 'png');

    end

end

end


function YESNO = isnan(F)
YESNO=0;


function out = isempty(v)
% overloads isempty

out = isempty(v.x);


function [pathway, notMapped]=mapPathwayRxnNames(pathway,originalLabels,newLabels)
% mapPathwayRxnNames
%   For mapping labels in the pathway object. Useful if you want to change
%   what is shown in the reaction boxes.
%
%   pathway         pathway structure representing the pathway to be drawn
%   originalLabels  cell array with the original reaction labels
%   newLabels       cell array with the new reaction labels
%
%   pathway         an updated pathway structure
%   notMapped       a cell array with labels that could not be found in the
%                   pathway object
%
%   Usage: [pathway, notMapped]=mapPathwayRxnNames(pathway,originalLabels,newLabels)

if numel(originalLabels)~=numel(newLabels)
    EM='The new label cell array must have the same length as the old label cell array';
    dispEM(EM);
end

mapped=false(numel(originalLabels),1);

for i=1:numel(pathway.listOfSpecies)
    if strcmpi(pathway.listOfSpecies(i).type,'PROTEIN')
        I=find(ismember(originalLabels,pathway.listOfSpecies(i).name));
        if any(I)
            if numel(I)==1
                pathway.listOfSpecies(i).name=newLabels{I};
                mapped(I)=true;
            else
                EM=['The label "' pathway.listOfSpecies(i).name '" was found in several positions in oldLabels'];
                dispEM(EM);
            end
        end
    end
end

notMapped=originalLabels(~mapped);
end


function SIM_GEN_f_FuncGen(plant)
    fileID = fopen('./funcgen/SIM_GEN_f.m','w');

    fprintf(fileID, 'function f = SIM_GEN_f(u,x,p)\n');
    fprintf(fileID, '   f = fSim_Wrapper(u,x,p);\n');
    fprintf(fileID, 'end');

    fclose(fileID);

end