function [result] = ft_test_report(varargin)

% FT_TEST_REPORT

% Copyright (C) 2017, 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$

narginchk(1, inf);
command = varargin{1};
assert(isequal(command, 'report'));
varargin = varargin(2:end);

optbeg = find(ismember(varargin, {'matlabversion', 'fieldtripversion', 'user', 'hostname', 'branch', 'arch', 'showdate', 'showid', 'timeout'}));
if ~isempty(optbeg)
  optarg   = varargin(optbeg:end);
  varargin = varargin(1:optbeg-1);
else
  optarg = {};
end

% varargin contains the file (or files) to test
% optarg contains the command-specific options
showdate = ft_getopt(optarg, 'showdate', false);  if ischar(showdate), showdate = istrue(showdate);    end
showid   = ft_getopt(optarg, 'showid', false);    if ischar(showid),   showid   = istrue(showid);      end
timeout  = ft_getopt(optarg, 'timeout', 30);      if ischar(timeout),  timeout  = str2double(timeout); end

% construct the query string that will be passed in the URL
query = '?';
queryparam = {'matlabversion', 'fieldtripversion', 'hostname', 'user', 'branch', 'arch'};
for i=1:numel(queryparam)
  val = ft_getopt(optarg, queryparam{i});
  if ~isempty(val)
    query = [query sprintf('%s=%s&', queryparam{i}, val)];
  end
end

options = weboptions('ContentType', 'json', 'Timeout', timeout); % this returns the result as MATLAB structure
url = 'http://dashboard.fieldtriptoolbox.org/api/';

if isempty(varargin)
  result = webread([url query], options);
  assert(~isempty(result), 'no results were returned');
  result = mergecellstruct(result);
else
  results = cell(size(varargin));
  for i=1:numel(varargin)
    result = webread([url query sprintf('&functionname=%s', varargin{i})], options);
    assert(~isempty(result), 'no results were returned for %s', varargin{i});
    results{i} = mergecellstruct(result);
  end
  % merge all results
  result = mergecellstruct(results);
end

% rename the automatically added fields
result = renamefields(result, 'x_id', 'id');
result = renamefields(result, 'createDate', 'date');

% remove some of the fields
if ~showid
  result = removefields(result, 'id');
end
if ~showdate
  result = removefields(result, 'date');
end


% PURPOSE: shows pop function ending statement (located at msg2end.txt)
%
% Format:
%
% msg2end
%
% See also readmsg2end.m msg2end.txt
%
%
% Author: Javier Lopez-Calderon
% Center for Mind and Brain
% University of California, Davis,
% Davis, CA
% 2011

