function varargout = database_manager(varargin)
%DATABASE_MANAGER - GUI to edit the User Databases and select one
% function varargout = database_manager(varargin)
%    USER = DATABASE_MANAGER launch modal GUI
%    DATABASE_MANAGER('callback_name', ...) invoke the named callback.
%
% Modal window, 
%  "Done" button returns selected database as Users structure, updates
%  the application data BrainStormDataBase in the TASKBAR, and saves the
%  databases in the Matlab prefs. Since the user may have switched databases,
%  the BrainStorm UserCurrentData is blanked.
% Returns the structure with fields:
%  Comment, string commenting on the location of the files
%  STUDIES, string giving the root location of all studies
%  SUBJECTS, string giving the root for subjects.
%  CurrentData with fields:
%      StudyFile: ''
%    SubjectFile: ''
%
% "Cancel" does nothing.

%<autobegin> ---------------------- 26-May-2004 11:29:56 -----------------------
% --------- Automatically Generated Comments Block Using AUTO_COMMENTS ---------
%
% CATEGORY: GUI and Related
%
% Alphabetical list of external functions (non-Matlab):
%   toolbox\browse_study_folder.m
%   toolbox\bst_color_scheme.m
%   toolbox\bst_layout.m
%   toolbox\bst_message_window.m
%   toolbox\select_folder.m
%
% Subfunctions in this file, in order of occurrence in file:
%   initialize_gui(handles);
%   varargout = pushbutton_done_Callback(h, eventdata, handles, varargin)
%   varargout = pushbutton_cancel_Callback(h, eventdata, handles, varargin)
%   varargout = listbox_database_Callback(h, eventdata, handles, varargin)
%   varargout = edit_SUBJECTS_Callback(h, eventdata, handles, varargin)
%   varargout = edit_STUDIES_Callback(h, eventdata, handles, varargin)
%   varargout = edit_databasename_Callback(h, eventdata, handles, varargin)
%   varargout = pushbutton_SUBJECTS_Callback(h, eventdata, handles, varargin)
%   varargout = pushbutton_STUDIES_Callback(h, eventdata, handles, varargin)
%   varargout = pushbutton_update_Callback(h, eventdata, handles, varargin)
%   varargout = pushbutton_add_Callback(h, eventdata, handles, varargin)
%   varargout = pushbutton_remove_Callback(h, eventdata, handles, varargin)
%   varargout = pushbutton_update_ButtonDownFcn(h, eventdata, handles, varargin)
%   varargout = pushbutton_add_ButtonDownFcn(h, eventdata, handles, varargin)
%   varargout = pushbutton_remove_ButtonDownFcn(h, eventdata, handles, varargin)
%   varargout = pushbutton_help_Callback(h, eventdata, handles, varargin)
%
% Group : Preference data and their calls in this file:
%   'BrainStorm' : 'CurrentData'
%   'BrainStorm' : 'UserDataBase'
%   'BrainStorm' : 'iUserDataBase'
%   
%   setpref('BrainStorm','CurrentData',struct('StudyFile','','SubjectFile',''));
%   setpref('BrainStorm','UserDataBase',UserDB)
%   setpref('BrainStorm','UserDataBase',Users);
%   setpref('BrainStorm','iUserDataBase',1);
%   setpref('BrainStorm','iUserDataBase',Val);
%   
%   CurrentData = getpref('BrainStorm','CurrentData');
%   UserDB = getpref('BrainStorm','UserDataBase');
%   Val = getpref('BrainStorm','iUserDataBase');
%
% Application data and their calls in this file:
%   'BrainStormDataBase'
%   'TileType'
%   'UserDB'
%   
%   setappdata(TASKBAR,'BrainStormDataBase',CurrentUser);
%   setappdata(fig,'TileType','T')
%   setappdata(fig,'UserDB',UserDB);
%   
%   TASKBAR = getappdata(0,'BrainStormTaskbar');
%   UserDB = getappdata(fig,'UserDB');
%   UserDB = getappdata(handles.figure_datamanager,'UserDB');
%
% Figure Files opened by this function:
%   mfilename
%
%   Format of strings below: Type:Style:Tag, "String", CallBack Type and Call
%   <automatic> callback is <Tag>_Callback by Matlab default
%
% Callbacks by figure database_manager.fig
%   uicontrol:edit:edit_databasename "Edit Text" uses Callback for <automatic>
%   uicontrol:edit:edit_STUDIES "Edit Text" uses Callback for <automatic>
%   uicontrol:edit:edit_SUBJECTS "Edit Text" uses Callback for <automatic>
%   uicontrol:listbox:listbox_database "Listbox" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_add "Add" uses ButtonDownFcn for <automatic>
%   uicontrol:pushbutton:pushbutton_add "Add" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_cancel "Cancel" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_done "Save" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_help "Help" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_remove "Remove" uses ButtonDownFcn for <automatic>
%   uicontrol:pushbutton:pushbutton_remove "Remove" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_STUDIES "Studies" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_SUBJECTS "Subjects" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_update "Update" uses ButtonDownFcn for <automatic>
%   uicontrol:pushbutton:pushbutton_update "Update" uses Callback for <automatic>
%
% At Check-in: $Author: Mosher $  $Revision: 19 $  $Date: 5/26/04 9:59a $
%
% This software is part of BrainStorm Toolbox Version 2.0 (Alpha) 24-May-2004
% 
% Principal Investigators and Developers:
% ** Richard M. Leahy, PhD, Signal & Image Processing Institute,
%    University of Southern California, Los Angeles, CA
% ** John C. Mosher, PhD, Biophysics Group,
%    Los Alamos National Laboratory, Los Alamos, NM
% ** Sylvain Baillet, PhD, Cognitive Neuroscience & Brain Imaging Laboratory,
%    CNRS, Hopital de la Salpetriere, Paris, France
% 
% See BrainStorm website at http://neuroimage.usc.edu for further information.
% 
% Copyright (c) 2004 BrainStorm by the University of Southern California
% This software distributed  under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPL
% 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.
%<autoend> ------------------------ 26-May-2004 11:29:56 -----------------------

