function varargout = results_time_series(varargin)
%RESULTS_TIME_SERIES - Application M-file for results_time_series.fig
% function varargout = results_time_series(varargin)
%    FIG = RESULTS_TIME_SERIES launch results_time_series GUI.
%    RESULTS_TIME_SERIES('callback_name', ...) invoke the named callback.

%<autobegin> ---------------------- 26-May-2004 11:34:15 -----------------------
% --------- Automatically Generated Comments Block Using AUTO_COMMENTS ---------
%
% CATEGORY: Visualization
%
% Alphabetical list of external functions (non-Matlab):
%   toolbox\bst_color_scheme.m
%   toolbox\bst_layout.m
%   toolbox\bst_message_window.m
%   toolbox\colnorm.m
%   toolbox\dataplot_cb.m
%   toolbox\fronorm.m
%   toolbox\mri_read_tool.m
%   toolbox\results_visualization.m
%
% Subfunctions in this file, in order of occurrence in file:
%   varargout = update(fig,Data,Results);
%   varargout = update_listbox(h,eventdata,handles);
%   plot_time_series(h,eventdata,handles);
%   varargout = listbox_sourceparam_Callback(h, eventdata, handles, varargin)
%   varargout = pushbutton_results_spatial_Callback(h, eventdata, handles, varargin)
%   varargout = pushbutton_help_Callback(h, eventdata, handles, varargin)
%   varargout = pushbutton_quit_Callback(h, eventdata, handles, varargin)
%   varargout = pushbutton_print_Callback(h, eventdata, handles, varargin)
%   varargout = checkbox_scale_ButtonDownFcn(h, eventdata, handles, varargin)
%   varargout = checkbox_scale_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_flip_orientation_Callback(h, eventdata, handles, varargin)
%
% Application data and their calls in this file:
%   'Data'
%   'ListSourceNumber'
%   'Results'
%   'SourceNumber'
%   'TileType'
%   'UnscaledTime'
%   'htime_series'
%   'visfig'
%   
%   setappdata(fig,'Data',Data);
%   setappdata(fig,'ListSourceNumber',ListSourceNumber);
%   setappdata(fig,'Results',Results);
%   setappdata(fig,'TileType','T');
%   setappdata(fig,'UnscaledTime',UnscaledTime);
%   setappdata(fig,'htime_series',htime_series);
%   setappdata(fig,'visfig',visfig);
%   setappdata(item1,'SourceNumber',i);
%   
%   Data = getappdata(fig,'Data');
%   ListSourceNumber = getappdata(fig,'ListSourceNumber');
%   Results = getappdata(fig,'Results');
%   SourceNumber = getappdata(h,'SourceNumber');
%   UnscaledTime = getappdata(fig,'UnscaledTime');
%   htime_series = getappdata(fig,'htime_series');
%   visfig = getappdata(fig,'visfig');
%
% 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 results_time_series.fig
%   uicontextmenu::uicontext_flip_orientation "" uses Callback for <automatic>
%   uicontrol:checkbox:checkbox_scale "Scale" uses ButtonDownFcn for <automatic>
%   uicontrol:checkbox:checkbox_scale "Scale" uses Callback for <automatic>
%   uicontrol:listbox:listbox_sourceparam "Source Parameters" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_help "Help" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_print "Print Menu ..." uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_quit "Quit" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_results_spatial "Spatial Display" uses Callback for <automatic>
%   uimenu::uimenu_flip_orientation "" uses Callback for <automatic>
%
% At Check-in: $Author: Mosher $  $Revision: 17 $  $Date: 5/26/04 10:02a $
%
% 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:34:15 -----------------------


% Last Modified by GUIDE v2.0 16-May-2002 08:35:34

% ----------------------------- Script History ---------------------------------
% JCM May 2002 initial build from results_update and results_update_gui,
%  the original BST 2000 versions
% JCM 31-Oct-2002 commenting, moving results up higher on screen
% SB  11-Jul-2003 linked to BST genneral Viewer
% 19-May-2004 JCM Comments Cleaning
% ----------------------------- Script History ---------------------------------