function msg2end
[msg2show x colormsg] = readmsg2end;
try
        cprintf(colormsg, msg2show');
catch
        fprintf(msg2show);
end
fprintf('\n');


function [data, variable] = getRemoteVariable(variable,varargin)
%"getRemoveVariable"
%   Accesses, loads and returns data that is stored remotely.
%
%   Also returns an optional copy of the variable with remote data stored
%   in the data field, and the loaded field set to 1.
%
% JRA 10/14/04
% APA 11/23/05 - Added Local storage capability in tarball format
%
%Usage:
%   [data, variable] = getRemoteVariable(variable)
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

global stateS planC
indexS = planC{end};

if isstruct(variable) & isfield(variable, 'remotePath') & isfield(variable, 'isLoaded') & isfield(variable, 'data') & isfield(variable, 'info') & strcmpi(variable.info, 'Remotely stored data.  Use getRemoteVariable to access.')'

    if variable.isLoaded
        data = variable.data;
    else
        switch upper(variable.storageType)
            case 'ZIP'
                load(fullfile(tempdir, variable.remotePath));
                data = CERRRemoteVariable;
                variable.data = data;
                variable.isLoaded = 1;
            case 'LOCAL'
                load(fullfile(variable.remotePath,variable.filename));
                data = CERRRemoteVariable;
                variable.data = data;
                variable.isLoaded = 1;
            case 'NETWORK'
                error('Local and Network storage not implemented yet.');
        end
    end
else
    error('Invalid remote data struct.')
end


function obj = removeVirtualConstraint(obj, name)
    % Remove virtual constraints defined for the system
    %
    % Parameters:
    % name: the name of the constraint @type cellstr

    assert(ischar(name) || iscellstr(name), ...
        'The name must be a character vector or cellstr.');
    if ischar(name), name = cellstr(name); end

    for i=1:length(name)
        constr = name{i};

        if isfield(obj.VirtualConstraints, constr)
            c_obj = obj.VirtualConstraints.(constr);
            obj = removeParam(obj,c_obj.OutputParamName);
            if ~isempty(c_obj.PhaseParams)
                obj = removeParam(obj,c_obj.PhaseParamName);
            end
            obj.VirtualConstraints = rmfield(obj.VirtualConstraints,constr);
        else
            error('The virtual constraint (%s) does not exist.\n',constr);
        end
    end
end


%FEACACHE FEATool data cache.
%
%   [ OUT ] = FEACACHE( VAR, SLOT, VAL ) Cache and retrieve data. VAR
%   designates a cache variable name, an integer SLOT retrieves, or
%   puts the argument VAL to that slot (cache{VAR,SLOT} = VAL).
%
%   Output OUT is either a requested VAR/SLOT pair, or with not input
%   arguments a struct ST_CACHE of cached expressions used by the
%   feacache, and evalexpr0, parseexpr, subcoef, and symvarbe.
%
%   FEACACHE(0) Clears the cache.

% Copyright 2013-2022 Precise Simulation, Ltd.


function outHtml = colText(inText, inColor)
% Returns a HTML string with colored font. Used for GUIs.
% Called by `metCompareGUI`, `reactionCompareGUI`.
%
% USAGE:
%
%    outHtml = colText(inText, inColor)
%
% INPUTS:
%    inText:      String
%    inColor      Color to make string.
%
% OUTPUTS:
%    outHtml:     Text with formatting
%
% Please cite:
% `Sauls, J. T., & Buescher, J. M. (2014). Assimilating genome-scale
% metabolic reconstructions with modelBorgifier. Bioinformatics
% (Oxford, England), 30(7), 1036?8`. http://doi.org/10.1093/bioinformatics/btt747
%
% ..
%    Edit the above text to modify the response to help addMetInfo
%    Last Modified by GUIDE v2.5 06-Dec-2013 14:19:28
%    This file is published under Creative Commons BY-NC-SA.
%
%    Correspondance:
%    johntsauls@gmail.com
%
%    Developed at:
%    BRAIN Aktiengesellschaft
%    Microbial Production Technologies Unit
%    Quantitative Biology and Sequencing Platform
%    Darmstaeter Str. 34-36
%    64673 Zwingenberg, Germany
%    www.brain-biotech.de

outHtml = ['', ...
    inText, ...
    ''];


function baseName=baseNameFromFileName(fileName)

[~,baseName]=fileparts(fileName);

end


function output = tokenize_cell_array(cellarray, num_headers)

% Takes a cell array, one entry per line and tokenizes it

end


%-----------------------------------------------------------------------
% Job configuration created by cfg_util (rev $Rev: 4899 $)
%-----------------------------------------------------------------------
matlabbatch{1}.menu_cfg.menu_struct.conf_choice.type = 'cfg_choice';
matlabbatch{1}.menu_cfg.menu_struct.conf_choice.name = 'File/Dir Operations';
matlabbatch{1}.menu_cfg.menu_struct.conf_choice.tag = 'file_dir';
matlabbatch{1}.menu_cfg.menu_struct.conf_choice.values = {
                                                          '<UNDEFINED>'
                                                          '<UNDEFINED>'
                                                          '<UNDEFINED>'
                                                          }';
matlabbatch{1}.menu_cfg.menu_struct.conf_choice.check = [];
matlabbatch{1}.menu_cfg.menu_struct.conf_choice.help = {''};


function varargout=readflac(varargin)
%
% For calling details please see v_readflac.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_readflac.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: readflac.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_readflac(varargin{:});
else
    v_readflac(varargin{:});
end


  function [out ii] = jf_pair_parse(cells, str, varargin)
%|function [out ii] = jf_pair_parse(cells, str, varargin)

arg.suffix = ' ';
arg = vararg_pair(arg, varargin);

str = [str arg.suffix];

tf = strncmp(str, cells, numel(str));
ii = find(tf);
if numel(ii) < 1
	fail('no match for "%s"', str)
end
if numel(ii) > 1
	fail('%d matches for "%s"', numel(ii), str)
end

out = cells{ii};
out = out((numel(str)+1):end);


function varargout = panel_dipoles(varargin)
% PANEL_DIPOLES: Create a panel to add/remove/edit scouts attached to a given 3DViz figure.
%
% USAGE:  bstPanelNew = panel_dipoles('CreatePanel')
%                       panel_dipoles('UpdatePanel')
%                       panel_dipoles('CurrentFigureChanged_Callback')
%                       panel_dipoles('SetGoodness', Goodness)

% @=============================================================================
% 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: Elizabeth Bock, 2010-2017
%          Francois Tadel, 2010-2020

eval(macro_method);
end

%% ===== CREATE PANEL =====
function bstPanelNew = CreatePanel() %#ok<DEFNU>
    panelName = 'Dipoles';
    % Java initializations
    import java.awt.*;
    import javax.swing.*;
    import org.brainstorm.list.*;

    % The the better JList height
    LABEL_WIDTH      = java_scaled('value', 40);
    SLIDER_WIDTH     = java_scaled('value', 5);
    DEFAULT_HEIGHT   = java_scaled('value', 22);
    LABEL_FONT = java.awt.Font('Arial', java.awt.Font.PLAIN, 9);
    % Font size for the lists
    fontSize = round(11 * bst_get('InterfaceScaling') / 100);

    % Main panel container
    jPanelNew = java_create('javax.swing.JPanel');
    jPanelNew.setLayout(BoxLayout(jPanelNew, BoxLayout.PAGE_AXIS));
    jPanelNew.setBorder(BorderFactory.createEmptyBorder(10,10,0,10));

    % ===== PANEL: LOADED DIPOLES =====
    jPanelList = gui_component('Panel');
    jPanelList.setPreferredSize(java_scaled('dimension', 100, 150));
    jPanelList.setMaximumSize(java_scaled('dimension', 500, 150));
        jBorder = java_scaled('titledborder', 'Loaded dipoles');
        jPanelList.setBorder(jBorder);
        % Groups
        jListDipoles = JList();
        jListDipoles.setCellRenderer(BstStringListRenderer(fontSize));
        java_setcb(jListDipoles, 'ValueChangedCallback', @DipolesListValueChanged_Callback, ...
                                 'KeyPressedCallback',   @DipolesListKeyTyped_Callback);
        jPanelScrollList = JScrollPane();
        jPanelScrollList.getLayout.getViewport.setView(jListDipoles);
        jPanelScrollList.setHorizontalScrollBarPolicy(jPanelScrollList.HORIZONTAL_SCROLLBAR_NEVER);
        jPanelScrollList.setBorder([]);
        % Subsets
        jListSubsets = JList();
        jListSubsets.setCellRenderer(BstStringListRenderer(fontSize));
        java_setcb(jListSubsets, 'ValueChangedCallback', @SubsetsListValueChanged_Callback, ...
                                 'MouseClickedCallback', @SubsetsListValueChanged_Callback, ...
                                 'KeyPressedCallback',   @DipolesListKeyTyped_Callback);

        jPanelScrollSubset = JScrollPane();
        jPanelScrollSubset.getLayout.getViewport.setView(jListSubsets);
        jPanelScrollSubset.setHorizontalScrollBarPolicy(jPanelScrollList.HORIZONTAL_SCROLLBAR_NEVER);
        jPanelScrollSubset.setBorder([]);

    jSplitDipoles = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, jPanelScrollSubset, jPanelScrollList );
    jSplitDipoles.setResizeWeight(0.3);
    jSplitDipoles.setDividerSize(4);
    jSplitDipoles.setBorder([]);

    jPanelList.add(jSplitDipoles, BorderLayout.CENTER);
    jPanelList.setVisible(0);
    jPanelNew.add(jPanelList);

    % ===== PANEL: FILTER =====
    jPanelFilter = gui_river([0,1], [0,0,0,0], 'Filter dipoles');
        % Goodness title
        jTitleGoodness = gui_component('Label', jPanelFilter, 'br', 'Goodness:');
        % Goodness slider
        jSliderGoodness = JSlider(0, 100, 0);
        jSliderGoodness.setPreferredSize(Dimension(SLIDER_WIDTH, DEFAULT_HEIGHT));
        java_setcb(jSliderGoodness, 'MouseReleasedCallback', @SliderGoodness_Callback,  'KeyPressedCallback', @SliderGoodness_Callback);
        jPanelFilter.add('tab hfill', jSliderGoodness);
        % Goodness label
        jLabelGoodness = gui_component('Label', jPanelFilter, [], '     0%', {JLabel.RIGHT, Dimension(LABEL_WIDTH, DEFAULT_HEIGHT)});
        jLabelGoodness.setFont(LABEL_FONT);

        % Confidence Volume title
        jTitleConfVol = gui_component('Label', jPanelFilter, 'br', 'ConfVol:');
        % Confidence volume slider
        jSliderConfVol = JSlider(0, 100, 100);
        jSliderConfVol.setPreferredSize(Dimension(SLIDER_WIDTH, DEFAULT_HEIGHT));
        jSliderConfVol.setInverted(1);
        java_setcb(jSliderConfVol, 'MouseReleasedCallback', @SliderConfVol_Callback, ...
                                   'KeyPressedCallback',    @SliderConfVol_Callback);
        jPanelFilter.add('tab hfill', jSliderConfVol);
        % Confidence volume label
        jLabelConfVol = gui_component('Label', jPanelFilter, [], '         ', {JLabel.RIGHT, Dimension(LABEL_WIDTH, DEFAULT_HEIGHT)});
        jLabelConfVol.setFont(LABEL_FONT);

        % Chi-square title
        jTitleKhi2 = gui_component('Label', jPanelFilter, 'br', 'Chi-sqr:');
        % Chi-square slider
        jSliderKhi2 = JSlider(0, 100, 100);
        jSliderKhi2.setPreferredSize(Dimension(SLIDER_WIDTH, DEFAULT_HEIGHT));
        jSliderKhi2.setInverted(1);
        java_setcb(jSliderKhi2, 'MouseReleasedCallback', @SliderKhi2_Callback, ...
                                'KeyPressedCallback',    @SliderKhi2_Callback);
        jPanelFilter.add('tab hfill', jSliderKhi2);
        % Chi-square label
        jLabelKhi2 = gui_component('Label', jPanelFilter, [], '         ', {JLabel.RIGHT, Dimension(LABEL_WIDTH, DEFAULT_HEIGHT)});
        jLabelKhi2.setFont(LABEL_FONT);
    jPanelNew.add(jPanelFilter);

    % ===== PANEL: DISPLAY OPTIONS =====
    jPanelOptions = gui_river([0,1], [2,4,4,0], 'Display filters');
        % Options
        jToggleMaxGoodness = gui_component('Checkbox', jPanelOptions, 'br', 'Show max goodness of fit', [], 'Show only the dipole with the maximal goodness of fit', @(h,ev)FireUpdateDisplayOptions);
        jToggleAllTimes    = gui_component('Checkbox', jPanelOptions, 'br', 'Show all time', [], 'Show all time points', @(h,ev)FireUpdateDisplayOptions);
        jToggleSelTimes    = gui_component('Checkbox', jPanelOptions, 'br', 'Show only preferred times', [], 'Show only the dipoles at custom selected times (default time=0)', @(h,ev)FireUpdateDisplayOptions);
        jToggleAllTimes.setSelected(1);
        jButtonSetSel = gui_component('Button', jPanelOptions, '', 'Set', Insets(1,5,1,5), 'Set the current time as the preferred time for the loaded group(s)', @SetSelectedTime_Callback);
        jButtonSetSel.setFocusable(0);
    jPanelNew.add(jPanelOptions);

    % ===== PANEL: COLOR =====
    jPanelColor = gui_river([0,1], [2,4,4,0], 'Color dipoles according to:');
        colorButtonGroup = javax.swing.ButtonGroup();
        jToggleColorTime     = gui_component('Radio', jPanelColor, 'br', 'Time', colorButtonGroup, 'Set dipole colors according to the time instant', @CheckColor_Callback);
        jToggleColorGoodness = gui_component('Radio', jPanelColor, 'br', 'Goodness of fit', colorButtonGroup, 'Set dipole colors according to the goodness of fit', @CheckColor_Callback);
        jToggleColorGroup    = gui_component('Radio', jPanelColor, 'br', 'Group', colorButtonGroup, 'Set dipole colors according to the dipole group', @CheckColor_Callback);
        jToggleColorTime.setSelected(1);

        %dipole size
        jTitleDipSize = gui_component('Label', jPanelColor, 'br', 'Point display size:');
        jSliderDipSize = JSlider(5, 20, 8);
        jSliderDipSize.setPreferredSize(Dimension(SLIDER_WIDTH, DEFAULT_HEIGHT));
        java_setcb(jSliderDipSize, 'MouseReleasedCallback', @FireUpdateDisplayOptions, ...
                                   'KeyPressedCallback',    @FireUpdateDisplayOptions);
        jPanelColor.add('tab hfill', jSliderDipSize);
        %dipole tail size
        jTitleTailWidth = gui_component('Label', jPanelColor, 'br', 'Tail display width:');
        jSliderTailWidth = JSlider(4, 40, 8);
        jSliderTailWidth.setPreferredSize(Dimension(SLIDER_WIDTH, DEFAULT_HEIGHT));
        java_setcb(jSliderTailWidth, 'MouseReleasedCallback', @FireUpdateDisplayOptions, ...
                                   'KeyPressedCallback',    @FireUpdateDisplayOptions);
        jPanelColor.add('tab hfill', jSliderTailWidth);
    jPanelNew.add(jPanelColor);

    % Set max panel sizes
    drawnow;
    jPanelList.setMaximumSize(java.awt.Dimension(jPanelList.getMaximumSize().getWidth(), jPanelList.getPreferredSize().getHeight()));
    jPanelOptions.setMaximumSize(java.awt.Dimension(jPanelOptions.getMaximumSize().getWidth(), jPanelOptions.getPreferredSize().getHeight()));
    jPanelFilter.setMaximumSize(java.awt.Dimension(jPanelFilter.getMaximumSize().getWidth(), jPanelFilter.getPreferredSize().getHeight()));
    jPanelColor.setMaximumSize(java.awt.Dimension(jPanelColor.getMaximumSize().getWidth(), jPanelColor.getPreferredSize().getHeight()));
    % Add an extra glue at the end, so that panel stay small
    jPanelNew.add(Box.createVerticalGlue());

    % Create the BstPanel object that is returned by the function
    % => constructor BstPanel(jHandle, panelName, sControls)
    bstPanelNew = BstPanel(panelName, ...
                           jPanelNew, ...
                           struct('jPanelList',            jPanelList, ...
                                  'jPanelOptions',         jPanelOptions, ...
                                  'jPanelFilter',          jPanelFilter, ...
                                  'jListDipoles',          jListDipoles, ...
                                  'jListSubsets',          jListSubsets, ...
                                  'jToggleAllTimes',       jToggleAllTimes, ...
                                  'jToggleColorGroup',     jToggleColorGroup, ...
                                  'jToggleColorTime',      jToggleColorTime, ...
                                  'jToggleColorGoodness',  jToggleColorGoodness, ...
                                  'jToggleMaxGoodness',    jToggleMaxGoodness, ...
                                  'jTitleGoodness',        jTitleGoodness, ...
                                  'jLabelGoodness',        jLabelGoodness, ...
                                  'jSliderGoodness',       jSliderGoodness, ...
                                  'jTitleKhi2',            jTitleKhi2, ...
                                  'jLabelKhi2',            jLabelKhi2, ...
                                  'jSliderKhi2',           jSliderKhi2, ...
                                  'jTitleConfVol',         jTitleConfVol, ...
                                  'jLabelConfVol',         jLabelConfVol, ...
                                  'jSliderConfVol',        jSliderConfVol, ...
                                  'jToggleSelTimes',       jToggleSelTimes, ...
                                  'jButtonSetSel',         jButtonSetSel, ...
                                  'jTitleDipSize',         jTitleDipSize, ...
                                  'jSliderDipSize',        jSliderDipSize, ...
                                  'jTitleTailWidth',       jTitleTailWidth, ...
                                  'jSliderTailWidth',      jSliderTailWidth));

