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

%<autobegin> ---------------------- 26-May-2004 11:34:24 -----------------------
% --------- Automatically Generated Comments Block Using AUTO_COMMENTS ---------
%
% CATEGORY: GUI and Related
%
% Alphabetical list of external functions (non-Matlab):
%   toolbox\blk_diag.m
%   toolbox\bst_color_scheme.m
%   toolbox\bst_layout.m
%   toolbox\bst_message_window.m
%   toolbox\engstr.m
%   toolbox\get_user_directory.m
%   toolbox\os_meg.m
%   toolbox\save_fieldnames.m
%   toolbox\sensor_axial.m
%   toolbox\sensor_planar.m
%   toolbox\sensor_spacing.m
%   toolbox\str_repeater.m
%   toolbox\vec.m
%
% Subfunctions in this file, in order of occurrence in file:
%   set_listbox_entry(h,newstr);
%   link_listbox_vals(h, eventdata, handles);
%   initialize_gui(h, eventdata, handles);
%   varargout = pushbutton_load_results_Callback(h, eventdata, handles, varargin)
%   varargout = edit_number_sources_Callback(h, eventdata, handles, varargin)
%   varargout = listbox_source_model_Callback(h, eventdata, handles, varargin)
%   varargout = listbox_source_location_Callback(h, eventdata, handles, varargin)
%   varargout = listbox_source_orientation_Callback(h, eventdata, handles, varargin)
%   varargout = listbox_source_amplitude_Callback(h, eventdata, handles, varargin)
%   varargout = listbox_source_delay_Callback(h, eventdata, handles, varargin)
%   varargout = listbox_source_waveform_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_source_model_dipole_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_source_model_multipole_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_waveform_hamming_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_waveform_hann_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_waveform_boxcar_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_waveform_triangle_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_waveform_sinusoid_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_waveform_custom_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_edit_location_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_random_location_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_edit_orientation_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_random_orientation_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_ForceTangential_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_edit_amplitude_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_edit_delay_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_help_location_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_help_amplitude_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_help_delay_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_help_waveform_Callback(h, eventdata, handles, varargin)
%   varargout = uimenu_help_model_Callback(h, eventdata, handles, varargin)
%   varargout = help_orientation_context_menu_Callback(h, eventdata, handles, varargin)
%   varargout = edit_data_root_name_Callback(h, eventdata, handles, varargin)
%   varargout = edit_STUDIES_Callback(h, eventdata, handles, varargin)
%   varargout = edit_data_folder_name_Callback(h, eventdata, handles, varargin)
%   varargout = edit_brain_radius_Callback(h, eventdata, handles, varargin)
%   varargout = edit_scalp_radius_Callback(h, eventdata, handles, varargin)
%   varargout = edit_sensor_radius_Callback(h, eventdata, handles, varargin)
%   varargout = edit_head_center_Callback(h, eventdata, handles, varargin)
%   varargout = edit_sensor_spacing_Callback(h, eventdata, handles, varargin)
%   varargout = popup_sensor_coverage_Callback(h, eventdata, handles, varargin)
%   varargout = popup_sensor_type_Callback(h, eventdata, handles, varargin)
%   varargout = edit_sensor_baseline_Callback(h, eventdata, handles, varargin)
%   varargout = popup_data_modality_Callback(h, eventdata, handles, varargin)
%   varargout = edit_number_samples_Callback(h, eventdata, handles, varargin)
%   varargout = popup_noise_generator_Callback(h, eventdata, handles, varargin)
%   varargout = edit_noise_variance_Callback(h, eventdata, handles, varargin)
%   varargout = Quit_Callback(h, eventdata, handles, varargin)
%   varargout = pushbutton_generate_Callback(h, eventdata, handles, varargin)
%
% Application data and their calls in this file:
%   'Center'
%   'SourceLoc'
%   'SourceOrientation'
%   'TileType'
%   'TimeSeries'
%   
%   setappdata(fig,'Center',Center);
%   setappdata(fig,'Center',UserFile.Center);
%   setappdata(fig,'SourceLoc',UserFile.SourceLoc);
%   setappdata(fig,'SourceOrientation',UserFile.SourceOrientation);
%   setappdata(fig,'TileType','T');
%   setappdata(fig,'TimeSeries',TimeSeries);
%   setappdata(fig,'TimeSeries',UserFile.TimeSeries);
%   
%   Center = getappdata(fig,'Center');
%   SourceLoc = getappdata(fig,'SourceLoc');
%   SourceOrientation = getappdata(fig,'SourceOrientation');
%   TimeSeries = getappdata(fig,'TimeSeries');
%
% 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 simulator.fig
%   uicontrol:edit:edit_brain_radius "Brain Radius" uses Callback for <automatic>
%   uicontrol:edit:edit_data_folder_name "Simulation Folder Name" uses Callback for <automatic>
%   uicontrol:edit:edit_data_root_name "Root File Name" uses Callback for <automatic>
%   uicontrol:edit:edit_head_center "Head Center" uses Callback for <automatic>
%   uicontrol:edit:edit_noise_variance "Noise %" uses Callback for <automatic>
%   uicontrol:edit:edit_number_samples "Number Samps" uses Callback for <automatic>
%   uicontrol:edit:edit_number_sources "Num Sources" uses Callback for <automatic>
%   uicontrol:edit:edit_scalp_radius "Scalp Radius" uses Callback for <automatic>
%   uicontrol:edit:edit_sensor_baseline "Baseline Sep" uses Callback for <automatic>
%   uicontrol:edit:edit_sensor_radius "Meg Sensor Radius" uses Callback for <automatic>
%   uicontrol:edit:edit_sensor_spacing "Sensor Spacing" uses Callback for <automatic>
%   uicontrol:edit:edit_STUDIES "Studies Folder" uses Callback for <automatic>
%   uicontrol:listbox:listbox_source_amplitude "Amp" uses Callback for <automatic>
%   uicontrol:listbox:listbox_source_delay "Delay Samps" uses Callback for <automatic>
%   uicontrol:listbox:listbox_source_location "Location 1" uses Callback for <automatic>
%   uicontrol:listbox:listbox_source_model "None" uses Callback for <automatic>
%   uicontrol:listbox:listbox_source_orientation "Orientation" uses Callback for <automatic>
%   uicontrol:listbox:listbox_source_waveform "Hamming" uses Callback for <automatic>
%   uicontrol:popupmenu:popup_data_modality "MEG" uses Callback for <automatic>
%   uicontrol:popupmenu:popup_noise_generator "Noiseless" uses Callback for <automatic>
%   uicontrol:popupmenu:popup_sensor_coverage "Upper Hemisphere" uses Callback for <automatic>
%   uicontrol:popupmenu:popup_sensor_type "Magnetometer" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_generate "Generate" uses Callback for <automatic>
%   uicontrol:pushbutton:pushbutton_load_results "Previous Results" uses Callback for <automatic>
%   uimenu::help_orientation_context_menu "" uses Callback for <automatic>
%   uimenu::uimenu_edit_amplitude "" uses Callback for <automatic>
%   uimenu::uimenu_edit_delay "" uses Callback for <automatic>
%   uimenu::uimenu_edit_location "" uses Callback for <automatic>
%   uimenu::uimenu_edit_orientation "" uses Callback for <automatic>
%   uimenu::uimenu_ForceTangential "" uses Callback for <automatic>
%   uimenu::uimenu_help_amplitude "" uses Callback for <automatic>
%   uimenu::uimenu_help_delay "" uses Callback for <automatic>
%   uimenu::uimenu_help_location "" uses Callback for <automatic>
%   uimenu::uimenu_help_model "" uses Callback for <automatic>
%   uimenu::uimenu_help_waveform "" uses Callback for <automatic>
%   uimenu::uimenu_random_location "" uses Callback for <automatic>
%   uimenu::uimenu_random_orientation "" uses Callback for <automatic>
%   uimenu::uimenu_source_model_dipole "" uses Callback for <automatic>
%   uimenu::uimenu_source_model_multipole "" uses Callback for <automatic>
%   uimenu::uimenu_waveform_boxcar "" uses Callback for <automatic>
%   uimenu::uimenu_waveform_custom "" uses Callback for <automatic>
%   uimenu::uimenu_waveform_hamming "" uses Callback for <automatic>
%   uimenu::uimenu_waveform_hann "" uses Callback for <automatic>
%   uimenu::uimenu_waveform_sinusoid "" uses Callback for <automatic>
%   uimenu::uimenu_waveform_triangle "" uses Callback for <automatic>
%
% At Check-in: $Author: Mosher $  $Revision: 16 $  $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:24 -----------------------