if nargin == 0  % LAUNCH GUI

	fig = openfig(mfilename,'new');

	% Generate a structure of handles to pass to callbacks, and store it. 
	handles = guihandles(fig);
	guidata(fig, handles);

	if nargout > 0
		varargout{1} = fig;
	end

   % customizations
   bst_color_scheme(fig);
   % don't really need default width display:
   set(handles.listbox_sourceparam,'fontname','default');
   % movegui(fig,[10 110]); % get it up above the Message Window as best possible
   % on a 1024 x 760 window
   setappdata(fig,'TileType','T');
   bst_layout('align',fig,2,1,2);
   set(fig,'visible','on');
   drawnow
   
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 -------------------------------

% ---------------- UPDATE THE GUI WITH NEW RESULTS -----------------
function varargout = update(fig,Data,Results);
% Outside program call to reload results into the GUI,
%  called as results_time_series('update',fig,Data,Results);
%  where fig = results_time_series; was the original creation
%
% Update of display the source parameters and residuals while RAP-MUSIC or LS is running.
% Must have the following fields in the BrainStorm structures Data and Results:
% Data: Structure containing information of the data
% Data.F: Spatio-temporal matrix of the original data
% Data.Time: Vector containing the time instants within the current time window of analysis for source localization    
% Results: Results structure containing the source parameters
% Results.IndepTopo
% Results.TimeSeries
% Results.Time
% Results.SourceOrder
% Results.Comment;
% Results.Subject.Name;
% Results.Study.Name;
% Results.SourceCorrelation
% Results.SourceLoc

% Please refer to the BrainStorm ParameterDescription file for details regarding the structure of arguments passed to this function

% ----------------------------- Script History ---------------------------------
% Sylvain Baillet, Ph.D.
% John C. Mosher, Ph.D.
% 2/22/00 JCM altering minor window features
% 2/23/00 JCM adding time series display as well
% JCM 3/20/00 added orientation string, made sure was compatible with least-squares
% JCM 3/20/00 Each run now gets its own update window. Makes for easier comparison between
%  solutions. Tag is based on output filename
% JCM 3/21/00 Switchable phrase between "correlation" and "variance explained", dependent on
%  Results.Function. Also set listbox to black text on white background in the program code,
%  so that hardcopy looks better.
% May 2002 major rewrite for MMII, see notes at beginning of this file
% 19-May-2004 JCM Comments Cleaning
% ----------------------------- Script History ---------------------------------

% filename being displayed

figure(fig); % bring to front
handles = guidata(fig); % get the handles for this gui

set(gcf,'Name',sprintf('Results %s %s %s',...
   Results.Subject.Name, Results.Study.Name, Results.GUI.Results));

% Now Results.IndepTopo is the fixed orientation gain matrix
% Results.TimeSeries is actually associated with Anrm, such
%  that the synthesized data is Anrm * TimeSeries'.
%  The unscaled timeseries is
UnscaledTime = [pinv(Results.IndepTopo)*Data.F]';
Model = Results.IndepTopo*UnscaledTime'; % synthesized data
Residual = Data.F - Model; % unexplained
% percent variance explained each part
PowModel = (fronorm(Model)/fronorm(Data.F))^2 *100;
PowResidual = (fronorm(Residual)/fronorm(Data.F))^2 *100;


setappdata(fig,'Data',Data);
setappdata(fig,'Results',Results);
setappdata(fig,'UnscaledTime',UnscaledTime);

if(0), % don't flip anymore, let user do the flipping
   % for plot niceties, lets flip polarity of time series as needed.
   FLIP = zeros(1,length(Results.SourceOrientation)); % should be one per topo column
   for i=  1:length(FLIP),
      [mx,mxi] = max(abs(Results.SourceOrientation{i}(:)));
      FLIP(i) = sign(Results.SourceOrientation{i}(mxi));
   end
   
   Results.IndepTopo = Results.IndepTopo .* FLIP(ones(1,size(Results.IndepTopo,1)),:);
   Results.TimeSeries = Results.TimeSeries .* FLIP(ones(1,size(Results.TimeSeries,1)),:);
end

update_listbox(fig,[],handles);

set(handles.checkbox_scale, 'Val',1); % scaling on

plot_time_series(fig,[],handles); % just the source time series