% /---Script Author--------------------------------------\
% | *** John C. Mosher, Ph.D.                            |
% |    Design Technology Group                           |
% |    Los Alamos National Laboratory                    |
% |    Los Alamos, New Mexico, USA                       |
% |                                                      |
% | *** Sylvain Baillet, Ph.D.                           |
% | Cognitive Neuroscience & Brain Imaging Laboratory    |
% | CNRS UPR640 - LENA                                   | 
% | Hopital de la Salpetriere, Paris, France             |
% | sylvain.baillet@chups.jussieu.fr                     |
% \------------------------------------------------------/
%
% Date of creation: January 2001, as function initialize_users
% Date of modification: August 2001                  
%---------------------------------------------------------------------------------------------------------------------------
% 25 Oct 2000 JCM, problems with saving the correct paths in the users.mat
%  Changed the overall style to rely on get_user_directory, which loads the users.mat file in the
%  custom folder. UserData in this window is no longer used. Sorted the folder lists alphabetically.
%  users.mat is saved with the first entry equal to the selected database files.
%
% 17 Aug 2001 SB, revamped version of the GUI + use of select_folder 
%   to select either the STUDIES to SUBJECTS folders
% 23-May-2002 JCM made bst_selectfolder become select_folder, which now uses 
%  getappdata to get folder.
% 24-May-2002 JCM select_folder is now modal and returns directly the folder
%
% 24-May-2002 
% Completely redesigned as database_manager, using feval switchyard and
%  setpref, getpref functions, in a modal window.
%
% JCM 24-May-2002 : initial build, trying to simplify our interactions
%                    with the database using the getprefs
% JCM 28-May-2002 : Added handling for CurrentData
% JCM 11-Jun-2002 : On Save, the Comments are sorted alphabetically for convenience
% JCM 2-Jul-2002  : Bug testing with UMinn. Order of structure elements is crucial, had
%                   to fix the default database, which interchanged the order of SUBJECTS
%                   and STUDIES. Had to account for case of non-existant directories
% SB  03-Jun-2003 : Updates GUI layout using tiling.
% JCM 18-Aug-2003 : Added FILELIST to newly defined structures
% ---------------------------------------------------------------------------------


