function ohf = least_squares_parameters_cb(action,GUI,hf);
%LEAST_SQUARES_PARAMETERS_CB - least_squares GUI setup and execution
% function ohf = least_squares_parameters_cb(action,GUI,hf);
% function hf = least_squares_parameters_cb; % Build and return handle to figure
% function least_squares_parameters_cb(action); % switchyard
% function least_squares_parameters_cb(StudySubject,GUI,hf); % initialize
% Called with no action, it will build the GUI window using least_squares_parameters.fig
% action may be either a string or a StudySubject structure
% StudySubject must be a proper find_brainstorm_structure
% In the initialization, GUI must contain the fields
%  GUI.Segment, vector of column indices to process in the data matrix
%  GUI.Rank, the rank of the signal subspace to use
%  GUI.DataName, the referentially qualified filename of the data set
%  GUI.ChannelFlag, +1 for each channel to be used

%<autobegin> ---------------------- 26-May-2004 11:30:49 -----------------------
% --------- Automatically Generated Comments Block Using AUTO_COMMENTS ---------
%
% CATEGORY: Inverse Modeling
%
% Alphabetical list of external functions (non-Matlab):
%   toolbox\get_user_directory.m
%   toolbox\least_squares_fit.m
%   toolbox\least_squares_parameters_cb.m  NOTE: Routine calls itself explicitly
%
% Figure Files opened by this function:
%   'least_squares_parameters.fig'
%
%   Format of strings below: Type:Style:Tag, "String", CallBack Type and Call
%   <automatic> callback is <Tag>_Callback by Matlab default
%
% Callbacks by figure least_squares_parameters.fig
%   figure::figure_LeastSquaresGui "" uses KeyPressFcn for dokeypress(gcbf)
%   figure::figure_LeastSquaresGui "" uses ResizeFcn for doresize(gcbf)
%   uicontrol:edit:edit_CurrentDipoleStereo "1" uses Callback for
%     least_squares_parameters_cb('set number')
%   uicontrol:edit:edit_MagneticDipole "1" uses Callback for
%     least_squares_parameters_cb('set number')
%   uicontrol:edit:edit_MagneticDipoleStereo "1" uses Callback for
%     least_squares_parameters_cb('set number')
%   uicontrol:edit:edit_Multipole "1" uses Callback for least_squares_parameters_cb('set number')
%   uicontrol:edit:edit_MultipoleStereo "1" uses Callback for
%     least_squares_parameters_cb('set number')
%   uicontrol:edit:EditCurrentDipole "1" uses Callback for least_squares_parameters_cb('set number')
%   uicontrol:popupmenu:popup_regularization "Regularization . . ." uses Callback for
%     least_squares_parameters_cb('set reg')
%   uicontrol:pushbutton:pushbutton_close "Close" uses Callback for delete(gcbf)
%   uicontrol:pushbutton:pushbutton_EditStartingPoints "Edit" uses Callback for
%     least_squares_parameters_cb('edit starting points');
%   uicontrol:pushbutton:pushbutton_Execute "Execute" uses Callback for
%     least_squares_parameters_cb('execute rap');
%   uicontrol:pushbutton:pushbutton_LoadStartingPoints "Load" uses Callback for
%     least_squares_parameters_cb('load starting points');
%   uicontrol:radiobutton:radio_CurrentDipole "Current Dipole" uses Callback for
%     least_squares_parameters_cb('set source')
%   uicontrol:radiobutton:radio_CurrentDipoleStereo "   Stereo Pair" uses Callback for
%     least_squares_parameters_cb('set source')
%   uicontrol:radiobutton:radio_MagneticDipole "Magnetic Dipole" uses Callback for
%     least_squares_parameters_cb('set source')
%   uicontrol:radiobutton:radio_MagneticDipoleStereo "   Stereo Pair" uses Callback for
%     least_squares_parameters_cb('set source')
%   uicontrol:radiobutton:radio_Moving "Moving" uses Callback for
%     least_squares_parameters_cb('set spatiotemporal')
%   uicontrol:radiobutton:radio_Multipole "1st-order Multipole" uses Callback for
%     least_squares_parameters_cb('set source')
%   uicontrol:radiobutton:radio_MultipoleStereo "   Stereo Pair" uses Callback for
%     least_squares_parameters_cb('set source')
%   uicontrol:radiobutton:radio_OrientationFixed "Fixed" uses Callback for
%     least_squares_parameters_cb('set orientation')
%   uicontrol:radiobutton:radio_OrientationRotating "Rotating" uses Callback for
%     least_squares_parameters_cb('set orientation')
%   uicontrol:radiobutton:radio_OrientationSynchronous "Synchronous" uses Callback for
%     least_squares_parameters_cb('set orientation')
%   uicontrol:radiobutton:radio_Stationary "Stationary" uses Callback for
%     least_squares_parameters_cb('set spatiotemporal')
%
% At Check-in: $Author: Mosher $  $Revision: 13 $  $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:30:49 -----------------------