% Last Modified by GUIDE v2.0 19-Jun-2002 08:58:59

if nargin == 0  % LAUNCH GUI

	fig = openfig(mfilename,'reuse');

	% Use system color scheme for figure:
	set(fig,'Color',get(0,'defaultUicontrolBackgroundColor'));

	% 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
   
   bst_color_scheme(fig);
   setappdata(fig,'TileType','T');
   bst_layout('align',fig,2,1,1);
   initialize_gui(fig,[],handles);
   set(fig,'visible','on');
   

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 ------------------------
function set_listbox_entry(h,newstr);
% set the current entry in the listbox to the new string
% used by the uimenus

str = get(h,'str');
if(~iscellstr(str)),
   str = cellstr(str);
end
val = get(h,'val');
str{val} = newstr;
set(h,'string',str); % put it back





% --------------------------------------------------------------------
function link_listbox_vals(h, eventdata, handles);
% set all listboxes to the same value

val = get(h,'val'); % the setting of the current listbox
links = {'model','location','orientation','amplitude','delay','waveform'};

for i =1:length(links),
   eval(sprintf('set(handles.listbox_source_%s,''val'',val);',links{i}));
end





% --------------------------------------------------------------------
function initialize_gui(h, eventdata, handles);

fig = handles.figure_simulator; % handy shorthand
User = get_user_directory;