% Last Modified by GUIDE v2.0 24-May-2002 22:39:50

if nargin == 0  % LAUNCH GUI
    
    fig = openfig(mfilename,'reuse');
    
    % Generate a structure of handles to pass to callbacks, and store it. 
    handles = guihandles(fig);
    guidata(fig, handles);
    
    % customization
    bst_color_scheme(fig);
    set(handles.listbox_database,'fontname','default'); % looks better
    
    setappdata(fig,'TileType','T')
    bst_layout('align',fig,2,1,1);
    
    set(fig,'visible','on'); % now make visible
    
    initialize_gui(handles); % load up the GUIs
    
    % Wait for callbacks to run and window to be dismissed:
    uiwait(fig);
    
    if(ishandle(fig)),
        % figure still exists, user did not cancel
        % get his selection from the listbox
        
        UserDB = getappdata(fig,'UserDB');
        Val = get(handles.listbox_database,'Val');
        
        CurrentUser = UserDB(Val);
        
        % DONE button will have reset the current data
        CurrentData = getpref('BrainStorm','CurrentData');
        
        % Enhance the User structure with this CurrentData and save to the
        %  taskbar
        CurrentUser = setfield(CurrentUser,'CurrentData',CurrentData);
        
        % update the TASKBAR data with the new Current User
        
        TASKBAR = getappdata(0,'BrainStormTaskbar');
        setappdata(TASKBAR,'BrainStormDataBase',CurrentUser);
        
        if nargout > 0
            varargout{1} = CurrentUser; % return the selected folder
        end
        
        close(fig); % now close it
        
    else
        
        % user cancelled, figure is gone
        varargout{1} = []; % return empty
        
    end
    