% ----------------------------- Script History ---------------------------------
% Author: John C. Mosher
% 19-May-2004 JCM Comments Cleaning
% ----------------------------- Script History ---------------------------------

linecolor = [.7 .7 .0]; % Line color for coordinates display

if(~exist('action')),
   open('least_squares_parameters.fig');
   ohf = gcf; %the new figure handle
   return   
end


if(isstruct(action)), % call is rap_parameters_cb(StudySubject,GUI)
   StudySubject = action;
   action = 'initialize';
else
   hf = gcbf; % the figure that called this
end

switch deblank(lower(action))
   
case 'initialize'
   % this action may be called by other windows, so consider gcf, gcbo
   %  do not recommend further recursive calls inside this case.
   Names = fieldnames(GUI); % what did the user provide
   temp = GUI; % will now overwrite
   GUI = struct('DataName',[],'Results',[],'Segment',[],'Order',[],'Rank',[],...
      'Corr',[],'ChannelFlag',[],'DisplayGraphics',[],'Tikhonov',[],'Column_norm',[]);
   for i = 1:length(Names),
      %map data in temp to data in GUI
      GUI = setfield(GUI,Names{i},getfield(temp,Names{i}));
   end
   % is there a slicker way to do this? JCM 2/17/00
   
   % so now I have the initial GUI parameters I need for RAP-MUSIC.
   % Map into the uicontrols
   
   ht = findobj(hf,'Tag','TextBrainStormStudy');
   set(ht,'String',StudySubject.Study);
   ht = findobj(hf,'Tag','TextBrainStormData');
   set(ht,'String',GUI.DataName);
   ht = findobj(hf,'Tag','TextBrainStormComment');
   set(ht,'String',sprintf('Rank: %.0f, From index %.0f to %.0f',...
      GUI.Rank,GUI.Segment(1),GUI.Segment(end)));
   
   % establish starting points
   GUI.StartingPoints = cell(1);
   GUI.StartingPoints = {[NaN NaN NaN]'}; % no starting points declared
   
   % make sure all edit windows are set to one
   TAGS = {'CurrentDipole','MagneticDipole','Multipole'};
   for i = 1:length(TAGS),
      ht = findobj(hf,'Tag',['Edit' TAGS{i}]);
      set(ht,'String','1'); % number of sources
      ht = findobj(hf,'Tag',['Edit' TAGS{i} 'Stereo']);
      set(ht,'String','1'); % number of sources
   end

   % store in the window user data
   set(hf,'UserData',struct('StudySubject',StudySubject,'GUI',GUI));
   
   % view the starting points
   % least_squares_parameters_cb('display starting points') % can't recursively call
   ht = findobj(hf,'Tag','ListBoxStartingPoints');
   set(ht,'String','  Random Start');
      
case 'set reg'
   i = get(gcbo,'Value');
   ht = findobj(hf,'Tag','EditReg'); % the edit field
   switch i
   case 1
      set(ht,'String',' ')
      str = get(gcbo,'String');
      set(gcbo,'String','Select Method');
      pause(1)
      set(gcbo,'String',str)
   case 2
      % truncated SVD
      set(ht,'String','100')
   case 3
      % energy truncation
      set(ht,'String','.98')
   case 4
      % Tikhonov Condition
      set(ht,'String','100')
   case 5
      % none, do nothing
      set(ht,'String',' ')
   end
   
case 'set number'
   % set the number of sources. Also set the radio button of
   %  whomever called it
   NumSources = str2num(get(gcbo,'String'));
   
   % want the existing list of starting points
   UD = get(hf,'UserData');
   GUI = UD.GUI;
   
   if(size(GUI.StartingPoints{1},2) < NumSources),
      GUI.StartingPoints{1}(:,(end+1):NumSources) = NaN; % set to NaN for random
   else
      GUI.StartingPoints{1} = GUI.StartingPoints{1}(:,1:NumSources); % trim to desired
   end
      
   UD = setfield(UD,'GUI',GUI); % replace the userfield data
   set(hf,'UserData',UD); % put it back
   
   % set the radio button of the edit field that called this
   % Possible Tag roots are prefixed by Edit:
   TAGS = {'MultipoleStereo','CurrentDipoleStereo','MagneticDipoleStereo',...
         'Multipole','CurrentDipole','MagneticDipole'};
   for i = 1:length(TAGS),
      ht = findobj(hf,'Tag',TAGS{i});
      set(ht,'Value',0);
   end
   TAG = get(gcbo,'Tag'); % the edit field that called us
   TAG = strrep(TAG,'Edit',''); % strip the edit prefix from it
   ht = findobj(hf,'TAG',TAG); % the corresponding radio button
   set(ht,'Value',1); % set the calling one on
   
   % now display the starting points
   least_squares_parameters_cb('display starting points');
   
case 'display starting points'
   
   UD = get(hf,'UserData');
   StartingPoints = UD.GUI.StartingPoints;
   
   str = cell(1,size(StartingPoints{1},2));
   for i = 1:size(StartingPoints{1},2), % cells
      if(isnan(StartingPoints{1}(1,i))),
         % a random point
         str{i} = '  Random Start';
      else
         str{i} = sprintf(' [ %6.1f %6.1f %6.1f ] mm',...
            StartingPoints{1}(:,i)*1000);
      end
   end
   str = [{' '} str]; %prepend with a blank line for aesthetics
   
   ht = findobj(hf,'Tag','ListBoxStartingPoints');
   set(ht,'String',str);
   
case 'load starting points'
   % load a set of starting points from a file, presumably a results file
   % All that really matters is that the file contain SourceLoc, a 
   %  cell array of three-dimensional locations
   User = get_user_directory; % the default locations of files
   cd(User.STUDIES); % set to the studies tree
   [Filename,Pathname]= uigetfile('*results*.mat',...
      'Select a File to Load in a Set of Starting Points'); 
   if(Filename == 0),
      % user selected nothing, do nothing
      return
   end
   
   UserFile = load(fullfile(Pathname,Filename));
   if(~isfield(UserFile,'SourceLoc')),
      errordlg('The file you selected does not have SourceLoc',...
         'Least Squares Load Error');
      return
   end
   UD = get(hf,'UserData');
   % extract matrix of starting points
   StartingPoints{1} =  [UserFile.SourceLoc{:}]; % map all starting points
   
   UD.GUI = setfield(UD.GUI,'StartingPoints',StartingPoints); 
   set(hf,'UserData',UD); % put it back
   
   % set all edit windows to this number
   TAGS = {'CurrentDipole','MagneticDipole','Multipole'};
   for i = 1:length(TAGS),
      ht = findobj(hf,'Tag',['Edit' TAGS{i}]);
      set(ht,'String',num2str(size(StartingPoints{1},2))); % number of sources
      ht = findobj(hf,'Tag',['Edit' TAGS{i} 'Stereo']);
      set(ht,'String',num2str(size(StartingPoints{1},2))); % number of sources
   end

   % now display the starting points
   least_squares_parameters_cb('display starting points');
   
case 'edit starting points'
   UD = get(hf,'UserData');
   StartingPoints = UD.GUI.StartingPoints;

   % edit the starting points to include non-random points
   dlgTitle = 'Starting Points';
   lineNo = 1;
   prompt = cell(1,size(StartingPoints{1},2));
   def = cell(1,size(StartingPoints{1},2));
   for i = 1:size(StartingPoints{1},2),
      prompt{i} = sprintf('Source %.0f (x y z triplet, (r)andom, or (d)elete)',i);
      if(isnan(StartingPoints{1}(1,i))),
         def{i} = 'random';
      else
         def{i} = sprintf('%.1f ',StartingPoints{1}(:,i)*1000);
      end
   end
   answer = inputdlg(prompt,dlgTitle,lineNo,def,...
      struct('Interpreter','none','Resize','off','WindowStyle','Modal'));
   
   if(isempty(answer))
      % user cancelled
      return
   end
   
   delete_ndx= []; % delete this starting point
   for i = 1:length(answer),
      switch deblank(lower(answer{i}(1)))
      case 'd' % remove this starting poitn
         delete_ndx = [delete_ndx i];
      case 'r' % random
         StartingPoints{1}(:,i) = [NaN NaN NaN]'; % flag into least squares program
      otherwise         
         StartingPoints{1}(:,i) = sscanf(answer{i},'%f')/1000;
      end
   end
   
   % delete the starting points the user didn't want
   StartingPoints{1}(:,delete_ndx) = [];
   
   % replace the userfield data
   UD.GUI = setfield(UD.GUI,'StartingPoints',StartingPoints); 
   set(hf,'UserData',UD); % put it back
      
   % set all edit windows to this number
   TAGS = {'CurrentDipole','MagneticDipole','Multipole'};
   for i = 1:length(TAGS),
      ht = findobj(hf,'Tag',['Edit' TAGS{i}]);
      set(ht,'String',num2str(size(StartingPoints{1},2))); % number of sources
      ht = findobj(hf,'Tag',['Edit' TAGS{i} 'Stereo']);
      set(ht,'String',num2str(size(StartingPoints{1},2))); % number of sources
   end

   % now display the starting points
   least_squares_parameters_cb('display starting points');
   
case 'set source'
   % for now, we only allow a single source type
   
   % the source checkbox tags
   TAGS = {'MultipoleStereo','CurrentDipoleStereo','MagneticDipoleStereo',...
         'Multipole','CurrentDipole','MagneticDipole'};
   
   for i = 1:length(TAGS),
      ht = findobj(hf,'Tag',TAGS{i});
      set(ht,'Value',0);
   end
   
   set(gcbo,'Value',1); % set the calling one on
   
   % set the number of sources correctly
   TAG = get(gcbo,'Tag'); % get the tag of the caller
   ht = findobj(hf,'Tag',['Edit' TAG]); % it's corresponding edit box
   UD = get(hf,'UserData'); % the present user data
   % set present length of starting points
   set(ht,'String',num2str(size(UD.GUI.StartingPoints{1},2)));

case 'set orientation'
   % either fixed or rotating, not both
   TAGS = {'OrientationRotating','OrientationFixed','OrientationSynchronous'};
   for i = 1:length(TAGS),
      ht = findobj(hf,'Tag',TAGS{i});
      set(ht,'Value',0); % clear all tags
   end
   
   set(gcbo,'Value',1); % set the calling one on

case 'set spatiotemporal'
   % either stationary or moving, not both
   TAGS = {'Stationary','Moving'};
   for i = 1:length(TAGS),
      ht = findobj(hf,'Tag',TAGS{i});
      set(ht,'Value',0); % clear all tags
   end
   
   set(gcbo,'Value',1); % set the calling one on

case 'execute rap'
   
   % collect up the stats
   UD = get(hf,'UserData');
   StudySubject = UD.StudySubject; %stored there
   GUI = UD.GUI;
   clear UD
   
   % now set the Orders to search by checking which flags are set
   % the source checkbox tags
   GUI.Order = []; % initialize
   GUI.Sync = [];
   TAGS = {'CurrentDipole','MagneticDipole','Multipole'};
   for i = 1:length(TAGS),
      ht = findobj(hf,'Tag',TAGS{i});
      if(get(ht,'Value')),
         GUI.Order(end+1) = i-2; % -1, 0, 1
         ht = findobj(hf,'Tag',['Edit' TAGS{i}]);
         GUI.Sync(end+1) = str2num(get(ht,'String')); % number of sources
      end
   end
   % now the stereo ones
   for i = 1:length(TAGS),
      ht = findobj(hf,'Tag',[TAGS{i} 'Stereo']);
      if(get(ht,'Value')),
         GUI.Order(end+1) = i-2; % -1, 0, 1
         ht = findobj(hf,'Tag',['Edit' TAGS{i} 'Stereo']);
         GUI.Sync(end+1) = str2num(get(ht,'String')); % number of sources
         GUI.Sync(end) = -GUI.Sync(end); %flag that sources are stereo
      end
   end
   
   if(isempty(GUI.Order)), % user didn't check anything
      msgbox('You must select a starting model order','Notice','modal');
      return
   end
   
   if(length(GUI.Order) > 1),
      msgbox('Sorry, unable yet to handle multiple source types.','Notice','modal');
      return
   end
      
   ht = findobj(hf,'Tag','PopupReg');
   hs = findobj(hf,'Tag','EditReg');
   i = get(ht,'Value');
   switch i
   case 1
      msgbox('You must select a regularization technique','Notice','modal');
      return
   case 2
      % truncated svd
      GUI.Condition = str2num(get(hs,'String'));
      GUI.Energy = [];
      GUI.Tikhonov = [];
   case 3
      % energy svd
      GUI.Condition = [];
      GUI.Energy = str2num(get(hs,'String'));
      GUI.Tikhonov = [];
   case 4
      % Tikhonov Condition normalization
      GUI.Condition = [];
      GUI.Energy = [];
      GUI.Tikhonov = str2num(get(hs,'String'));
   case 5
      % none
      GUI.Condition = [];
      GUI.Energy = [];
      GUI.Tikhonov = [];
   end
   
   hcn = findobj(hf,'Tag','CheckboxColumnNorm');
   GUI.Column_norm = get(hcn,'Value'); % 0 is no, 1 is yes
   
   % What is the orientation
   % either fixed or rotating, not both
   TAGS = {'OrientationRotating','OrientationFixed','OrientationSynchronous'};
   GUI.Orientation = [];
   for i = 1:length(TAGS),
      ht = findobj(hf,'Tag',TAGS{i});
      if(get(ht,'Value'));
         GUI.Orientation{end+1} = TAGS{i};
      end
   end
   if(length(GUI.Orientation) ~= 1),
      msgbox('Sorry, unable yet to handle multiple orientation models.',...
         'Notice','modal');
      return
   end
   
   % What is temporal model
   % either Stationary or Moving, not both
   TAGS = {'Stationary','Moving'};
   GUI.Temporal = [];
   for i = 1:length(TAGS),
      ht = findobj(hf,'Tag',TAGS{i});
      if(get(ht,'Value'));
         GUI.Temporal{end+1} = TAGS{i};
      end
   end
   if(length(GUI.Temporal) ~= 1),
      msgbox('Sorry, unable yet to handle multiple temporal models.',...
         'Notice','modal');
      return
   end
   
   % now hash together a results name
   [PATH,NAME,EXT,VER] = fileparts(GUI.DataName);
   c = clock;
   newname = fullfile(PATH,[NAME sprintf('_results_%02.0f%02.0f',c(4:5)) EXT VER]);
   i = 0;
   while(exist(newname,'file')),
      i = i+1; % subtract another minute
      c(5) = mod(c(5) - 1,60);
      newname = fullfile(PATH,[NAME sprintf('_results_%02.0f%02.0f',c(4),c(5)) EXT VER]);
   end
   GUI.Results = newname;
   
   more off % let the text flow freely
   
   %% CHEAT %% for displaying graphic
   GUI.DisplayGraphics = 1; % always display
   [PATH,NAME,EXT,VER] = fileparts(StudySubject.SubjectTess);
   
   TessRap = fullfile(PATH,[[NAME '_rap'] EXT VER]); % possible tesselation file
   if(exist(TessRap,'file')), % there is a reduce one for rap
      StudySubject.SubjectTess = TessRap; % map it in
   end
   
   % now adjust for March 2000 version
   temp = GUI.Order;
   temp2 = [GUI.StartingPoints{:}]; % cat all starting points
   
   GUI.Order = cell(1,size(temp2,2)); % one cell per starting poit
   GUI.StartingPoints = GUI.Order; % same size
   for i = 1:length(GUI.StartingPoints),
      GUI.StartingPoints{i} = temp2(:,i); % single starting point
      GUI.Order{i} = temp; % model order
   end
   

   least_squares_fit(StudySubject,GUI);
   
otherwise
   
   errordlg(sprintf('Unknown action: %s',action),'LEAST SQUARES');
   
end % case switch of actions

if(nargout),
   ohf = hf;
end

return