%% ===== INTERNAL CALLBACKS =====
    function SliderGoodness_Callback(varargin)
        % Update text field
        val = jSliderGoodness.getValue();
        jLabelGoodness.setText(sprintf('%d%%', val));
        % Update display options
        FireUpdateDisplayOptions();
    end

    function SliderKhi2_Callback(varargin)
        % Update display options
        FireUpdateDisplayOptions();
    end

    function SliderConfVol_Callback(varargin)
        % Update display options
        FireUpdateDisplayOptions();
    end
end

%% =================================================================================
%  === CONTROLS CALLBACKS  =========================================================
%  =================================================================================
%% ===== CHECKBOX: 3D COLOR =====
function CheckColor_Callback(varargin)
    % Get current figure
    hFig = bst_figures('GetCurrentFigure', '3D');
    if isempty(hFig)
        return
    end
    % Update display
    FireUpdateDisplayOptions();
    % Update colormap
    FireUpdateSurfaceColormap();
end

%% ===== LIST SELECTION CHANGED CALLBACK =====
function DipolesListValueChanged_Callback(h, ev)
    if ~ev.getValueIsAdjusting()
        FireUpdateDisplayOptions();
    end
end

%% ===== LIST KEY TYPED CALLBACK =====
function DipolesListKeyTyped_Callback(h, ev)
    import java.awt.event.KeyEvent;
    if ismember(ev.getKeyCode(), [KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT])
        panel_time('TimeKeyCallback', ev);
    end
end

%% ===== SUBSET SELECTION CHANGED CALLBACK =====
function SubsetsListValueChanged_Callback(h, ev)
    % Get panel controls
    ctrl = bst_get('PanelControls','Dipoles');
    if isempty(ctrl)
        return;
    end
    % Get selected subset
    iSubset = double(ctrl.jListSubsets.getSelectedIndices())' + 1;

    % Remove JList callback
    bakCallback = java_getcb(ctrl.jListDipoles, 'ValueChangedCallback');
    java_setcb(ctrl.jListDipoles, 'ValueChangedCallback', []);

    hFig = bst_figures('GetCurrentFigure');
    DipolesInfo = GetDipolesForFigure(hFig);
    iNames = [];
    % Find all DipoleNames that contain the subset number
    for i=1:length(iSubset)
        strSubset = ['(' num2str(iSubset(i)) ')'];
        x=strfind([DipolesInfo.DipoleNames], strSubset);
        iNames = cat(2,iNames,find(~cellfun(@isempty,x))-1);
    end
    % Select the DipoleNames, or All, if no match...
    if isempty(iNames)
        iNames = 0:length(DipolesInfo.DipoleNames)-1;
    end
    ctrl.jListDipoles.setSelectedIndices(iNames);
    java_setcb(ctrl.jListDipoles, 'ValueChangedCallback', bakCallback);

    % Display/hide dipoles
    FireUpdateDisplayOptions()
end
%% ===== SET TIME SELECTION CALLBACK =====
function SetSelectedTime_Callback(h,ev)
    global GlobalData
    hFig = bst_figures('GetCurrentFigure');
    % Get the dipole info structure
    DipolesInfo = GetDipolesForFigure(hFig);
    % Get selected dipole(s)
    iSel = GetDisplayedDipoles(hFig);
    % Set the current time as the selected time for the displayed groups
    DipolesInfo.PreferredTimes(iSel) = GlobalData.UserTimeWindow.CurrentTime;

    % Save the times back to the dipole file
    DipolesFileInfo = getappdata(hFig, 'Dipoles');
    DipolesFile = file_fullpath(DipolesFileInfo.FileName);
    save(DipolesFile,'-struct','DipolesInfo','PreferredTimes','-append')

    % Update the loaded dipoles
    [iDS, iDipoles] = bst_memory('LoadDipolesFile', DipolesFile);
    GlobalData.DataSet(iDS).Dipoles(iDipoles).PreferredTimes = DipolesInfo.PreferredTimes;

    % Display/hide dipoles
    FireUpdateDisplayOptions()
end
%% =================================================================================
%  === EXTERNAL PANEL CALLBACKS  ===================================================
%  =================================================================================
%% ===== UPDATE CALLBACK =====
function UpdatePanel() %#ok<DEFNU>
    hFig = bst_figures('GetCurrentFigure');
    UpdateDipolesList(hFig);
end

%% ===== CURRENT FIGURE CHANGED =====
function CurrentFigureChanged_Callback(hFig) %#ok<DEFNU>
    % Get panel controls
    ctrl = bst_get('PanelControls', 'Dipoles');
    if isempty(ctrl)
        return;
    end
    % Remove JList callback
    bakCallback = java_getcb(ctrl.jListDipoles, 'ValueChangedCallback');
    java_setcb(ctrl.jListDipoles, 'ValueChangedCallback', []);
    % Update dipoles list
    UpdateDipolesList(hFig);
    % Restore callback
    java_setcb(ctrl.jListDipoles, 'ValueChangedCallback', bakCallback);
end

%% ===== CURRENT TIME CHANGED =====
function CurrentTimeChangedCallback(hFig) %#ok<DEFNU>
    PlotSelectedDipoles(hFig);
end

%% ===== LOAD DIPOLES =====
function AddDipoles(hFig, DipolesFile, isDisplay) %#ok<DEFNU>
    global GlobalData;
    if (nargin < 3)
        isDisplay = 1;
    end
    % Make file name relative
    DipolesFile = file_short(DipolesFile);
    % Get dipoles currently shown in figure
    DipolesInfo = getappdata(hFig, 'Dipoles');
    % If dipoles files already displayed: return
    if ~isempty(DipolesInfo) && any(file_compare({DipolesInfo.FileName}, DipolesFile))
        warning('This dipoles file is already displayed. Ignoring... ');
        return
    end
    % Load file
    [iDS, iDipoles] = bst_memory('LoadDipolesFile', DipolesFile);
    if isempty(iDS)
        return
    end
    % Add new dipole structure in DipolesInfo
    iNewDip = length(DipolesInfo) + 1;
    DipolesInfo(iNewDip).FileName = GlobalData.DataSet(iDS).Dipoles(iDipoles).FileName;
    DipolesInfo(iNewDip).Selected = [];
    % Set dipoles in figure application data
    setappdata(hFig, 'Dipoles',     DipolesInfo);
    setappdata(hFig, 'SubjectFile', GlobalData.DataSet(iDS).SubjectFile);
    setappdata(hFig, 'StudyFile',   GlobalData.DataSet(iDS).StudyFile);
    % Update dipoles list
    UpdateDipolesList(hFig, 1);
    % Select "dipoles" tab
    gui_brainstorm('SetSelectedTab', 'Dipoles');
    % Plot selected dipoles
    if isDisplay
        FireUpdateDisplayOptions();
        % Update colormap
        FireUpdateSurfaceColormap();
    end
end

%% ===== GET DIPOLES FOR FIGURE =====
function DipolesInfo = GetDipolesForFigure(hFig)
    global GlobalData;
    % Initialize returned structure
    DipolesInfo.DipoleNames = {};
    DipolesInfo.Dipole = [];
    DipolesInfo.Subset = [];
    DipolesInfo.PreferredTimes = [];
    DipolesInfo.DisplayColorType = 'time';
    DipolesInfo.DisplayAllTime = 0;
    DipolesInfo.DisplayMaxGoodness = 0;
    DipolesInfo.DisplaySelTimes = 0;

    % Get Dipoles description in figure
    DipolesApp = getappdata(hFig, 'Dipoles');
    if isempty(DipolesApp)
        return
    end
    % For each dipoles file displayed in this figure
    for i = 1:length(DipolesApp)
        % Get loaded dipoles
        [iDS, iDipoles] = bst_memory('GetDataSetDipoles', DipolesApp(i).FileName);
        % Add description to dipoles
        DipolesInfo.Dipole = [DipolesInfo.Dipole, GlobalData.DataSet(iDS).Dipoles(iDipoles).Dipole];
        DipolesInfo.DipoleNames = cat(2, DipolesInfo.DipoleNames, GlobalData.DataSet(iDS).Dipoles(iDipoles).DipoleNames);
        % Check for subsets
        DipolesInfo.Subset = cat(2, DipolesInfo.Subset, GlobalData.DataSet(iDS).Dipoles(iDipoles).Subset);
        DipolesInfo.PreferredTimes = cat(2, DipolesInfo.PreferredTimes, GlobalData.DataSet(iDS).Dipoles(iDipoles).PreferredTimes);
    end
    % Get panel controls
    ctrl = bst_get('PanelControls', 'Dipoles');
    if isempty(ctrl)
        return;
    end
    % Goodness
    sScales = GetSliderScales('goodness',hFig);
    if isempty([sScales.min])
        ctrl.jLabelGoodness.setEnabled(0);
        ctrl.jTitleGoodness.setEnabled(0);
        ctrl.jSliderGoodness.setEnabled(0);
        ctrl.jToggleColorGoodness.setEnabled(0);
        ctrl.jToggleMaxGoodness.setEnabled(0);
    end
    % Khi2
    sScales = GetSliderScales('khi2',hFig);
    if isempty([sScales.min])
        ctrl.jLabelKhi2.setEnabled(0);
        ctrl.jTitleKhi2.setEnabled(0);
        ctrl.jSliderKhi2.setEnabled(0);
    end
    % ConfVol
    sScales = GetSliderScales('confvol',hFig);
    if isempty([sScales.min])
        ctrl.jTitleConfVol.setEnabled(0);
        ctrl.jLabelConfVol.setEnabled(0);
        ctrl.jSliderConfVol.setEnabled(0);
    end

    % Make the list visible if more than one set
    nDipoles = length(DipolesInfo.DipoleNames);
    nSubsets = length(DipolesInfo.Subset);
    if (nDipoles > 2) || (nSubsets > 2)
       ctrl.jPanelList.setVisible(1);
    end

    % Set the display color scheme
    if ctrl.jToggleColorTime.isSelected()
        DipolesInfo.DisplayColorType = 'time';
    elseif ctrl.jToggleColorGoodness.isSelected()
        DipolesInfo.DisplayColorType = 'goodness';
    elseif ctrl.jToggleColorGroup.isSelected()
        DipolesInfo.DisplayColorType = 'group';
    end

    % Determine if there is any display filters
    % Show preferred time only
    if ctrl.jToggleSelTimes.isSelected()
        DipolesInfo.DisplaySelTimes = 1;
        ctrl.jToggleMaxGoodness.setSelected(0);
        ctrl.jToggleAllTimes.setSelected(0);
        % Do not allow setting preferred time when this filter is on
        ctrl.jButtonSetSel.setEnabled(0);
    else
        ctrl.jButtonSetSel.setEnabled(1);
    end
    % Show all time
    if ctrl.jToggleAllTimes.isSelected()
        DipolesInfo.DisplayAllTime = 1;
        % Do not allow setting preferred time when all time is displayed
        ctrl.jButtonSetSel.setEnabled(0);
    end
    % Show maximum goodness of selected dipoles
    if ctrl.jToggleMaxGoodness.isSelected()
        DipolesInfo.DisplayMaxGoodness = 1;
    end