if 0 % deprecated code | following time series are plotted in Viewer's general timeseries figure
    % Plot the data
    axes(handles.axes_data)
    cla
    line(Data.Time(Results.Time),Data.F');
    set(gca,'YGrid','on');
    ylabel('Data','color','w');
    axis tight;
    Vaxis = axis; % so what are the axis settings?
    
    
    % Plotting Modelled Sensor Time Series
    axes(handles.axes_model)
    cla
    line(Data.Time(Results.Time),Model');
    set(gca,'YGrid','on');
    axis tight;
    ylabel('Model','color','w');
    axis(Vaxis); % set to the same as the  data
    
    
    % Plotting Residuals 
    
    axes(handles.axes_residuals)
    cla
    line(Data.Time(Results.Time),Residual');
    set(gca,'YGrid','on');
    axis(Vaxis); % set to the same as the  data
    ylabel('Residual','color','w');
    xlabel(...
        sprintf('Model: %.1f%% Explained, Residual: %.1f%% Unexplained',...
        PowModel,PowResidual),'color','w');
    
else
    global data % Get data structure from active Viewer
    % Fill time series arrays - get prepared for viewer
    for ifname = [1:3]
        data.Fmax{ifname} = zeros(1,3);
        for mod=data.imod
            if ~isempty(data.SelectedChannels{mod})
                switch ifname
                case 1
                    data.F{ifname}(data.SelectedChannels{mod},:) = Data.F;
                case 2
                    data.F{ifname}(data.SelectedChannels{mod},:) = Model;
                case 3
                    data.F{ifname}(data.SelectedChannels{mod},:) = Residual;
                end
                data.Fmax{ifname}(mod) = max(max(abs(data.F{ifname}(data.SelectedChannels{mod},:))));
            end
        end
    end
    
    data.FileName = {'data','model','residuals'};
    dataplot_cb('TimeSeries')
    
end




% -------------------- UPDATE THE LISTBOX DISPLAY -------------
function varargout = update_listbox(h,eventdata,handles);

fig = handles.figure_time_series;
Results = getappdata(fig,'Results');

%Update the listbox display
if(0), % optional look
   % since there is no "inverthardcopy" for list boxes, make black text
   %  on white background, for better hardcopies
   %set(handles.listbox_sourceparam,'BackgroundColor','w');
   %set(handles.listbox_sourceparam,'ForegroundColor','k');
end

ListSourceNumber = zeros(1000,1); % initialize, will trim below
% ListSourceNumber(i) gives the number of the associated source
%  for each line in the list box. As the user clicks on lines in the
%  listbox, the corresponding source is noted. A zero indicates no source

% Some Header Information

String{1} = 'BrainStorm MMII'; % let the world know who did this
String{end+1} = datestr(now);
String{end+1} = Results.Subject.Name;
String{end+1} = Results.Study.Name;
String{end+1} = Results.Comment;
String{end+1} = ' ';

for k = 1:length(Results.SourceLoc), % for each source
   String{end+1} = ['Source ',int2str(k),' :'];
   ListSourceNumber(length(String)) = k; % line assigned to source

   switch(Results.SourceOrder(k))
   case -1
      Type = 'Current Dipole';
   case 0
      Type = 'Magnetic Dipole';
   case 1
      Type = '1st-Order Multipole';
   case 2
      Type = 'Dipole Synchronous Pair';
   case 3
      Type = 'Magnetic Dipole Synchronous Pair';
   case 4
      Type = '1st-Order Multipole Synchronous Pair';
   otherwise
      Type = 'Unknown??';
   end
   String{end+1} = Type;
   ListSourceNumber(length(String)) = k;

   if ~isempty(Results.SourceCorrelation(k))
      switch lower(deblank(Results.Function))
      case 'least_squares_fit'
         String{end+1} = sprintf('%.1f%% variance explained',...
            100*Results.SourceCorrelation(k));
         ListSourceNumber(length(String)) = k;
      case 'rapmusic_gui'         
         String{end+1} = sprintf('%.1f%% correlation',...
            100*Results.SourceCorrelation(k));
         ListSourceNumber(length(String)) = k;
      otherwise
         String{end+1} = sprintf('%.1f%% unknown units',...
            100*Results.SourceCorrelation(k));         
         ListSourceNumber(length(String)) = k;
      end
   end
   
   Locs = Results.SourceLoc{k};
   Orients = Results.SourceOrientation{k};
   % one column per source
   Orients = reshape(Orients,length(Orients)/size(Locs,2),size(Locs,2)); 
   % In a synchronous source, each column is not unity norm, rather it
   %  represents the portion of energy in each location
   [OPower,nOrients] = colnorm(Orients);
   OPower = OPower.^2; % percent energy for each location
   % normalization has no effect for asynchronous case
   
   for j = 1:size(Locs,2)
      switch size(Locs,2)
      case 1
         String{end+1} = ['Location: ',...
               num2str(Locs(:,j)'*1000,'%6.1f ') 'mm'];
         ListSourceNumber(length(String)) = k;
      case 2 % two source
         String{end+1} = [sprintf('Location %.0f: ',j), ...
               num2str(Locs(1:3,j)'*1000,'%6.1f ') 'mm'];
         ListSourceNumber([-1:0]+length(String)) = k;
      end
      
      switch length(Orients(:,j))
      case 3
         String{end+1} = ['Dipole: ',num2str(nOrients(:,j)','%5.2f ')];
         ListSourceNumber(length(String)) = k;
      case 12
         String{end+1} = ['Dipole: ',num2str(nOrients(1:3,j)','%5.2f ')];
         String{end+1} = ['Quadrupole: ',num2str(nOrients(4:12,j)','%5.2f ')];
         ListSourceNumber([-1:0]+length(String)) = k;
      end
      
      if(size(Locs,2) > 1), % more than one location
         String{end+1} = sprintf('Percent contribution: %.1f%%',...
            OPower(j)*100);
         ListSourceNumber(length(String)) = k;
      end
      
      if ( (size(Locs,2) > 1) & (j < size(Locs,2)) ),
         % inside multiple source loop
         % pretty print
         String{end+1} = ' ';
         ListSourceNumber(length(String)) = k;
      end
      
      
   end % for each location in a source
   
      String{end+1} = ' ';
end

set(handles.listbox_sourceparam,'String',String);
setappdata(fig,'ListSourceNumber',ListSourceNumber);





% ----------------------- Plot the Time Series ----------------------
function plot_time_series(h,eventdata,handles);
% called by other routines to redo the time series, don't depend on h

fig = handles.figure_time_series;
Data = getappdata(fig,'Data');
Results = getappdata(fig,'Results');
UnscaledTime = getappdata(fig,'UnscaledTime');


% Plotting Solution Time Series
set(fig,'currentaxes',handles.axes_timeseries);
cla

if(get(handles.checkbox_scale,'Val')),
   htime_series = line(Data.Time(Results.Time)*1000,Results.TimeSeries);
else
   htime_series = line(Data.Time(Results.Time)*1000,UnscaledTime);
end

set(gca,'YGrid','on');
htitle = title(sprintf('%s',Results.GUI.Results),'color','w','interpreter','none'); 
ylabel('Solution Time Series','color','w')
xlabel('Time (ms)','color','w')

axis tight;
if(0)
   % give it a legend
   legstr = cell(1,size(Results.TimeSeries,2)); % number of solutions
   for i = 1:length(legstr),
      legstr{i} = sprintf('Source %.0f',i);
   end
   hleg = legend(legstr,0);
   hstr= findobj(hleg,'Type','Text'); % find the text strings
   set(hstr,'color','w');
end

% setup a uicontextmenu for each plot
for i = 1:length(htime_series),
   cmenu = uicontextmenu;
   % second item actually can flip the orientation
   item1 = uimenu(cmenu,'Label',sprintf('Source %02.0f Flip Orientation',i),...
      'Callback',...
      'results_time_series(''uimenu_flip_orientation_Callback'',gcbo,[],guidata(gcbo))');
   set(htime_series(i),'UiContextMenu',cmenu);
   setappdata(item1,'SourceNumber',i); % to retrieve which source this is
end


setappdata(fig,'htime_series',htime_series);

% update the highlighted source
listbox_sourceparam_Callback(handles.listbox_sourceparam,[],handles);




% ----------------- UICONTROL CALLBACKS ------------------------------
% --------------------------------------------------------------------
function varargout = listbox_sourceparam_Callback(h, eventdata, handles, varargin)

fig = handles.figure_time_series;
ListSourceNumber = getappdata(fig,'ListSourceNumber');
% Results = getappdata(fig,'Results');
htime_series = getappdata(fig,'htime_series');

Val = get(h,'Val'); % what line is the user on?
Val = Val(1); % just in case multiple lines were somehow selected

ThisSource = ListSourceNumber(Val); % corresponding source

% set all lines back to normal width
set(htime_series,'LineWidth',1);
if(ThisSource), % non-zero correspondence
   % set this line to width of 2, set rest to 1
   set(htime_series(ThisSource),'Linewidth',2);
end





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

fig = handles.figure_time_series;
Results = getappdata(fig,'Results');

% link in an MRI view of this data

% code testing here, which of Alex's routines to call
switch 2
case 1
   mrifig = mri_read_tool; % invoke a new copy
   mrihandles = guidata(mrifig); % and it's handles
   mri_read_tool('readbs_Callback',mrifig, eventdata, mrihandles,...
      Results.Subject.Anatomy);
case 2
   visfig = getappdata(fig,'visfig');
   if(isempty(visfig) | ~ishandle(visfig)), % not created or gone
      visfig = results_visualization;
      setappdata(fig,'visfig',visfig); % save it to prevent duplication
   end
   vishandles = guidata(visfig);
   results_visualization('loadparametric_Callback',...
      vishandles.loadparametric, eventdata, vishandles, Results.GUI.Results);
end





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

par1 = ['Top graph is the time series for each source. Lower three ',...
      'are the subspace data, the model synthesized using the sources ',...
      'and time series, and the residual between data and model. The ',...
      'locations and orientations of the sources are given in the ',...
      'listbox. '];
par2 = ['Left-Click on any line in the listbox to see the ',...
      'corresponding time series highlighted.'];
par3 = ['Right-click on any line in the top time series window to ',...
      'see the corresponding source number. Select the "flip ',...
      'orientation" item to reverse the polarity of the time ',...
      'series and corresponding moment orientation.'];
par4 = ['Synchronous sources: The location and moment are listed ',...
      'for each source, followed by the percent variance of each ',...
      'source. In other words, 50% indicates that each source ',...
      'uses 50% of the "energy" of the corresponding time series. ',...
      'It does not necessarily equate to the energy contribution ',...
      'of that source to the model. Similarly, 2% may indicate ',...
      'a spurious second dipole in the model.'];
      
bst_message_window('wrap',{'','DRAFT: Help for the Time Series Results',...
      '',par1,'',par2,'',par3,'',par4,''});


% --------------------------------------------------------------------
function varargout = pushbutton_quit_Callback(h, eventdata, handles, varargin)
close(handles.figure_time_series)



% --------------------------------------------------------------------
function varargout = pushbutton_print_Callback(h, eventdata, handles, varargin)
% we want to look reasonably pretty for possible publication

fig = handles.figure_time_series;
figure(fig);
set(fig,'menubar','figure'); % make the standard menu bar available

% force the listbox to be black and white for pretty print
set(handles.listbox_sourceparam,'foregroundcolor','k','backgroundcolor','w');
% black/white the checkbox too
set(handles.checkbox_scale,'foregroundcolor','k','backgroundcolor','w');

printpreview(handles.figure_time_series)



% --------------------------------------------------------------------
function varargout = checkbox_scale_ButtonDownFcn(h, eventdata, handles, varargin)
bst_message_window('wrap',{'','DRAFT HELP on meaning of scale'});



% --------------------------------------------------------------------
function varargout = checkbox_scale_Callback(h, eventdata, handles, varargin)
plot_time_series(h,eventdata,handles);



% --------------------------------------------------------------------
function varargout = uimenu_flip_orientation_Callback(h, eventdata, handles, varargin)
% flip the time series and associated orientation of the source
SourceNumber = getappdata(h,'SourceNumber'); % which source has been clicked on
fig = handles.figure_time_series;
Results = getappdata(fig,'Results');
UnscaledTime = getappdata(fig,'UnscaledTime');

Results.TimeSeries(:,SourceNumber) = -Results.TimeSeries(:,SourceNumber);
Results.SourceOrientation{SourceNumber} = -Results.SourceOrientation{SourceNumber};
UnscaledTime(:,SourceNumber) = -UnscaledTime(:,SourceNumber);

setappdata(fig,'Results',Results);
setappdata(fig,'UnscaledTime',UnscaledTime);

update_listbox(h,eventdata,handles);
plot_time_series(h,eventdata,handles);