elseif ischar(varargin{1}) % INVOKE NAMED SUBFUNCTION OR CALLBACK
    
    try
        if (nargout)
            [varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard
        else
            feval(varargin{:}); % FEVAL switchyard
        end
    catch
        disp(lasterr);
    end
    
end


% ---------------------- local functions -----------------------------
% ------------------- LOAD THE GUI -----------------------------------
function initialize_gui(handles);
% load up the GUI's application data

fig = handles.figure_datamanager;

% UserDB is a structured array, with fields Comment, SUBJECTS, and STUDIES
%  and FILELIST.
% These items are stored using the Mathwork's setpref utility, which is 
%  a system dependent means of storing data

% since this is a change from the Custom users.mat and bst_prev_session,
%  we'll put some effort into initializing from the old ways.

% deprecated by JCM 8-sep-2003. Data_manager already has checked for this
if(0),
   if(~ispref('BrainStorm','UserDataBase')), % probably a new user
      % is there a users.mat in the path
      UserFilename = which('users.mat');
      if(isempty(UserFilename)),
         % setup defaults
         
         BST_ROOT = fileparts(which('startup.m')); % user's brainstorm directory
         Users(1) = struct('Comment','Default Database','SUBJECTS',BST_ROOT,...
            'STUDIES',BST_ROOT);
      else
         % there is a users.mat, let's use that to initialize
         Users = load(UserFilename);
         Users = Users.Users; % remap field to variable
      end
      setpref('BrainStorm','UserDataBase',Users); % initialize  
   end

end % deprecated code


UserDB = getpref('BrainStorm','UserDataBase'); % get the current database


if(~ispref('BrainStorm','iUserDataBase')), % probably a new user
    % CBB, use the bst_prev_session, but simpler is to set to 1
    setpref('BrainStorm','iUserDataBase',1); % initialize to first one
end

Val = getpref('BrainStorm','iUserDataBase'); % get the current user
set(handles.listbox_database,'Val',Val); % what line are we on?

setappdata(fig,'UserDB',UserDB); % store in the GUI app

listbox_database_Callback(handles.listbox_database,[],handles);




% ----------------------- callbacks ----------------------------------

% --------------------------------------------------------------------
function varargout = pushbutton_done_Callback(h, eventdata, handles, varargin)

% window is modal, we're done now, save the changes permanently
fig = handles.figure_datamanager;

if(strcmp('on',get(handles.pushbutton_update,'enable'))),
    % User has changed data, assume that he wants to update before saving
    pushbutton_update_Callback(handles.pushbutton_update,[],handles);
end

UserDB = getappdata(fig,'UserDB');
Val = get(handles.listbox_database,'Val');

% sort alphabetically for human convenience
[ignore,isort] = sort({UserDB.Comment});
UserDB = UserDB(isort);
Val = find(isort == Val); % the new location

setpref('BrainStorm','UserDataBase',UserDB)
setpref('BrainStorm','iUserDataBase',Val);

% now clear his current data, since it's a new database

setpref('BrainStorm','CurrentData',struct('StudyFile','','SubjectFile',''));

% release the figure
uiresume(fig);




% --------------------------------------------------------------------
function varargout = pushbutton_cancel_Callback(h, eventdata, handles, varargin)
% user does not want to keep any of his changes

% release the uiwait by closing the figure, with no saves
close(handles.figure_datamanager); 




% --------------------------------------------------------------------
function varargout = listbox_database_Callback(h, eventdata, handles, varargin)

UserDB = getappdata(handles.figure_datamanager,'UserDB');
Val = get(handles.listbox_database,'Val'); % what line are we on?

set(handles.listbox_database,'string',{UserDB.Comment},'Val',Val);

set(handles.edit_databasename,'string',UserDB(Val).Comment);
set(handles.edit_STUDIES,'string',UserDB(Val).STUDIES);
set(handles.edit_SUBJECTS,'string',UserDB(Val).SUBJECTS);

% we have reloaded valid parameters, turn the update back off
set(handles.pushbutton_update,'enable','off')
set(handles.pushbutton_add,'string','Copy');



% --------------------------------------------------------------------
function varargout = edit_SUBJECTS_Callback(h, eventdata, handles, varargin)
% inactive, use the pushbutton instead




% --------------------------------------------------------------------
function varargout = edit_STUDIES_Callback(h, eventdata, handles, varargin)
% inactive, use the pushbutton instead



% --------------------------------------------------------------------
function varargout = edit_databasename_Callback(h, eventdata, handles, varargin)

% user has changed the field, activate the update button
set(handles.pushbutton_update,'enable','on');
set(handles.pushbutton_add,'string','Add');




% --------------------------------------------------------------------
function varargout = pushbutton_SUBJECTS_Callback(h, eventdata, handles, varargin)
% browse for a new folder
fig = handles.figure_datamanager;
UserDB = getappdata(fig,'UserDB');
Val = get(handles.listbox_database,'Val'); % what line are we on?

if(exist(UserDB(Val).SUBJECTS,'dir')),
    % folder listed no longer exists, just stay where we are, otherwise
    cd(UserDB(Val).SUBJECTS); % go there
end 

Folder = select_folder; % begin from original location
if(~isempty(Folder)),
    set(handles.edit_SUBJECTS,'String',Folder);
    set(handles.pushbutton_update,'enable','on');
    set(handles.pushbutton_add,'string','Add');
    % if user doesn't press 'update', change won't be stick
end
% otherwise, do nothing





% --------------------------------------------------------------------
function varargout = pushbutton_STUDIES_Callback(h, eventdata, handles, varargin)
% browse for a new folder

fig = handles.figure_datamanager;
UserDB = getappdata(fig,'UserDB');
Val = get(handles.listbox_database,'Val'); % what line are we on?

if(exist(UserDB(Val).STUDIES,'dir'))
    cd(UserDB(Val).STUDIES); % go there, only if it exists, otherwise stay put
end

Folder = select_folder; % begin from original location
if(~isempty(Folder)),
    set(handles.edit_STUDIES,'String',Folder);
    set(handles.pushbutton_update,'enable','on');
    set(handles.pushbutton_add,'string','Add');
    
    % if user doesn't press 'update', change won't be stick
end
% otherwise, do nothing




% --------------------------------------------------------------------
function varargout = pushbutton_update_Callback(h, eventdata, handles, varargin)
% replace the parameters of the current database
% JCM, 18 August 2003 added filelist for new structure
fig = handles.figure_datamanager;
UserDB = getappdata(fig,'UserDB');
Val = get(handles.listbox_database,'Val'); % where are we in the list

% get the current parameters
Comment = get(handles.edit_databasename,'string');
STUDIES = get(handles.edit_STUDIES,'string');
SUBJECTS = get(handles.edit_SUBJECTS,'string');
FILELIST = browse_study_folder(STUDIES); % Update file list in current study folder


UserDB(Val) = struct('Comment',Comment,'STUDIES',STUDIES,'SUBJECTS',SUBJECTS,'FILELIST',FILELIST);

setappdata(fig,'UserDB',UserDB);

listbox_database_Callback(handles.listbox_database,[],handles);





% --------------------------------------------------------------------
function varargout = pushbutton_add_Callback(h, eventdata, handles, varargin)
% add the existing parameters as a new database
% JCM, 18 August 2003 added filelist for new structure

fig = handles.figure_datamanager;
UserDB = getappdata(fig,'UserDB');

% get the current parameters
Comment = get(handles.edit_databasename,'string');
STUDIES = get(handles.edit_STUDIES,'string');
SUBJECTS = get(handles.edit_SUBJECTS,'string');
FILELIST = browse_study_folder(STUDIES); % Update file list in current study folder

UserDB(end+1) = struct('Comment',Comment,'STUDIES',STUDIES,'SUBJECTS',SUBJECTS,'FILELIST',FILELIST);

setappdata(fig,'UserDB',UserDB);

listbox_database_Callback(handles.listbox_database,[],handles);





% --------------------------------------------------------------------
function varargout = pushbutton_remove_Callback(h, eventdata, handles, varargin)
% remove the existing database from the list

fig = handles.figure_datamanager;
UserDB = getappdata(fig,'UserDB');

Val = get(handles.listbox_database,'Val');

UserDB(Val) = []; % remove

if(~length(UserDB)), % deleted all, can't have
    BST_ROOT = fileparts(which('startup.m')); % user's brainstorm directory
    UserDB = struct('Comment','Default Database',...
        'STUDIES',BST_ROOT,'SUBJECTS',BST_ROOT);
end

if(Val > length(UserDB)), % exceeded length by deleting last one
    Val = length(UserDB);
    set(handles.listbox_database,'Val',Val);
end

setappdata(fig,'UserDB',UserDB);

listbox_database_Callback(handles.listbox_database,[],handles);



% --------------------------------------------------------------------
function varargout = pushbutton_update_ButtonDownFcn(h, eventdata, handles, varargin)
% help for update

par1 = ['This button activates when you alter the parameters of an existing ',...
        'database entry. If you Update, only the local copy is updated. To permanently ',...
        'save, you must also press the Save button when exiting.'];

bst_message_window('wrap',{'','Pushbutton Update Help',par1});





% --------------------------------------------------------------------
function varargout = pushbutton_add_ButtonDownFcn(h, eventdata, handles, varargin)

par1 = ['This button toggles between Copy and Add, depending on the ',...
        'status of the Update button. The parameters in the window are used ',...
        'to create a new database entry. To permanently save the new database, ',...
        'you must press the Save button to exit.'];

bst_message_window('wrap',{'','Pushbutton Add/Copy Help',par1});





% --------------------------------------------------------------------
function varargout = pushbutton_remove_ButtonDownFcn(h, eventdata, handles, varargin)
par1 = ['This button removes the highlighted database from the list. To ',...
        'permanently delete, you must press the Save button when exiting. If ',...
        'you Cancel, the permanent database remains unaltered.'];

bst_message_window('wrap',{'','Pushbutton Remove Help',par1});





% --------------------------------------------------------------------
function varargout = pushbutton_help_Callback(h, eventdata, handles, varargin)

par1 = ['Update, Add, or Remove Databases from the list, then Save. If you Cancel ',...
        'all changes are discarded. Right click on the buttons for more help.',...
        ''];

bst_message_window('wrap',{'','General Database Manager Help',par1});