end

%% ===== UPDATE DIPOLES LIST =====
function UpdateDipolesList(hFig, isSelectAll)
    % Parse inputs
    if (nargin < 2) || isempty(isSelectAll)
        isSelectAll = 0;
    end
    % Get Dipoles description in figure
    if ~isempty(hFig)
        DipolesInfo = GetDipolesForFigure(hFig);
        if isempty(DipolesInfo)
            return
        end
        nDipoles = length(DipolesInfo.DipoleNames);
        nSubsets = length(DipolesInfo.Subset);
    else
        nDipoles = 0;
        nSubsets = 0;
    end
    % Get panel controls
    ctrl = bst_get('PanelControls', 'Dipoles');
    if isempty(ctrl)
        return;
    end
    % ==== Dipole List
    % Remove JList callback
    bakCallback = java_getcb(ctrl.jListDipoles, 'ValueChangedCallback');
    java_setcb(ctrl.jListDipoles, 'ValueChangedCallback', []);

    % Create a new empty list
    listModel = java_create('javax.swing.DefaultListModel');
    % Add an item in list for each scout found for target figure
    for i = 1:nDipoles
        listModel.addElement(DipolesInfo.DipoleNames{i});
    end
    % Update list model
    ctrl.jListDipoles.setModel(listModel);

    % ==== Subset List
    % Remove JList callback
    sbakCallback = java_getcb(ctrl.jListSubsets, 'ValueChangedCallback');
    java_setcb(ctrl.jListSubsets, 'ValueChangedCallback', []);

    % Create a new empty list
    subsetModel = java_create('javax.swing.DefaultListModel');
    % Add an item in list for each subset
    for i = 1:nSubsets
        subsetModel.addElement(['Subset #' num2str(DipolesInfo.Subset(i))]);
    end

    % Update list model
    ctrl.jListSubsets.setModel(subsetModel);
    drawnow

    % Select all dipoles
    if isSelectAll && (nDipoles > 0)
        iSel = 1:nDipoles;
    % Get dipoles displayed in this figure
    else
        iSel = GetDisplayedDipoles(hFig);
    end
    % Change list selection
    if ~isempty(iSel)
        ctrl.jListDipoles.setSelectedIndices(iSel - 1);
    end

    % Restore callback
    drawnow
    java_setcb(ctrl.jListDipoles, 'ValueChangedCallback', bakCallback);
    java_setcb(ctrl.jListSubsets, 'ValueChangedCallback', sbakCallback);

end

%% ===== UPDATE DISPLAY OPTIONS ======
function FireUpdateDisplayOptions(varargin)
    % Progress bar
    isProgress = bst_progress('IsVisible');
    if ~isProgress
        bst_progress('start', 'Dipoles', 'Updating figure...');
    end
    % Update all figures with selected display options
    hFigs = bst_figures('GetAllFigures');
    for iFig = 1:length(hFigs)
        hFig = hFigs(iFig);
        FigureId = getappdata(hFig, 'FigureId');
        DipolesInfo = GetDipolesForFigure(hFig);
        % Redraw dipoles for current figure
        if ~isempty(FigureId) && ~isempty(DipolesInfo.Dipole)
            switch (FigureId.Type)
                case 'MriViewer'
                    % Nothing specific to update
                case '3DViz'
                    % === 3D: SPECIAL COLORMAPS ===
                    CmapInfo = getappdata(hFig, 'Colormap');
                    switch DipolesInfo.DisplayColorType
                        % Color = Time
                        case 'time'
                            CmapInfo.Type = 'time';
                            CmapInfo.AllTypes{end+1} = 'time';
                            CmapInfo.AllTypes = unique(CmapInfo.AllTypes);
                        % Color = Goodness of fit
                        case 'goodness'
                            CmapInfo.Type = 'percent';
                            CmapInfo.AllTypes{end+1} = 'percent';
                            CmapInfo.AllTypes = unique(CmapInfo.AllTypes);
                        % Color = Group (no colormap)
                        case 'group'
                            CmapInfo.AllTypes = setdiff(CmapInfo.AllTypes, {'time', 'percent', 'stat1'});
                            if ~isempty(CmapInfo.AllTypes)
                                CmapInfo.Type = CmapInfo.AllTypes{1};
                            else
                                CmapInfo.Type = [];
                            end
                    end
                    % Update 3D figure configuration
                    setappdata(hFig, 'Colormap', CmapInfo);
            end
        end
        % Redraw dipoles for current figure
        RedrawDipoles(hFig);
    end
    % Close progress bar
    if ~isProgress
        bst_progress('stop');
    end
end

%% ===== UPDATE COLORMAP =====
function FireUpdateSurfaceColormap()
    [hFigs] = bst_figures('GetAllFigures');
    for iFig = 1:length(hFigs)
        hFig = hFigs(iFig);
        panel_surface('UpdateSurfaceColormap', hFig);
    end
end
%% ===== GET DISPLAYED DIPOLES =====
function iSel = GetDisplayedDipoles(hFig)
    iSel = [];
    if ~isempty(hFig) && ishandle(hFig)
        DipolesInfo = getappdata(hFig, 'Dipoles');
        if isfield(DipolesInfo, 'Selected')
            iSel = DipolesInfo.Selected;
        end
    end
end

%% ===== GET SELECTED DIPOLES =====
function [sDipoles, iDipoles] = GetSelectedDipoles(hFig)
    global GlobalData
    sDipoles = [];
    iDipoles = [];
    % Get Dipoles description in figure
    DipolesInfo = GetDipolesForFigure(hFig);
    if isempty(DipolesInfo) || isempty(DipolesInfo.Dipole)
        return
    end
    % Get panel controls
    ctrl = bst_get('PanelControls', 'Dipoles');
    if isempty(ctrl)
        return;
    end
    % Get the selected dipoles in JList
    iSelList = double(ctrl.jListDipoles.getSelectedIndices() + 1);
    % Save selection list in figure
    DipolesApp = getappdata(hFig, 'Dipoles');
    DipolesApp.Selected = iSelList;
    setappdata(hFig, 'Dipoles', DipolesApp);

    % Select time points
    if DipolesInfo.DisplayAllTime || DipolesInfo.DisplaySelTimes
        % Select all time points when this is asked for explicitly or when
        % using the custom selected times filter
        iSelTime = 1:length(DipolesInfo.Dipole);
    else
        % Select only those time points that are closest to the current time
        curTime = GlobalData.UserTimeWindow.CurrentTime;
        if isempty(curTime)
            iSelTime = find(abs([DipolesInfo.Dipole.Time] - [DipolesInfo.Dipole(1).Time]) < 1e-6);
        else
            iSelTime = find(abs([DipolesInfo.Dipole.Time] - curTime) < 1e-6);
        end
    end

    % Get dipoles that fit the selection
    if isempty(iSelTime)
        return
    end
    iDipoles = iSelTime(ismember([DipolesInfo.Dipole(iSelTime).Index], iSelList));

    % Show only the preferred time point dipoles
    if DipolesInfo.DisplaySelTimes && ~isempty(iDipoles)
        indexNums = [DipolesInfo.Dipole(iDipoles).Index];
        % Find unique index numbers (groups)
        nIndexNums = unique(indexNums);
        % Loop through groups to find the selected time of each group
        iGroupTime = zeros(1,length(nIndexNums));
        for n=1:length(nIndexNums)
            ind = find(indexNums == nIndexNums(n));
            groupTimes = [DipolesInfo.Dipole(ind).Time];
            t = DipolesInfo.PreferredTimes(nIndexNums(n));
            iGroupTime(n) = bst_closest(groupTimes,t) + ind(1) - 1;
        end
        % Get the indices of the maximums
        iDipoles = iDipoles(iGroupTime);
    end

    % Slider thresholds

    % Goodness
    sScales = GetSliderScales('goodness', hFig);
    if ~isempty([sScales.min])
        minGoodness = double(ctrl.jSliderGoodness.getValue()) ./ 100;
        iDipoles = iDipoles([DipolesInfo.Dipole(iDipoles).Goodness] >= minGoodness);
    end
    % Khi2
    sScales = GetSliderScales('khi2', hFig);
    if ~isempty([sScales.min])
        val = double(ctrl.jSliderKhi2.getValue());
        minKhi2 = val/100 * sScales.max;
        iDipoles = iDipoles([DipolesInfo.Dipole(iDipoles).Khi2] <= minKhi2);
        % Update text field
        ctrl.jLabelKhi2.setText(sprintf('%1.1e', minKhi2));
    end
    % ConfVol
    sScales = GetSliderScales('confvol', hFig);
    if ~isempty([sScales.min])
        val = double(ctrl.jSliderConfVol.getValue());
        minConfVol = val/100 * sScales.max;
        iDipoles = iDipoles([DipolesInfo.Dipole(iDipoles).ConfVol] <= minConfVol);
        % Update text field
        ctrl.jLabelConfVol.setText(sprintf('%1.1e', minConfVol));
    end

    % Show only maximum goodness of fit
    if DipolesInfo.DisplayMaxGoodness && ~isempty(iDipoles)
        indexNums = [DipolesInfo.Dipole(iDipoles).Index];
        % Find unique index numbers (groups)
        nIndexNums = unique(indexNums);
        goodVals = [DipolesInfo.Dipole(iDipoles).Goodness];
        % Loop through groups to find the max goodness of each group
        iMaxGoodness = zeros(1,length(nIndexNums));
        for n=1:length(nIndexNums)
            ind = find(indexNums == nIndexNums(n));
            z = zeros(1, length(goodVals));
            % Get the goodness values for the group
            z(ind) = goodVals(ind);
            % Get the maximum goodness for the group
            [maxGoodness, iMaxGoodness(n)] = max(z);
        end
        % Get the indices of the maximums
        iDipoles = iDipoles(iMaxGoodness);
    end

    % Get dipoles selected in time and index at the same time
    sDipoles = DipolesInfo.Dipole(iDipoles);