% Set location boxes
% display current studies folder
set(handles.edit_STUDIES,'string',User.STUDIES);

% folder
set(handles.edit_data_folder_name,'string','simulated');

% data
set(handles.edit_data_root_name,'string','sphere_');


% sphere parameters
set(handles.edit_brain_radius,'string','80');
set(handles.edit_scalp_radius,'string','100');
% head center set below


% sensor parameters
set(handles.edit_sensor_radius,'string','120');
set(handles.edit_sensor_spacing,'string','25');
set(handles.edit_sensor_baseline,'string','50');

% Noise parameters
set(handles.popup_noise_generator,'val',2); % gaussian is 2
set(handles.edit_noise_variance,'string','1'); % good snr

% Data Parameters
% set the number of sources desired on initialization
set(handles.edit_number_sources,'string','3');

% now retrieve it
NumSources = str2num(get(handles.edit_number_sources,'string'));

% set the listbox strings
links = {'model','location','orientation','amplitude','delay','waveform'};
inits = {'Dipole','[0.0 0.0 80.0] mm','[1.00 0.00 0.00]','10 nA-m','10','Hamming'};

% is there application data defined? use it instead as the defaults

if(isappdata(fig,'SourceLoc'))
   % assume it is all there
   SourceLoc = getappdata(fig,'SourceLoc');
   SourceOrientation = getappdata(fig,'SourceOrientation');
   TimeSeries = getappdata(fig,'TimeSeries');
   % now convert to matrices
   SourceLoc = [SourceLoc{:}]; % make a matrix
   SourceOrientation = [SourceOrientation{:}];
else
   SourceLoc = repmat([0;0;80]/1000,1,NumSources); % source locations
   SourceOrientation = repmat([1.00;0.00;0.00],1,NumSources); % orients
   TimeSeries = []; % empty
end

% NOTE: Will crash if load is for synchronized sources. TimeSeries not same as 
%  number of sources in that case. CBB.

NumSources = size(SourceLoc,2); % number of sources

% are there time series? Initialize the number of samples
if(~isempty(TimeSeries)),
   inits{4} = '1 nA-m'; % unity scaling
   inits{5} = '0'; % no delay
   inits{6} = 'Custom'; % custom waveform
   set(handles.edit_number_samples,'String',int2str(size(TimeSeries,1)));
else
   set(handles.edit_number_samples,'String','100');
end


% now initialize listboxes
for i = 1:length(links),
   eval(sprintf(...
      'set(handles.listbox_source_%s,''val'',1,''string'',cellstr(repmat(''%s'',%.0f,1)));',...
      links{i},inits{i},NumSources));
end

% now overwrite just the custom initialization
cLoc = cell(NumSources,1); % cell array of locations
cOrient = cell(NumSources,1); % orientions

set(handles.edit_number_sources,'String',int2str(NumSources));
for i = 1:NumSources,
   cLoc{i} = ['[' str_repeater('%.1f',' ',SourceLoc(:,i)*1000) '] mm']; % pretty print
   cOrient{i} = ['[' str_repeater('%.2f',' ',SourceOrientation(:,i)) ']'];
end

set(handles.listbox_source_location,'String',cLoc);
set(handles.listbox_source_orientation,'String',cOrient);

% How about a center?
if(isappdata(fig,'Center')),
   Center = getappdata(fig,'Center');
   set(handles.edit_head_center,'string',sprintf('[%.1f %.1f %.1f]',...
      Center*1000));
else
   set(handles.edit_head_center,'string','[0 0 0]');
end

% activate the callback for sources
edit_number_sources_Callback(handles.edit_number_sources,eventdata,handles);





% --------------- UICONTROL CALLBACKS --------------------

% ------------ LOAD PREVIOUS RESULTS FOR SIMULATION -------------------
function varargout = pushbutton_load_results_Callback(h, eventdata, handles, varargin)

fig = handles.figure_simulator; % handy shorthand

% 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',...
      'Simulator Load Error');
   return
end