end

%% ===== REDRAW DIPOLES =====
function RedrawDipoles(hFig)
    % Get figure type
    FigureId = getappdata(hFig, 'FigureId');
    % Redraw dipoles for current figure
    if ~isempty(FigureId)
        switch (FigureId.Type)
            case 'MriViewer'
                panel_surface('UpdateSurfaceData', hFig)
            case '3DViz'
                PlotSelectedDipoles(hFig);
        end
    end
end

%% ===== PLOT DIPOLES =====
function PlotSelectedDipoles(hFig)
    % Get panel controls
    ctrl = bst_get('PanelControls', 'Dipoles');
    if isempty(ctrl)
        return;
    end
    % Get axis
    hAxes = findobj(hFig, '-depth', 1, 'Tag', 'Axes3D');
    if isempty(hAxes)
        return
    end
    % Delete previous dipoles display
    hPoints = findobj(hAxes, '-depth', 1, 'Tag', 'DipolesLoc');
    hLines  = findobj(hAxes, '-depth', 1, 'Tag', 'DipolesOrient');
    if ~isempty(hPoints)
        delete([hPoints(:); hLines(:)]);
    end

    % Get all dipoles
    DipolesInfo = GetDipolesForFigure(hFig);
    % Get selected dipoles
    [sDipoles, iDipoles] = GetSelectedDipoles(hFig);
    if isempty(sDipoles)
        return
    end

    % ===== GROUP DIPOLES =====
    % If color-coded time => group dipoles by time
    ColormapInfo = getappdata(hFig, 'Colormap');
    switch DipolesInfo.DisplayColorType
        case 'time'
            % Get all times for all dipoles
            allTimes = [DipolesInfo.Dipole.Time];
            % Get times for selected dipoles
            selTimes = [sDipoles.Time];
            dipGroupTag = 1:length(sDipoles);
            % Get time colormap
            sColormap = bst_colormaps('GetColormap', ColormapInfo.Type);

            if length(allTimes) < 2
                % Get time limits for this figure
                hAxes = [findobj(hFig, '-depth', 1, 'Tag', 'Axes3D'), ...
                         findobj(hFig, '-depth', 1, 'Tag', 'axc'), ...
                         findobj(hFig, '-depth', 1, 'Tag', 'axa'), ...
                         findobj(hFig, '-depth', 1, 'Tag', 'axs')];
                CLim = get(hAxes(1), 'CLim');
            else
                % Get time limits for the selected group(s)
                CLim = [min(allTimes), max(allTimes)];
            end
            % If start = stop time: cannot create a colormap
            if (CLim(1) == CLim(2))
                CLim(2) = CLim(1) + 0.001;
            end
            % Get color table for dipoles
            if isequal(CLim, [0,1]) && (length(allTimes) < 2)
                iCol = 1;
            else
                iCol = round((selTimes - CLim(1)) / abs(CLim(2) - CLim(1)) * (length(sColormap.CMap) - 1)) + 1;
                iCol = bst_saturate(iCol, [1, length(sColormap.CMap)]);
            end
            ColorTable = sColormap.CMap(iCol, :);

        case 'goodness'
            % Group tag is the Index
            dipGroupTag = 1:length(sDipoles);
            % Get color table for dipoles
            sColormap = bst_colormaps('GetColormap', ColormapInfo.Type);
            selGoodness = bst_saturate([sDipoles.Goodness] * 100, [0, 100]);
            CLim = [0, 100];
            % Get color table for dipoles
            iCol = round((selGoodness - CLim(1)) / abs(CLim(2) - CLim(1)) * (length(sColormap.CMap) - 1)) + 1;
            ColorTable = sColormap.CMap(iCol, :);

        case 'group'
            % Group tag is the Index
            dipGroupTag = [sDipoles.Index];
            % Get color table for dipoles
            ColorTable = GetDipolesColorTable();
    end
    % Group dipoles by index
    dipGroups = unique(dipGroupTag);
    % Get display properties
    pointSize = ctrl.jSliderDipSize.getValue;
    lineWidth = 1.5*(ctrl.jSliderTailWidth.getValue/10);

    % ===== DISPLAY GROUPS =====
    % Get number of different groups
    for iGroup = 1:length(dipGroups)
        % Get all the dipoles of this group
        iDipGroup = find(dipGroupTag == dipGroups(iGroup));
        % Get dipole locations
        Loc = [sDipoles(iDipGroup).Loc];
        % Compute dipole orientations (normalized amplitude)
        Orient = [sDipoles(iDipGroup).Amplitude];
        normAmp = sqrt(sum(Orient.^2,1));
        Orient = Orient ./ repmat(normAmp,3,1) .* 0.02;
        % Get color
        iColor = mod(dipGroups(iGroup)-1, size(ColorTable,1)) + 1;

        % Loop added to be able to track each dipole inpendently
        for i = 1:length(iDipGroup)
            % Plot point
            line(Loc(1,i), Loc(2,i), Loc(3,i), ...
                'LineStyle',       'none', ...
                'MarkerFaceColor', ColorTable(iColor,:), ...
                'Marker',          'o', ...
                'MarkerEdgeColor', [.4 .4 .4], ...
                'MarkerSize',      pointSize, ...
                'Tag',             'DipolesLoc', ...
                'UserData',        iDipoles(iDipGroup(i)), ...
                'Parent',          hAxes);
            % Plot orientation
            if lineWidth > 0.70
                line([Loc(1,i); Loc(1,i) + Orient(1,i)], ...
                     [Loc(2,i); Loc(2,i) + Orient(2,i)], ...
                     [Loc(3,i); Loc(3,i) + Orient(3,i)], ...
                    'Color',      ColorTable(iColor,:), ...
                    'LineStyle',  '-', ...
                    'LineWidth',   lineWidth, ...
                    'Tag',        'DipolesOrient', ...
                    'UserData',        iDipoles(iDipGroup(i)), ...
                    'Parent',     hAxes);
            end
        end
    end
    % Force updating this figure before upd
    drawnow
end

%% ===== GET DIPOLES COLOR TABLE =====
function ColorTable = GetDipolesColorTable()
    ColorTable = [0    1    0   ;
                  1    0    0   ;
                  .4   .4   1   ;
                  1    .694 .392;
                  0    1    1   ;
                  1    0    1   ;
                  .4   0    0  ;
                  0    .5   0];
end

%% ===== COMPUTE DENSITY VOLUMES =====
function Cube = ComputeDensity(sMri, sDipoles) %#ok<DEFNU>
    % Initialize cube
    sizeCube = size(sMri.Cube(:,:,:,1));
    Cube = zeros(sizeCube);

    % Gaussian kernel
    A = zeros(5,5,5);
    A(:,:,1) = [0 0 0 0 0;
                0 0 0 0 0;
                0 0 1 0 0;
                0 0 0 0 0;
                0 0 0 0 0];

    A(:,:,2) = [0 0 0 0 0;
                0 1 2 1 0;
                0 2 3 2 0;
                0 1 2 1 0;
                0 0 0 0 0];

    A(:,:,3) = [0 1 1 1 0;
                1 2 3 2 1;
                1 3 4 3 1;
                1 2 3 2 1;
                0 1 1 1 0];
    A(:,:,4) = A(:,:,2);
    A(:,:,5) = A(:,:,1);

    % Loop on each dipole
    for i = 1:length(sDipoles)
        % Vertices: SCS->Voxels
        mriLoc = round(cs_convert(sMri, 'scs', 'voxel', [sDipoles(i).Loc]'));
        % Get the valid indices in the kernel
        iX = [min(2, mriLoc(:,1) - 1),  min(2, sizeCube(1)-mriLoc(:,1))];
        iY = [min(2, mriLoc(:,2) - 1),  min(2, sizeCube(2)-mriLoc(:,2))];
        iZ = [min(2, mriLoc(:,3) - 1),  min(2, sizeCube(3)-mriLoc(:,3))];
        % Each dipole is displayed by a cube of 5*5*5 voxels (gaussian kernel)
        X = mriLoc(:,1) - iX(1) : mriLoc(:,1) + iX(2);
        Y = mriLoc(:,2) - iY(1) : mriLoc(:,2) + iY(2);
        Z = mriLoc(:,3) - iZ(1) : mriLoc(:,3) + iZ(2);
        Cube(X,Y,Z) = Cube(X,Y,Z) + A(3-iX(1):3+iX(2), 3-iY(1):3+iY(2), 3-iZ(1):3+iZ(2));
    end
    % Convert in percentage
    maxCube = max(Cube(:));
    if (maxCube > 0)
        Cube = Cube ./ maxCube .* 100;
    end
end

%% ===== SLIDER SCALES =====
function sScales = GetSliderScales(varargin)
    global GlobalData;

    if size(varargin,2) < 2
        scale = varargin{1};
        hFig = bst_figures('GetCurrentFigure');
    else
        scale = varargin{1};
        hFig = varargin{2};
    end

    % Initialize returned structures
    sScales.label = {};
    sScales.min = [];
    sScales.max = [];
    DipolesInfo.Dipole = [];

    % Get Dipoles description in figure
    DipolesApp = getappdata(hFig, 'Dipoles');
    if isempty(DipolesApp)
        return
    end
    % For each dipoles file displayed in this figure
    for i = 1:length(DipolesApp)
        % Get loaded dipoles
        [iDS, iDipoles] = bst_memory('GetDataSetDipoles', DipolesApp(i).FileName);
        % Add description to dipoles
        DipolesInfo.Dipole = [DipolesInfo.Dipole, GlobalData.DataSet(iDS).Dipoles(iDipoles).Dipole];
    end

    switch scale
        case 'goodness'
            % find scale of goodness
            sScales.label = {'goodness'};
            sScales.min = min([DipolesInfo.Dipole.Goodness]);
            sScales.max = max([DipolesInfo.Dipole.Goodness]);
        case 'khi2'
            % find scale of khi2 value
            sScales.label = {'khi2'};
            sScales.min = min([DipolesInfo.Dipole.Khi2]);
            sScales.max = max([DipolesInfo.Dipole.Khi2]);
        case 'rkhi2'
            % find scale of Reduced khi2 value
            sScales.label = {'rkhi2'};
            sScales.min = min([DipolesInfo.Dipole.DOF]);
            sScales.max = max([DipolesInfo.Dipole.DOF]);
        case 'confvol'
            % find scale of confidence volume values
            sScales.label = {'confvol'};
            sScales.min = min([DipolesInfo.Dipole.ConfVol]);
            sScales.max = max([DipolesInfo.Dipole.ConfVol]);
    end
end

%% ===== SET GOODNESS THRESHOLD =====
function SetGoodness(Goodness) %#ok<DEFNU>
    % Get panel controls
    ctrl = bst_get('PanelControls', 'Dipoles');
    if isempty(ctrl)
        return;
    end
    % Round goodness of fit
    Goodness = round(Goodness * 100);
    % Set the goodness of fit
    if isfield(ctrl, 'jSliderGoodness') && ctrl.jSliderGoodness.isEnabled() && (Goodness >= 0) && (Goodness < 100)
        % Set slider
        ctrl.jSliderGoodness.setValue(Goodness);
        ctrl.jLabelGoodness.setText(sprintf('%d%%', Goodness));
        % Update figures
        FireUpdateDisplayOptions();
    end
end


 function cells = blockify_data(ob, data, varargin)
%function cells = blockify_data(ob, data, varargin)

if isempty(ob.handle_blockify_data)
	error(['The Fatrix of type ' ob.caller ' has no handle_blockify_data'])
end
cells = ob.handle_blockify_data(ob, data, varargin{:});


%% OMAS SYSTEM ENUMS (OMAS_systemType.m) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

classdef OMAS_systemType < uint8
   enumeration
      windows(0);
      OSX(1);
      linux(2);
   end
end


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

% Last Modified by GUIDE v2.5 11-May-2021 14:34:10

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

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

    event = varargin{1};
    setappdata(hObject,'event',event);
    setappdata(hObject,'lvdData',event.script.lvdData);

    populateGUI(handles, event);

    % Update handles structure
    guidata(hObject, handles);

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

function populateGUI(handles, event)
    termCondStrs = TerminationConditionEnum.getTermCondTypeNameStrs();
    set(handles.termCondTypeCombo,'String',termCondStrs);

    termCond = event.termCond;
    ind = TerminationConditionEnum.getIndOfListboxStrsForTermCond(termCond);
    set(handles.termCondTypeCombo,'Value',ind);

    params = termCond.getTermCondUiStruct();

    value = params.value;
    if(isempty(value))
        value = 0.0;
    end

    set(handles.numParamText,'String',fullAccNum2Str(value));

    lv = event.script.lvdData.launchVehicle;

    stagesListStr = lv.getStagesListBoxStr();
    set(handles.refStageCombo,'String',stagesListStr);

    tanksListStr = lv.getTanksListBoxStr();
    set(handles.refTankCombo,'String',tanksListStr);

    enginesListStr = lv.getEnginesListBoxStr();
    set(handles.refEngineCombo,'String',enginesListStr);

    swListStr = lv.getStopwatchesListBoxStr();
    set(handles.refStopwatchCombo,'String',swListStr);
    if(isempty(swListStr))
        set(handles.refStopwatchCombo,'String','<No Stopwatch Yet Created>');
        set(handles.refStopwatchCombo,'Value',1);
    end

    set(handles.numParamLabel,'String',params.paramName);
    set(handles.numParamUnitLabel,'String',params.paramUnit);

    set(handles.numParamText,'Enable',params.useParam);
    set(handles.optParamCheckbox,'Enable',params.useParam);
    set(handles.paramLbText,'Enable',params.useParam);
    set(handles.paramUbText,'Enable',params.useParam);

    set(handles.refStageCombo,'Enable',params.useStages);
    set(handles.refTankCombo,'Enable',params.useTanks);
    set(handles.refEngineCombo,'Enable',params.useEngines);
    set(handles.refStopwatchCombo,'Enable',params.useStopwatches);

    if(not(isempty(params.refStage)))
        set(handles.refStageCombo,'Value',lv.getListBoxIndForStage(params.refStage));
    end

    if(not(isempty(params.refTank)))
        set(handles.refTankCombo,'Value',lv.getListBoxIndForTank(params.refTank));
    end

    if(not(isempty(params.refEngine)))
        set(handles.refEngineCombo,'Value',lv.getListBoxIndForEngine(params.refEngine));
    end

    if(not(isempty(params.refStopwatch)))
        set(handles.refStopwatchCombo,'Value',lv.getListBoxIndForStopwatch(params.refStopwatch));
    end

    optVar = termCond.getExistingOptVar();
    if(isempty(optVar))
        useTf = false([1,1]);
        lb = zeros(size(useTf));
        ub = zeros(size(useTf));
    else
        useTf = optVar.getUseTfForVariable();
        optVar.setUseTfForVariable(true(size(useTf)));
        [lb, ub] = optVar.getBndsForVariable();
        optVar.setUseTfForVariable(useTf);
    end

    if(strcmpi(params.paramUnit,'deg'))
        lb = rad2deg(lb);
        ub = rad2deg(ub);
    elseif(strcmpi(params.paramUnit,'%'))
        lb = lb*100;
        ub = ub*100;
    end

    lbStr = fullAccNum2Str(lb);
    ubStr = fullAccNum2Str(ub);

    set(handles.optParamCheckbox,'Value',useTf);
    set(handles.paramLbText,'String',lbStr);
    set(handles.paramUbText,'String',ubStr);

    optParamCheckbox_Callback(handles.optParamCheckbox,[],handles);

    frame = termCond.frame;
    if(isempty(frame))
        frame = LvdData.getDefaultInitialBodyInfo(event.script.lvdData.celBodyData).getBodyCenteredInertialFrame();
        termCond.frame = frame;
    end
    setappdata(handles.lvd_editEvtTermCond,'frame',frame);

    handles.refFrameTypeCombo.String = ReferenceFrameEnum.getListBoxStr();
    [ind, ~] = ReferenceFrameEnum.getIndForName(frame.typeEnum.name);
    handles.refFrameTypeCombo.Value = ind;
    handles.setFrameOptionsButton.TooltipString = sprintf('Current Frame: %s', frame.getNameStr());
    handles.refFrameNameLabel.String = sprintf('%s', frame.getNameStr());
    handles.refFrameNameLabel.TooltipString = sprintf('%s', frame.getNameStr());

% --- Outputs from this function are returned to the command line.
function varargout = lvd_editEvtTermCond_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
    if(isempty(handles))
        varargout{1} = [];
    else
        event = getappdata(hObject,'event');
        lv = event.script.lvdData.launchVehicle;

        paramValue = str2double(get(handles.numParamText,'String'));

        termCond = event.termCond;
        params = getParamsForSelectedTermCondType(handles);

        optVar = termCond.getExistingOptVar();
        if(not(isempty(optVar)))
            lv.lvdData.optimizer.vars.removeVariable(optVar);%need to remove existing var if it exists
        end

        if(strcmpi(params.paramUnit,'deg'))
            paramValue = deg2rad(paramValue);
        elseif(strcmpi(params.paramUnit,'%'))
            paramValue = paramValue/100;
        end

        [~,stages] = lv.getStagesListBoxStr();
        [~,tanks] = lv.getTanksListBoxStr();
        [~,engines] = lv.getEnginesListBoxStr();
        [~,stopwatches] = lv.getStopwatchesListBoxStr();

        if(not(isempty(stages)))
            stage = stages(get(handles.refStageCombo,'Value'));
        else
            stage = stages;
        end

        if(not(isempty(tanks)))
            tank = tanks(get(handles.refTankCombo,'Value'));
        else
            tank = tanks;
        end

        if(not(isempty(engines)))
            engine = engines(get(handles.refEngineCombo,'Value'));
        else
            engine = engines;
        end

        if(not(isempty(stopwatches)))
            stopwatch = stopwatches(get(handles.refStopwatchCombo,'Value'));
        else
            stopwatch = stopwatches;
        end

        [m,~] = enumeration('TerminationConditionEnum');
        contents = cellstr(get(handles.termCondTypeCombo,'String'));
        termCondType = contents{get(handles.termCondTypeCombo,'Value')};
        ind = strcmpi({m.nameStr},termCondType);
        termCond = feval(sprintf('%s.getTermCondForParams',m(ind).classNameStr), paramValue, stage, tank, engine, stopwatch);

        lb = str2double(get(handles.paramLbText,'String'));
        ub = str2double(get(handles.paramUbText,'String'));

        if(strcmpi(params.paramUnit,'deg'))
            lb = deg2rad(lb);
            ub = deg2rad(ub);
        elseif(strcmpi(params.paramUnit,'%'))
            lb = lb/100;
            ub = ub/100;
        end

        optVar = termCond.getNewOptVar();

        if(not(isempty(optVar)))
            optVar.setUseTfForVariable(true);
            optVar.setBndsForVariable(lb, ub);

            useTf = logical(get(handles.optParamCheckbox,'Value'));
            optVar.setUseTfForVariable(useTf);

            termCond.optVar = optVar;
            optVar.varObj = termCond;

            lv.lvdData.optimizer.vars.addVariable(optVar);
        end

        frame = getappdata(hObject,'frame');
        termCond.frame = frame;

        event.termCond = termCond;

        close(handles.lvd_editEvtTermCond);
    end

function errMsg = validateInputs(handles)
    errMsg = {};

    value = str2double(get(handles.numParamText,'String'));
    enteredStr = get(handles.numParamText,'String');
    numberName = get(handles.numParamLabel,'String');
    lb = -Inf;
    ub = Inf;
    isInt = false;
    errMsg = validateNumber(value, numberName, lb, ub, isInt, errMsg, enteredStr);

    lwrBndValue = str2double(get(handles.paramLbText,'String'));
    enteredStr = get(handles.paramLbText,'String');
    numberName = [get(handles.numParamLabel,'String'), ' Lower Bound'];
    lb = -Inf;
    ub = Inf;
    isInt = false;
    errMsg = validateNumber(lwrBndValue, numberName, lb, ub, isInt, errMsg, enteredStr);

    uprBndValue = str2double(get(handles.paramUbText,'String'));
    enteredStr = get(handles.paramUbText,'String');
    numberName = [get(handles.numParamLabel,'String'), ' Upper Bound'];
    lb = -Inf;
    ub = Inf;
    isInt = false;
    errMsg = validateNumber(uprBndValue, numberName, lb, ub, isInt, errMsg, enteredStr);

    if(isempty(errMsg))
        uprBndValue = str2double(get(handles.paramUbText,'String'));
        enteredStr = get(handles.paramUbText,'String');
        numberName = [get(handles.numParamLabel,'String'), ' Upper Bound'];
        lb = lwrBndValue;
        ub = Inf;
        isInt = false;
        errMsg = validateNumber(uprBndValue, numberName, lb, ub, isInt, errMsg, enteredStr);
    end

% --- Executes on selection change in termCondTypeCombo.
function termCondTypeCombo_Callback(hObject, eventdata, handles)
% hObject    handle to termCondTypeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns termCondTypeCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from termCondTypeCombo
    params = getParamsForSelectedTermCondType(handles);

    set(handles.numParamLabel,'String',params.paramName);
    set(handles.numParamUnitLabel,'String',params.paramUnit);

    set(handles.numParamText,'Enable',params.useParam);
    set(handles.optParamCheckbox,'Enable',params.useParam);
    set(handles.paramLbText,'Enable',params.useParam);
    set(handles.paramUbText,'Enable',params.useParam);

    if(params.useParam == false)
        set(handles.optParamCheckbox,'Value',0);
    end

    set(handles.refStageCombo,'Enable',params.useStages);
    set(handles.refTankCombo,'Enable',params.useTanks);
    set(handles.refEngineCombo,'Enable',params.useEngines);
    set(handles.refStopwatchCombo,'Enable',params.useStopwatches);

function params = getParamsForSelectedTermCondType(handles)
	event = getappdata(handles.lvd_editEvtTermCond,'event');
    lv = event.script.lvdData.launchVehicle;

    [~,stages] = lv.getStagesListBoxStr();
    [~,tanks] = lv.getTanksListBoxStr();
    [~,engines] = lv.getEnginesListBoxStr();
    [~, stopwatches] = lv.getStopwatchesListBoxStr();

    stage = stages(1);
    tank = tanks(1);
    engine = engines(1);

    if(not(isempty(stopwatches)))
        stopwatch = stopwatches(1);
    else
        stopwatch = LaunchVehicleStopwatch.empty(1,0);
    end

    [m,~] = enumeration('TerminationConditionEnum');
    contents = cellstr(get(handles.termCondTypeCombo,'String'));
    termCondType = contents{get(handles.termCondTypeCombo,'Value')};
    ind = strcmpi({m.nameStr},termCondType);
    termCond = feval(sprintf('%s.getTermCondForParams',m(ind).classNameStr), 0, stage, tank, engine, stopwatch);

    params = termCond.getTermCondUiStruct();

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

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function numParamText_Callback(hObject, eventdata, handles)
% hObject    handle to numParamText (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,'String') returns contents of numParamText as text
%        str2double(get(hObject,'String')) returns contents of numParamText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

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

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in refStageCombo.
function refStageCombo_Callback(hObject, eventdata, handles)
% hObject    handle to refStageCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns refStageCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from refStageCombo

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

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in refTankCombo.
function refTankCombo_Callback(hObject, eventdata, handles)
% hObject    handle to refTankCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns refTankCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from refTankCombo

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

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in refEngineCombo.
function refEngineCombo_Callback(hObject, eventdata, handles)
% hObject    handle to refEngineCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns refEngineCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from refEngineCombo

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

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

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

    if(isempty(errMsg))
       uiresume(handles.lvd_editEvtTermCond);
    else
        msgbox(errMsg,'Errors were found while editing the termination conditions.','error');
    end

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

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

% Hint: get(hObject,'Value') returns toggle state of optParamCheckbox
    if(get(hObject,'Value') == 1)
        set(handles.paramLbText,'Enable','on');
        set(handles.paramUbText,'Enable','on');
    else
        set(handles.paramLbText,'Enable','off');
        set(handles.paramUbText,'Enable','off');
    end

function paramLbText_Callback(hObject, eventdata, handles)
% hObject    handle to paramLbText (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,'String') returns contents of paramLbText as text
%        str2double(get(hObject,'String')) returns contents of paramLbText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

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

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function paramUbText_Callback(hObject, eventdata, handles)
% hObject    handle to paramUbText (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,'String') returns contents of paramUbText as text
%        str2double(get(hObject,'String')) returns contents of paramUbText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

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

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on key release with focus on lvd_editEvtTermCond or any of its controls.
function lvd_editEvtTermCond_WindowKeyReleaseFcn(hObject, eventdata, handles)
% hObject    handle to lvd_editEvtTermCond (see GCBO)
% eventdata  structure with the following fields (see MATLAB.UI.FIGURE)
%	Key: name of the key that was released, in lower case
%	Character: character interpretation of the key(s) that was released
%	Modifier: name(s) of the modifier key(s) (i.e., control, shift) released
% handles    structure with handles and user data (see GUIDATA)
    switch(eventdata.Key)
        case 'return'
            saveAndCloseButton_Callback(handles.saveAndCloseButton, [], handles);
        case 'enter'
            saveAndCloseButton_Callback(handles.saveAndCloseButton, [], handles);
        case 'escape'
            close(handles.lvd_editEvtTermCond);
    end

% --- Executes on selection change in refStopwatchCombo.
function refStopwatchCombo_Callback(hObject, eventdata, handles)
% hObject    handle to refStopwatchCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns refStopwatchCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from refStopwatchCombo

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

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in refFrameTypeCombo.
function refFrameTypeCombo_Callback(hObject, eventdata, handles)
% hObject    handle to refFrameTypeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns refFrameTypeCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from refFrameTypeCombo
    updateFrameChange(handles);

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

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in setFrameOptionsButton.
function setFrameOptionsButton_Callback(hObject, eventdata, handles)
% hObject    handle to setFrameOptionsButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
    curFrame = getappdata(handles.lvd_editEvtTermCond,'frame');
    curFrame = curFrame.editFrameDialogUI(EditReferenceFrameContextEnum.ForState);

    setappdata(handles.lvd_editEvtTermCond,'frame',curFrame);

    handles.setFrameOptionsButton.Tooltip = sprintf('Current Frame: %s', curFrame.getNameStr());
    handles.refFrameNameLabel.String = sprintf('%s', curFrame.getNameStr());
    handles.refFrameNameLabel.TooltipString = sprintf('%s', curFrame.getNameStr());

function updateFrameChange(handles)
    lvdData = getappdata(handles.lvd_editEvtTermCond,'lvdData');
    celBodyData = lvdData.celBodyData;

    refEnumListBoxStr = ReferenceFrameEnum.getListBoxStr();
    selFrameTypeInd = handles.refFrameTypeCombo.Value;
    refFrameEnum = ReferenceFrameEnum.getEnumForListboxStr(refEnumListBoxStr{selFrameTypeInd});

%             if(not(isempty(newFrame)) && newFrame.typeEnum ~= refFrameEnum)
%                 refFrameEnum = newFrame.typeEnum;
%                 app.refFrameTypeCombo.Value = ReferenceFrameEnum.getIndForName(refFrameEnum.name);
%             end

    switch refFrameEnum
        case ReferenceFrameEnum.BodyCenteredInertial
            bodyInfo = getSelectedBodyInfo(handles);

            newFrame = bodyInfo.getBodyCenteredInertialFrame();

        case ReferenceFrameEnum.BodyFixedRotating
            bodyInfo = getSelectedBodyInfo(handles);

            newFrame = bodyInfo.getBodyFixedFrame();

        case ReferenceFrameEnum.TwoBodyRotating
            bodyInfo = getSelectedBodyInfo(handles);
            if(not(isempty(bodyInfo.childrenBodyInfo)))
                primaryBody = bodyInfo;
                secondaryBody = bodyInfo.childrenBodyInfo(1);
            else
                primaryBody = bodyInfo.getParBodyInfo();
                secondaryBody = bodyInfo;
            end

            originPt = TwoBodyRotatingFrameOriginEnum.Primary;

            newFrame = TwoBodyRotatingFrame(primaryBody, secondaryBody, originPt, celBodyData);

        case ReferenceFrameEnum.UserDefined
            numFrames = lvdData.geometry.refFrames.getNumRefFrames();
            if(numFrames >= 1)
                geometricFrame = AbstractGeometricRefFrame.empty(1,0);
                for(i=1:numFrames)
                    frame = lvdData.geometry.refFrames.getRefFrameAtInd(i);
                    if(frame.isVehDependent() == false)
                        geometricFrame = frame;
                        break;
                    end
                end

                if(not(isempty(geometricFrame)))
                    newFrame = UserDefinedGeometricFrame(geometricFrame, lvdData);
                else
                    bodyInfo = getSelectedBodyInfo(handles);
                    newFrame = bodyInfo.getBodyCenteredInertialFrame();

                    warndlg('There are no geometric frames available which are not dependent on vehicle properties.  A body-centered inertial frame will be selected instead.');
                end
            else
                bodyInfo = getSelectedBodyInfo(handles);
                newFrame = bodyInfo.getBodyCenteredInertialFrame();

                warndlg('There are no geometric frames available which are not dependent on vehicle properties.  A body-centered inertial frame will be selected instead.');
            end

        otherwise
            error('Unknown reference frame type: %s', string(refFrameEnum));
    end

    if(not(isempty(newFrame)) && newFrame.typeEnum ~= refFrameEnum)
        refFrameEnum = newFrame.typeEnum;
        handles.refFrameTypeCombo.Value = ReferenceFrameEnum.getIndForName(refFrameEnum.name);
    end

    setappdata(handles.lvd_editEvtTermCond,'frame', newFrame);
    handles.setFrameOptionsButton.TooltipString = sprintf('Current Frame: %s', newFrame.getNameStr());
    handles.refFrameNameLabel.String = sprintf('%s', newFrame.getNameStr());
    handles.refFrameNameLabel.TooltipString = sprintf('%s', newFrame.getNameStr());

function bodyInfo = getSelectedBodyInfo(handles)
    curFrame = getappdata(handles.lvd_editEvtTermCond,'frame');
    bodyInfo = curFrame.getOriginBody();


%-----------------------------------------------------------------------
% Job configuration created by cfg_util (rev $Rev: 4899 $)
%-----------------------------------------------------------------------
matlabbatch{1}.menu_cfg{1}.menu_entry{1}.conf_files.type = 'cfg_files';
matlabbatch{1}.menu_cfg{1}.menu_entry{1}.conf_files.name = 'Directory';
matlabbatch{1}.menu_cfg{1}.menu_entry{1}.conf_files.tag = 'dir';
matlabbatch{1}.menu_cfg{1}.menu_entry{1}.conf_files.filter = 'dir';
matlabbatch{1}.menu_cfg{1}.menu_entry{1}.conf_files.ufilter = '.*';
matlabbatch{1}.menu_cfg{1}.menu_entry{1}.conf_files.dir = '';
matlabbatch{1}.menu_cfg{1}.menu_entry{1}.conf_files.num = [1 1];
matlabbatch{1}.menu_cfg{1}.menu_entry{1}.conf_files.check = [];
matlabbatch{1}.menu_cfg{1}.menu_entry{1}.conf_files.help = {'New working directory.'};
matlabbatch{1}.menu_cfg{1}.menu_entry{1}.conf_files.def = [];
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.type = 'cfg_exbranch';
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.name = 'Change Directory';
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.tag = 'cfg_cd';
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.val{1}(1) = cfg_dep;
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.val{1}(1).tname = 'Val Item';
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.val{1}(1).tgt_spec = {};
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.val{1}(1).sname = 'Directory (cfg_files)';
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.val{1}(1).src_exbranch = substruct('.','val', '{}',{1}, '.','val', '{}',{1}, '.','val', '{}',{1});
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.val{1}(1).src_output = substruct('()',{1});
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.prog = @cfg_run_cd;
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.vout = [];
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.check = [];
matlabbatch{2}.menu_cfg{1}.menu_struct{1}.conf_exbranch.help = {'Change working directory.'};


function rts_retrieveSolarPanelsAndStore(~, ~,tcpipClient, vesselGUID, dblsTcpipClient)
%rts_retrieveSolarPanelsAndStore Summary of this function goes here
%   Detailed explanation goes here

    try
        data = get(dblsTcpipClient,'UserData');
        numDbls = data{1}(2);
        if(~isempty(numDbls))
            rts_retrieveDataAndStore(tcpipClient, numDbls, 'd');
        end
    catch ME
%         disp(ME.message);
%         for k=1:length(ME.stack)
%             ME.stack(k)
%         end
    end
end


function xx = to_gpu(x)
    xx = gpuArray(single(x));
end


% OtTablePost Post changes to the database table.
%
% Usage:
%    OtTablePost(htable)

% OtMatlab: Matlab interface to the Omnitrans transport planning software

% Copyright (c) 2008, VORtech Computing
% Copyright (c) 2010, Omnitrans International

% All rights reserved.

% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are
% met:

%     * Redistributions of source code must retain the above copyright
%       notice, this list of conditions and the following disclaimer.
%     * Redistributions in binary form must reproduce the above copyright
%       notice, this list of conditions and the following disclaimer in
%       the documentation and/or other materials provided with the distribution
%     * Neither the name of VORtech Computing and Omnitrans International nor the names
%       of its contributors may be used to endorse or promote products derived
%       from this software without specific prior written permission.

% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
% POSSIBILITY OF SUCH DAMAGE.

% 2006-04-11 Created (Johan Meijdam, VORtech)

function iret = OtTablePost(htable)
   iret = Ot('table.post', htable);
end


function [ ret ] = setBlueOff( t_Kuka )
%% About:
% This function is used to set off the blue light of the KUKA iiwa 7 R 800.

%% Syntax:
% [ ret ] = setBlueOff( t_Kuka )

%% Arreguments:
% t_Kuka: is the TCP/IP connection

%% Return value:
% ret: a boolean variable
% true: if the message is treated successfully
% false: if an error has happened

% Copy right, Mohammad SAFEEA, 3rd of May 2017

theCommand='blueOff';
fprintf(t_Kuka, theCommand);
message=fgets(t_Kuka);
ret=checkAcknowledgment(message);
end


function result = getMotionObject()
objectname = findobj('name','Stepper Motor Simulator');
result =get(objectname,'UserData');

end


%% write_mff_history.m
%  Matlab File
%  author Colin Davey
%  date 4/15/2014
%  Copyright 2014 EGI. All rights reserved.
%
%  This function adds an item to the list of history items. It is intended
%  to be run after running code that either a) creates a new mff file based
%  on an existing one, or b) modifies an existing one. The history item can
%  be seen in Net Station through the File Info->History feature.
%
%  filePath ? The path to the .mff file.
%
%  entryStruct has the following elements:
%
%  name - string that corresponds to the name of the tool specification in
%  NetStation. For example, if you create a segmentation specification for
%  a VTD experiment, and call it "VTD Seg", then the string "VTD Seg" would
%  go here.
%
%  method - The name of the tool (not the tool specification.) In the above
%  example, the string "Segmentation" would go here.
%
%  version - The version of the tool, eg "1.0".
%
%  beginTime - The time the tool started running. The following matlab
%  command creates a time in the proper format:
%    sprintf('%d-%02d-%02dT%02d:%02d:%02.5f',clock);
%
%  endTime - The time the tool finished running. See beginTime, above, for
%  the matlab command that creates a time in the proper format.
%
% sourceFileList - The list of files that were processed by the tool to
% generate the resulting file. For example, a tool that filters a single
% file to create a filtered version of the data would have just one item in
% this list. A tool that creates a grand average by averaging multiple
% single-subject files would have multiple items in this list.
%
% settingList - A cell array of zero or more strings that express the
% settings/parameters for the tool. These are optional, and are intended to
% be read by humans, not machines.
%
% resultList - A cell array of zero or more strings that express the
% results of the tool. These are optional, and are intended to be read by
% humans, not machines.
%%
function write_mff_history(filePath, entryStruct)
try
    mff_valid(filePath);