% assume the other parameters are there, in addition to SourceLoc
setappdata(fig,'SourceLoc',UserFile.SourceLoc);
setappdata(fig,'SourceOrientation',UserFile.SourceOrientation);
setappdata(fig,'TimeSeries',UserFile.TimeSeries);

if(isfield(UserFile,'IndepTopo')),
   % proper units, not contributions
   TimeSeries = pinv(UserFile.IndepTopo)*UserFile.Fsynth;
   TimeSeries = TimeSeries';
   setappdata(fig,'TimeSeries',TimeSeries);
end

% Is there a headcenter
if(isappdata(fig,'Center')),
   rmappdata(fig,'Center'); % initialize as nonexistant
end

if(isfield(UserFile,'StudySubject')), % the file has a StudySubject structure
   if(isfield(UserFile.StudySubject,'HeadModel')), % with a headmodel field
      if(exist(UserFile.StudySubject.HeadModel,'file')),
         % and the file exists
         HeadModel = load(fullfile(User.STUDIES,UserFile.StudySubject.HeadModel));
         Center = mean([HeadModel.Param.Center],2);  % average over all centers
         setappdata(fig,'Center',Center);
      end
   end
end % if the studysubject exists

% simulated data may conveniently have the Center defined in the file
if(isfield(UserFile,'Center')),
   % overrides the HeadModel, if there was one
   setappdata(fig,'Center',UserFile.Center);
end

initialize_gui(fig, eventdata, handles);





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

NumSources = round(str2num(get(h,'string')));
set(h,'string',NumSources) % properly displayed

% how many sources were there originally
Cstr = get(handles.listbox_source_model,'string');
OldNum = length(Cstr); % old number of sources

% set the listbox strings
links = {'model','location','orientation','amplitude','delay','waveform'};
inits = {'Dipole','[0.0 0.0 80.0] mm','[1.00 0.00 0.00]','10 nA-m','10','Hamming'};
   
if(OldNum < NumSources),
   % we need to initialize some new sources
   NewNum = NumSources - OldNum;
   
   
   for i = 1:length(links),
      hlist = eval(sprintf('handles.listbox_source_%s',links{i}));
      OldCstr = get(hlist,'String'); % old string array
      NewCstr = cellstr(repmat(inits{i},NewNum,1));
      set(hlist,'val',1,'string',[OldCstr;NewCstr]);
   end
   
elseif(OldNum > NumSources)
   % shorter, just trim
   for i = 1:length(links),
      hlist = eval(sprintf('handles.listbox_source_%s',links{i}));
      OldCstr = get(hlist,'String'); % old string array
      set(hlist,'val',1,'string',OldCstr(1:NumSources));
   end
   
end 


% --------------- START OF LINKED LISTBOXES --------------------------

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

link_listbox_vals(h, eventdata, handles);


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

link_listbox_vals(h, eventdata, handles);



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


link_listbox_vals(h, eventdata, handles);


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

link_listbox_vals(h, eventdata, handles);



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

link_listbox_vals(h, eventdata, handles);




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

link_listbox_vals(h, eventdata, handles);




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

set_listbox_entry(handles.listbox_source_model,'Dipole');



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

disp('Not implemented')
set_listbox_entry(handles.listbox_source_model,'Dipole');




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

set_listbox_entry(handles.listbox_source_waveform,'Hamming');



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

set_listbox_entry(handles.listbox_source_waveform,'Hann');



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

set_listbox_entry(handles.listbox_source_waveform,'Boxcar');



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

set_listbox_entry(handles.listbox_source_waveform,'Triangle');



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

set_listbox_entry(handles.listbox_source_waveform,'Sinusoid');



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

set_listbox_entry(handles.listbox_source_waveform,'Custom');



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

Cstr = get(handles.listbox_source_location,'string'); 
val = get(handles.listbox_source_location,'val');
str = Cstr{val}; % current entry in the listbox

% strip out the brackets, if any
str = strrep(str,'[','');
str = strrep(str,']','');
str = strrep(str,' mm',''); % strip the units in the display

% expand the orientation display
prompt={'Location in the x, y, z coordinates'};
def = {str};
dlgTitle = 'Source Location';
lineNo = 1;
answer = inputdlg(prompt,dlgTitle,lineNo,def);

if(~isempty(answer))
   % set the edit box
   location = str2num(answer{1}); % convert to array
   
   if(~isempty(location)),
      % valid read of the answer box      
      % build string
      str = ['[',str_repeater('%.1f',' ',location),'] mm'];
      
      Cstr{val} = str; % replace in array
      
      % replace array
      set(handles.listbox_source_location,'string',Cstr);
      
   end
   
   % once the location is edited, update the orientation
   uimenu_edit_orientation_Callback(...
      handles.listbox_source_orientation, eventdata, handles, varargin)

end % else do nothing






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

Cstr = get(handles.listbox_source_location,'string'); 
val = get(handles.listbox_source_location,'val');
str = Cstr{val}; % current entry in the listbox

location = [randn(1,2)*20 rand(1)*100];

str = ['[',str_repeater('%.1f',' ',location),'] mm'];

Cstr{val} = str; % replace in array

% replace array
set(handles.listbox_source_location,'string',Cstr);

% now treat as new edited entry
uimenu_edit_location_Callback(handles.listbox_source_location, eventdata, handles, varargin)





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

Cstr = get(handles.listbox_source_orientation,'string'); 
val = get(handles.listbox_source_orientation,'val');
str = Cstr{val}; % current entry in the listbox

% strip out the brackets, if any
str = strrep(str,'[','');
str = strrep(str,']','');

% expand the orientation display
prompt={'Orientation in the x, y, z directions'};
def = {str};
dlgTitle = 'Source Orientation, answer normalized automatically';
lineNo = 1;
answer = inputdlg(prompt,dlgTitle,lineNo,def);

if(~isempty(answer))
   % set the edit box
   orient = str2num(answer{1}); % convert to array
   
   if(~isempty(orient)),
      % valid read of the answer box
      orient = orient(:);
      Tangential = get(handles.uimenu_ForceTangential,'checked');
      % is Tangential checked on?
      if(strcmp(Tangential,'on')),
         % need location, project tangential to it
         LCstr = get(handles.listbox_source_location,'string'); 
         Lval = get(handles.listbox_source_location,'val');
         Lstr = LCstr{Lval}; % current entry in the listbox
         
         Lstr = strrep(Lstr,'mm',''); % remove units
         
         Location = str2num(Lstr);
         CENTER = get(handles.edit_head_center,'string');
         CENTER = strrep(CENTER,'[','');
         CENTER = strrep(CENTER,']','');
         Center = str2num(CENTER); % center
         Location = Location - Center; % adjust to head center
         
         orient = orient - Location'*(Location*orient)/(Location*Location');
      end
      
      orient = orient/norm(orient); % the normalized orientation
      
      % build string
      str = ['[',str_repeater('%.2f',' ',orient),']'];
      
      Cstr{val} = str; % replace in array
      
      % replace array
      set(handles.listbox_source_orientation,'string',Cstr);
      
   end
end % else do nothing




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

Cstr = get(handles.listbox_source_orientation,'string'); 
val = get(handles.listbox_source_orientation,'val');
str = Cstr{val}; % current entry in the listbox

orient = randn(1,3);
orient = orient/norm(orient);

str = ['[',str_repeater('%.2f',' ',orient),']'];

Cstr{val} = str; % replace in array

% replace array
set(handles.listbox_source_orientation,'string',Cstr);

uimenu_edit_orientation_Callback(handles.listbox_source_orientation, eventdata, handles, varargin)




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

% whether or not to force all orientations to be tangential
Tangential = get(h,'checked');
switch Tangential
case 'on'
   set(h,'checked','off');
case 'off'
   set(h,'checked','on');
end





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

Cstr = get(handles.listbox_source_amplitude,'string'); 
val = get(handles.listbox_source_amplitude,'val');
str = Cstr{val}; % current entry in the listbox

str = strrep(str,' nA-m',''); % remove units

% expand the orientation display
prompt={'Maximum amplitude in nA-m'};
def = {str};
dlgTitle = 'Source Amplitude';
lineNo = 1;
answer = inputdlg(prompt,dlgTitle,lineNo,def);

if(~isempty(answer))
   % set the edit box
   amp = str2num(answer{1}); % convert to array
   
   if(~isempty(amp)),
      % valid read of the answer box      
      % build string
      str = sprintf('%.0f nA-m',amp);
      
      Cstr{val} = str; % replace in array
      
      % replace array
      set(handles.listbox_source_amplitude,'string',Cstr);
      
   end
end % else do nothing





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

Cstr = get(handles.listbox_source_delay,'string'); 
val = get(handles.listbox_source_delay,'val');
str = Cstr{val}; % current entry in the listbox

% expand the orientation display
prompt={'Number of samples delay'};
def = {str};
dlgTitle = 'Source Delay';
lineNo = 1;
answer = inputdlg(prompt,dlgTitle,lineNo,def);

if(~isempty(answer))
   % set the edit box
   delay = str2num(answer{1}); % convert to array
   delay = round(delay);
   
   if(~isempty(delay)),
      % valid read of the answer box      
      % build string
      str = sprintf('%.0f',delay);
      
      Cstr{val} = str; % replace in array
      
      % replace array
      set(handles.listbox_source_delay,'string',Cstr);
      
   end