catch theException
    throw(theException);
end

%% 1) Read in history resource.
histObj = mff_getObject(com.egi.services.mff.api.MFFResourceType.kMFF_RT_History, 'history.xml', filePath);

%% 2) Get the list of current entires (it might be null, in which case
% create a new one and set it).
if isempty(histObj)
    delegate = javaObject('com.egi.services.mff.api.LocalMFFFactoryDelegate');
    factory = javaObject('com.egi.services.mff.api.MFFFactory', delegate);
    resourceVal = com.egi.services.mff.api.MFFResourceType.kMFF_RT_History;
    resourceType = javaObject('com.egi.services.mff.api.MFFResourceType', resourceVal);
    factory.createResourceAtURI([filePath filesep 'history.xml'], resourceType);
    histObj = factory.openResourceAtURI([filePath filesep 'history.xml'], resourceType);

    entryList = javaObject('java.util.ArrayList');
    histObj.setEntries(entryList);
else
    entryList = histObj.getEntries;
    if isempty(entryList) % Is this feasible? ie history exists, but entryList is empty?
        entryList = javaObject('java.util.ArrayList');
        histObj.setEntries(entryList);
    end
end

%% 3) Add an Entry object to the list.
entry = javaObject('com.egi.services.mff.api.Entry');
tool = javaObject('com.egi.services.mff.api.Tool');
tool.setName(entryStruct.name);
tool.setKind('Transformation');
tool.setMethod(entryStruct.method);
tool.setVersion(entryStruct.version);
tool.setBeginTime(entryStruct.beginTime);
tool.setEndTime(entryStruct.endTime);

sourceFileList = javaObject('java.util.ArrayList');
for p=1:size(entryStruct.sourceFileList,2)
    filePathObj = javaObject('com.egi.services.mff.api.FilePath');
    filePathObj.setFilePath(entryStruct.sourceFileList{p});
    sourceFileList.add(filePathObj);
    filePathObj = [];
end
java.lang.Runtime.getRuntime.freeMemory;
tool.setSourceFiles(sourceFileList);

settingList = javaObject('java.util.ArrayList');
for p=1:size(entryStruct.settingList,2)
    settingList.add(entryStruct.settingList{p});
end
tool.setSettings(settingList);

resultList = javaObject('java.util.ArrayList');
for p=1:size(entryStruct.resultList,2)
    resultList.add(entryStruct.resultList{p});
end
tool.setResults(resultList);

entry.setEntry(tool);
entry.setType('tool');

entryList.add(entry);

%% 4) Save the history resource in the standard way all resources are saved.
histObj.setEntries(entryList);
histObj.saveResource;