end % else do nothing





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





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




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




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



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



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

bst_message_window('wrap','DRAFT: Help for setting the simulation orientation');




% --------------- END OF LINKED LISTBOXES ----------------------------






% --------------------------------------------------------------------
function varargout = edit_data_root_name_Callback(h, eventdata, handles, varargin)
% The file prefix name



% --------------------------------------------------------------------
function varargout = edit_STUDIES_Callback(h, eventdata, handles, varargin)
% Inactive, for display purposes only. Use datamanager to change



% --------------------------------------------------------------------
function varargout = edit_data_folder_name_Callback(h, eventdata, handles, varargin)
% Folder inside of studies to store




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





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





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





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





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





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

% strings relate loosely to half and full coverage



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

% strings relate loosely to magnetometer, axial gradi, planar grad



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

% numeric in mm



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





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






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





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







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

delete(gcbf)





% -------------------- MAKE THE SIMULATED DATA -------------------------------
function varargout = pushbutton_generate_Callback(h, eventdata, handles, varargin)

fig = handles.figure_simulator; % handy shorthand

% Global variables
User = get_user_directory; % where are we?

% GUI Variables
% the folder name and prefix to the data names
STUDIES = User.STUDIES; % root folder
FOLDER = get(handles.edit_data_folder_name,'String'); % desired simulation folder
PREFIX = get(handles.edit_data_root_name,'String'); % desired prefix name


% which sensor modality was selected
tempstr = get(handles.popup_data_modality,'String');
MODALITY = tempstr{get(handles.popup_data_modality,'Val')};

% spacing of sensors in mm -> m
SENSOR_SPACING = str2num(get(handles.edit_sensor_spacing,'string'))/1000;

% Sensor coverage
SENSOR_COVERAGE = {'half','full'};
SENSOR_COVERAGE = SENSOR_COVERAGE{get(handles.popup_sensor_coverage,'value')};

% Sensor type, important if MEG
SENSOR_TYPE = {'magnetometer','axial','planar'};
SENSOR_TYPE = SENSOR_TYPE{get(handles.popup_sensor_type,'value')};

% Sensor baseline in mm -> m
BASELINE = str2num(get(handles.edit_sensor_baseline,'string'))/1000;

MODEL = get(handles.listbox_source_model,'string');
LOCATION = get(handles.listbox_source_location,'string');
ORIENTATION = get(handles.listbox_source_orientation,'string');
AMPLITUDE = get(handles.listbox_source_amplitude,'string');
DELAY = get(handles.listbox_source_delay,'string');
WAVEFORM = get(handles.listbox_source_waveform,'string');

% strip units
LOCATION = strrep(LOCATION,' mm','');
AMPLITUDE = strrep(AMPLITUDE,' nA-m','');

CENTER = vec(str2num(get(handles.edit_head_center,'string')))/1000;

NUM_SAMPLES = str2num(get(handles.edit_number_samples,'string'));

TimeSeries = getappdata(fig,'TimeSeries');


% ----------------------- STUDY STRUCTURE --------------------------
% The Study Structure
% Build and load a brainstormstudy.mat

% Information about the Study
Study = struct('Name',[],'Session',[],'DateOfStudy',[],...
   'DateOfModification',[],'BrainStormSubject',[],'Subject',[]);
Study.Name = 'Simulated Data';
Study.Session = 'Simulated Session';
Study.DateOfStudy = '01-Jan-1998';
Study.DateOfModification = date;
Study.BrainStormSubject = []; % the filename of the subject, handled below.
Study.Subject = 'Simulated Subject';

% what is the modality and therefore the SENSOR radius:
switch MODALITY
case 'MEG'
   SENSOR = str2num(get(handles.edit_sensor_radius,'string'))/1000;
case 'EEG'
   SENSOR = str2num(get(handles.edit_scalp_radius,'string'));
otherwise
   disp('unknown modality');
end

% --------------------- CHANNEL GENERATION ----------------------------
% The Channel information

% pre-allocate space
[Channel(1:1000)] = deal(struct('Loc',[],'Orient',[],'Weight',[],'Type',[],...
   'Comment',[],'Name',[],'System',[]));

% Initial sensor arrangement
tempLoc = sensor_spacing(SENSOR,SENSOR_SPACING,SENSOR_COVERAGE);

switch MODALITY
case 'MEG'
   
   switch SENSOR_TYPE
   case 'magnetometer'   
      % simple, keep the existing location
      NUM_CHANNELS = size(tempLoc,1);
      for i = 1:NUM_CHANNELS,
         Channel(i).Loc = tempLoc(i,:)';
         Channel(i).Orient = Channel(i).Loc/norm(Channel(i).Loc);
         Channel(i).Weight = [1];
         Channel(i).Type = 'MEG';
         Channel(i).Comment = sprintf('Simulated magnetometer #%03.0f',i);
         Channel(i).Name = sprintf('MEG %03.0f',i);
         Channel(i).System = 'ctf';
      end
      
   case 'axial'
      % create second sensor in radial direction
      [tempLoc,tempOrient] = sensor_axial(tempLoc,BASELINE);
      NUM_CHANNELS = size(tempLoc,1);
      for i = 1:NUM_CHANNELS,
         Channel(i).Loc = reshape(tempLoc(i,:),3,2);
         Channel(i).Orient = reshape(tempOrient(i,:),3,2);
         Channel(i).Weight = [1; -1];
         Channel(i).Type = 'MEG';
         Channel(i).Comment = sprintf('Simulated axial gradiometer #%03.0f',i);
         Channel(i).Name = sprintf('MEG %03.0f',i);
         Channel(i).System = 'ctf';
      end
      
   case 'planar'
      % create two planar sensors per location
      [tempLoc,tempOrient] = sensor_planar(tempLoc,BASELINE);
      NUM_CHANNELS = size(tempLoc,1);
      for i = 1:NUM_CHANNELS,
         Channel(i).Loc = reshape(tempLoc(i,:),3,2);
         Channel(i).Orient = reshape(tempOrient(i,:),3,2);
         Channel(i).Weight = [1; -1];
         Channel(i).Type = 'MEG';
         Channel(i).Comment = sprintf('Simulated planar gradiometer #%03.0f',i);
         Channel(i).Name = sprintf('MEG %03.0f',i);
         Channel(i).System = 'ctf';
      end
      
   case 'triaxial'
      [tempLocp,tempOrient] = sensor_planar(tempLoc,BASELINE);
      NUM_MAG = size(tempLoc,1);
      NUM_PLANE = size(tempLocp,1);
      
      NUM_CHANNELS = NUM_MAG + NUM_PLANE;
      
      % first the magnetometers
      for i = 1:NUM_MAG,
         Channel(i).Loc = tempLoc(i,:)';
         Channel(i).Orient = Channel(i).Loc/norm(Channel(i).Loc);
         Channel(i).Weight = [1];
         Channel(i).Type = 'MEG';
         Channel(i).Comment = sprintf('Simulated magnetometer #%03.0f',i);
         Channel(i).Name = sprintf('MEG %03.0f',i);
         Channel(i).System = 'ctf';
      end
      
      % then the gradiometers
      for i = 1:NUM_PLANE,   
         Channel(i + NUM_MAG).Loc = reshape(tempLocp(i,:),3,2);
         Channel(i + NUM_MAG).Orient = reshape(tempOrient(i,:),3,2);
         Channel(i + NUM_MAG).Weight = [1; -1];
         Channel(i + NUM_MAG).Type = 'MEG';
         Channel(i + NUM_MAG).Comment = sprintf('Simulated planar gradiometer #%03.0f',i);
         Channel(i + NUM_MAG).Name = sprintf('MEG %03.0f',i);
         Channel(i + NUM_MAG).System = 'ctf';
      end
      
      
   end
   
case 'EEG'
   % not yet
   
end

Channel = Channel(1:NUM_CHANNELS); % trim allocation

% Move all channels to be spherical about the head center
for i = 1:NUM_CHANNELS,
   % Move the channel from sphere to PCS
   Channel(i).Loc = Channel(i).Loc + repmat(CENTER,1,size(Channel(i).Loc,2));
end

[Param(1:NUM_CHANNELS)] = struct('Center',CENTER);


% ----------------------- DATA GENERATION ------------------------

Data = struct('F',[],'Time',[],'ChannelFlag',[],'NoiseCov',[],'SourceCov',[],...
   'Projector',[],'Comment',[]);

Location = str2num(char({'[', LOCATION{:} ']'}))'/1000; % per column
% Location is already in the PCs

Orientation = str2num(char({'[', ORIENTATION{:} ']'}))'; % per column

G = os_meg(Location,Channel,Param,-1);
A = G*blk_diag(Orientation,1); % each source gets a column
S = zeros(NUM_SAMPLES,size(A,2)); % one time series per source

for i = 1:size(S,2), % for each source
   amp = str2num(AMPLITUDE{i});
   delay = str2num(DELAY{i});
   wavlen = NUM_SAMPLES-delay; % number of samples to generate
   
   switch WAVEFORM{i}
   case 'Hamming'
      waveform = hamming(wavlen);
   case 'Hann'
      waveform = hann(wavlen);
   case 'Boxcar'
      waveform = ones(wavlen,1);
   case 'Triangle'
      waveform = triang(wavlen);
   case 'Sinusoid'
      % start and return to zero
      waveform = sin(2*pi*[0:(wavlen-1)]'/(wavlen-1));
   case 'Custom'
      waveform = TimeSeries(:,i)*1e9; % nA-m units
   otherwise
      error(sprintf('Problem waveform type: %s',WAVEFORM{i}));
   end
   
   waveform = waveform*amp;
   S(:,i) = [zeros(delay,1);waveform];
   
end   
      
Data.F = A*S';
% Data.F = Data.F * (1e-9 * 1e15); % to convert nA-m to A-m, then units to fT.
Data.F = Data.F * (1e-9); % to convert nA-m to A-m, leave  units in T.

% -------------------- NOISE GENERATION ----------------------------
% now add the noise

NoiseVal = get(handles.popup_noise_generator,'val');
NoisePCT = str2num(get(handles.edit_noise_variance,'string'))/100;
if(isempty(NoisePCT)),
   disp('Noise value string corrupted, edit');
   bst_message_window('append','Noise value string corrupted, edit');
   NoisePCT = 0;
end
VarSig = sum(Data.F(:).^2); % variance of the data

switch NoiseVal
case 1
   % noiseless, do nothing
   FNoise = zeros(size(Data.F));
case 2
   % gaussian
   FNoise = randn(size(Data.F));
case 3
   % uniform
   FNoise = rand(size(Data.F));
otherwise
   % unknown
   error('unknown noise val added to popup, edit m-file');
end

VarNoise = sum(FNoise(:).^2);
if(VarNoise), % non-zero case
   FNoise = FNoise*sqrt(VarSig/VarNoise*NoisePCT/(1-NoisePCT));
end
% Noise is now NoisePCT Variance not explained

ChannelStd = std(FNoise'); % standard dev per channel
disp(sprintf('Std. Dev per channel: %s',engstr(mean(ChannelStd))));
Data.F = Data.F + FNoise;


% ------------------- FINAL CLEANUP AND WRITING -----------------

Data.Time = ([1:size(S,1)]-6) * 2/1000; % 2 ms sampling, fake pre-stim


disp('True Locations (mm):')
disp(Location*1000)
disp('True Orientations: ')
disp(Orientation)

Data.ChannelFlag = ones(1,length(Channel)); % all channels good
Data.NoiseCov = []; % unused for now
Data.SourceCov = []; % unused for now
Data.Projector = []; % unused for now
Data.Comment = 'Simulated Data';
Data.Device = 'Ctf_Axial';  % simulated

% So now all structures are complete and residing in ram. Need to write out
%  to the appropriate files.
% Recall that PREFIX and PREFIX_STUDY were defined above.

Users = get_user_directory; % where is the base storage area


% now the study data
cd(STUDIES);
if(~exist(FOLDER,'dir')),
   % CBB handle status errors
   [status, message] = mkdir(FOLDER);
end
cd(FOLDER);


% Need a unique name
% Remote possibility of creating a duplicate name, which would overwrite old data
clk = clock;
SUF = sprintf('%02.0f%04.0f',clk(5),round(clk(6)*100)); % suffix of minutes, seconds, hundreds
DataFileName = [PREFIX 'data_' SUF];
% DataSimResults = [DataFileName '_sim_results'];
% New convention, replace data with results in filename
DataSimResults = [PREFIX 'results_' SUF];

if(~exist([PREFIX 'brainstormstudy.mat'],'file')),
   save_fieldnames(Study,[PREFIX 'brainstormstudy']);
end

% because we kept Channel a single array, requires special handling
save([PREFIX 'channel'],'Channel');
% load as two-step, Channel = load('channel.mat'); Channel = Channel.Channel;

save_fieldnames(Data,DataFileName); % the first of several possible data sets.

bst_message_window('append',sprintf('Current directory: %s',pwd));
bst_message_window('append',sprintf('Wrote %s',DataFileName));

% now write out the answers to a simulated results file

SourceLoc = cell(1,size(Location,2));
SourceOrientation = cell(size(SourceLoc));
IndepTopo = A;
TimeSeries = S;
Fsynth = Data.F;
Time = Data.Time;
Comment = 'Simulated data';
Center = CENTER;

for i= 1:size(Location,2),
   SourceLoc{i} = Location(:,i);
   SourceOrientation{i} = Orientation(:,i);
end

save(DataSimResults,'SourceLoc','SourceOrientation','Center',...
   'IndepTopo','TimeSeries','Fsynth','Time','Comment');


bst_message_window('append',sprintf('Wrote %s',DataSimResults));

bst_message_window('Done');

