function varargout = phantom_channel_assignment(varargin)
%PHANTOM_CHANNEL_ASSIGNMENT - Application M-file for phantom_channel_assignment.fig
% function varargout = phantom_channel_assignment(varargin)
%    FIG = PHANTOM_CHANNEL_ASSIGNMENT launch phantom_channel_assignment GUI.
%    PHANTOM_CHANNEL_ASSIGNMENT('callback_name', ...) invoke the named callback.
% This tool (window) returns the assignment of an EEG channel structure
% (from any subject)to the phantom channel structure
%
% Use as:
%   [assigned_locs] = phantom_channel_assignment(MontrealChannels,MontrealLandmarks,Channel,Landmark);
%
%   input:
%   MontrealChannels:   .Loc:  3xn array of channel locations
%                       .Name: 1xn structure of strings containing the names of the channels
%   MontrealLandmarks:  .Loc:  3xn array of landmark locations
%                       .Name: 1xn structure of strings containing the names of the landmarks   
%   Channel:            The standard Channel structure of Brainstorm, belonging to the subject of interest
%   Landmark:           The standard Landmark of Brainstorm, belonging to the subject of interest
%
%   output:
%   assigned_locs:      .phantom: 3xm array of doubles, the channel locations of the phantom that 
%                                 have common correspondance with the
%                                 subject (begining with Nasion, PAL, PAR, ...
%                       .subject: 3xm array of doubles, the channel locations of the subject that 
%                                 have common correspondance with the subject
%
% See also TESS_ALIGN_TOOL.m

%<autobegin> ---------------------- 12-Oct-2004 12:02:45 -----------------------
% --------- Automatically Generated Comments Block Using AUTO_COMMENTS ---------
%
% CATEGORY: Database Management
%
% Alphabetical list of external functions (non-Matlab):
%   publictoolbox\othertools\select3d.m
%   toolbox\bst_color_scheme.m
%   toolbox\bst_layout.m
%   toolbox\bst_message_window.m
%   toolbox\makeuswait.m
%
% Subfunctions in this file, in order of occurrence in file:
%   varargout = initialize_gui(h,eventdata,handles,varargin);
%   Montreal_listbox_Callback(hObject, eventdata, handles)
%   Subject_listbox_Callback(hObject, eventdata, handles)
%   Autoassign_Callback(hObject, eventdata, handles)
%   Assign_Callback(hObject, eventdata, handles)
%   Deassign_Callback(hObject, eventdata, handles)
%   varargout = channelClick_Callback
%   varargout = Done_Callback(h, eventdata, handles, varargin)
%   varargout = Quit_Callback(h, eventdata, handles, varargin)
%
% Application data and their calls in this file:
%   'TileType'
%   'data'
%   'phantom_channel_assignment_handles'
%   
%   setappdata(0,'phantom_channel_assignment_handles',handles);
%   setappdata(fig,'TileType','T')
%   setappdata(fig,'data',data);
%   
%   data = getappdata(fig,'data');
%   handles = getappdata(0,'phantom_channel_assignment_handles');
%
% 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 phantom_channel_assignment.fig
%   uicontrol:listbox:Montreal_listbox "populating list..." uses Callback for <automatic>
%   uicontrol:listbox:Subject_listbox "populating list..." uses Callback for <automatic>
%   uicontrol:pushbutton:Assign "Assign" uses Callback for <automatic>
%   uicontrol:pushbutton:Autoassign "Auto Assign" uses Callback for <automatic>
%   uicontrol:pushbutton:Deassign "Deassign" uses Callback for <automatic>
%   uicontrol:pushbutton:Done "Done" uses Callback for <automatic>
%   uicontrol:pushbutton:Quit "Quit" uses Callback for <automatic>
%
% At Check-in: $Author: Mosher $  $Revision: 2 $  $Date: 10/12/04 10:24a $
%
% This software is part of BrainStorm Toolbox Version 2.0 (Alpha) 12-Oct-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> ------------------------ 12-Oct-2004 12:02:45 -----------------------

% Last Modified by GUIDE v2.5 04-Oct-2004 14:34:44


% /---Script Author--------------------------------------\
% |                                                      |
% | *** Dimitrios Pantazis, Ph.D. student                |
% | University of Southern California                    |
% |                                                      | 
% \------------------------------------------------------/
%  
% Date of creation: October 2004

% ----------------------------- Script History ---------------------------------
% 03-Oct-2004 DP  Creation
% JCM 11-Oct-2004 Commenting header
% ----------------------------- Script History ---------------------------------


% All communication between functions is done using the 'data' structure 
%
%data = 
%    MontrealName: {1xnPhantomPoints cell}
%     MontrealLoc: [3xnPhantomPoints double]
%     SubjectName: {1xnSubjectPoints cell}
%      SubjectLoc: [3xnSubjectPoints double]
%     assignments: [1xnPhantomPoints double]
%      plotHandle: Handle for the plot figure
%   hannelHandles: Handle for channels
%     lineHandles: [1xnPhantomPoints double], stores handles for lines


if ~ischar(varargin{1})  % LAUNCH GUI

	fig = openfig(mfilename,'reuse');

    bst_color_scheme(fig);
    setappdata(fig,'TileType','T')
    bst_layout('align',fig,2,2,4)
    set(fig,'visible','on'); % .fig saved as invisible until ready
        
	% Generate a structure of handles to pass to callbacks, and store it. 
	handles = guihandles(fig);
	guidata(fig, handles);
    
    %save arguments in data structure
    data.MontrealChannels = varargin{1};
    data.MontrealLandmarks = varargin{2};
    data.Channel = varargin{3};
    data.Landmark = varargin{4};

    %MontrealName & MontrealLoc will be the first listbox
    data.MontrealName = data.MontrealLandmarks.Name;
    data.MontrealName = [data.MontrealName data.MontrealChannels.Name];
    data.MontrealLoc = data.MontrealLandmarks.Loc;
    data.MontrealLoc = [data.MontrealLoc data.MontrealChannels.Loc];
    
    %SubjectName & SubjectLoc will be the second listbox
    data.SubjectName = data.Landmark.Name;
    data.SubjectName = [data.SubjectName {data.Channel.Name}];
    data.SubjectLoc = data.Landmark.Loc;
    data.SubjectLoc = [data.SubjectLoc data.Channel.Loc];
    
    %clear useless structures
    data = rmfield(data,'MontrealChannels');
    data = rmfield(data,'MontrealLandmarks');
    data = rmfield(data,'Channel');
    data = rmfield(data,'Landmark');
    
    %null assignments
    data.assignments = zeros(1,size(data.MontrealName,2));
    
    %save application data
    setappdata(fig,'data',data);

    %initialize
    initialize_gui(fig,[],handles,varargin{:});
    
    data = getappdata(fig,'data');
    set(data.plotHandle,'pointer','crosshair');
  	% Wait for callbacks to run and window to be dismissed:
	uiwait(fig);

    data = getappdata(fig,'data');
     
    %delete additional channels and lines
    phantom_points = size(data.MontrealName,2);
    for i = 1:phantom_points
        if ishandle(data.lineHandles(i))
            delete(data.lineHandles(i))
        end
    end
    if(ishandle(data.channelHandles));
        delete(data.channelHandles);
    end
    %delete marker if exist
    if(ishandle(data.channelMarker))
        delete(data.channelMarker)
    end
    
    %deactivate pointclicking on plotWindow
    set(data.plotHandle,'windowbuttondownfcn','');
    %delet tool handles on root window
    rmappdata(0,'phantom_channel_assignment_handles');
    %restore pointer
    set(data.plotHandle,'pointer','arrow');
    
    if(~ishandle(fig)) %if figure is closed already
         assigned_locs.phantom = [];
         assigned_locs.subject = [];
         varargout{1} = assigned_locs;
         varargout{2} = {[]};
         return
    end
        
    varargout{1} = data.assigned_locs;
    close(fig);
    
    
    
    
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 varargout = initialize_gui(h,eventdata,handles,varargin);
% This function initializes GUI controls, as well as two structures, 'data' and 'changed'

makeuswait('start')
fig = handles.phantom_channel_assignment; % make sure we have the handle
handles = guidata(fig);
data = getappdata(fig,'data');

%populate lists
set(handles.Montreal_listbox,'string',data.MontrealName)
set(handles.Subject_listbox,'string',data.SubjectName)


%locate plot figure (has the name: tessellations)
name = 'Tessellations';
hw = get(0,'children');		% all open windows
hw = sort(hw);			% in increasing window order
for i = 1:length(hw),
  s = get(hw(i),'Name');
  if(strcmp(deblank(s),deblank(name))),
    data.plotHandle = hw(i);
  end
end


%plot phantom channels
figure(data.plotHandle)
if isfield(data,'plotHandle')%if figure exists
    data.channelHandles = plot3(data.MontrealLoc(1,:),data.MontrealLoc(2,:),data.MontrealLoc(3,:),'ko');
    set(data.channelHandles,'markerfacecolor','red');
    axis equal
    axis off
end

%initialize data.lineHandles
data.lineHandles = -1*ones(1,size(data.MontrealLoc,2));

%activate pointclicking on plotWindow
set(data.plotHandle,'windowbuttondownfcn','phantom_channel_assignment(''channelClick_Callback'')');
%save tool handles on root window, so they can be accessed by channelClick fn
setappdata(0,'phantom_channel_assignment_handles',handles);
%define channelMarker
data.channelMarker = line('marker','o','markerfacecolor','k','linewidth',2,'markersize',8,'erasemode','xor','visible','off');
% channelMarker = data.channelMarker;
% setappdata(0,'channelMarker',channelMarker);


setappdata(fig,'data',data);

makeuswait('stop')



  

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

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


%get handles
fig = handles.phantom_channel_assignment; % make sure we have the handle
handles = guidata(fig);
data = getappdata(fig,'data');

%get selected Montreal channel
vi = get(handles.Montreal_listbox,'value');

p = data.MontrealLoc(:,vi);

%show marker
set(data.channelMarker,'visible','on','xdata',p(1),'ydata',p(2),'zdata',p(3));




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

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

%get handles
fig = handles.phantom_channel_assignment; % make sure we have the handle
handles = guidata(fig);
data = getappdata(fig,'data');

%get selected Montreal channel
vj = get(handles.Subject_listbox,'value');

p = data.SubjectLoc(:,vj);

%show marker
set(data.channelMarker,'visible','on','xdata',p(1),'ydata',p(2),'zdata',p(3));



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

%get handles
fig = handles.phantom_channel_assignment; % make sure we have the handle
handles = guidata(fig);
data = getappdata(fig,'data');

%deassign everything
data.assignments = zeros(size(data.assignments));

%number of points
phantom_points = size(data.MontrealName,2);
subject_points = size(data.SubjectName,2);

%make assignments
for i = 1:phantom_points %for all phantom points
    for j = 1:subject_points %for all subject points
        detect = strfind(lower(data.SubjectName{j}),lower(data.MontrealName{i}));
        %if detected, make assignment
        if ~isempty(detect)
            data.assignments(i) = j;
        end
    end
end

%special assignments
for j = 1:subject_points
     detect = strfind(lower(data.SubjectName{j}),'nas');
     if ~isempty(detect) %nasion
         data.assignments(1) = j;
     end
          detect = strfind(lower(data.SubjectName{j}),'par');
     if ~isempty(detect) %right preauricular
         data.assignments(3) = j;
     end
     detect = strfind(lower(data.SubjectName{j}),'pal');
     if ~isempty(detect) %left preauricular
         data.assignments(2) = j;
     end

end


%display assignments
figure(data.plotHandle)
for i = 1:phantom_points
    displayStr{i} = data.MontrealName{i};
    if data.assignments(i)~=0 %if assigned
        displayStr{i} = [displayStr{i} ' --> ' data.SubjectName{data.assignments(i)}];
    end
end
set(handles.Montreal_listbox,'string',displayStr)


%plot lines between assigned channels
for i = 1:phantom_points
    %if there is already a line, delete it
    if ishandle(data.lineHandles(i))
        delete(data.lineHandles(i))
    end
    if data.assignments(i)~=0 %if assigned
        X = [data.MontrealLoc(1,i) data.SubjectLoc(1,data.assignments(i))];
        Y = [data.MontrealLoc(2,i) data.SubjectLoc(2,data.assignments(i))];
        Z = [data.MontrealLoc(3,i) data.SubjectLoc(3,data.assignments(i))];
        data.lineHandles(i) = line(X,Y,Z);
        set(data.lineHandles(i),'color','black','linewidth',2)
    end
end



setappdata(fig,'data',data);    




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

%get handles
fig = handles.phantom_channel_assignment; % make sure we have the handle
handles = guidata(fig);
data = getappdata(fig,'data');

%make assignment
vi = get(handles.Montreal_listbox,'value');
vj = get(handles.Subject_listbox,'value');
data.assignments(vi) = vj;

%display assignments
phantom_points = size(data.MontrealName,2);
for i = 1:phantom_points
    displayStr{i} = data.MontrealName{i};
    if data.assignments(i)~=0 %if assigned
        displayStr{i} = [displayStr{i} ' --> ' data.SubjectName{data.assignments(i)}];
    end
end
set(handles.Montreal_listbox,'string',displayStr)

%display line
figure(data.plotHandle)
if ishandle(data.lineHandles(vi)) %if there is already a line, delete it
     delete(data.lineHandles(vi))
end
X = [data.MontrealLoc(1,vi) data.SubjectLoc(1,data.assignments(vi))];
Y = [data.MontrealLoc(2,vi) data.SubjectLoc(2,data.assignments(vi))];
Z = [data.MontrealLoc(3,vi) data.SubjectLoc(3,data.assignments(vi))];
data.lineHandles(vi) = line(X,Y,Z);
set(data.lineHandles(vi),'color','black','linewidth',2)

setappdata(fig,'data',data);



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

%get handles
fig = handles.phantom_channel_assignment; % make sure we have the handle
handles = guidata(fig);
data = getappdata(fig,'data');

%deassign
i = get(handles.Montreal_listbox,'value');
data.assignments(i) = 0;
%remove line if exists
if ishandle(data.lineHandles(i)) %if there is already a line, delete it
     delete(data.lineHandles(i))
end

%display assignments
phantom_points = size(data.MontrealName,2);
for i = 1:phantom_points
    displayStr{i} = data.MontrealName{i};
    if data.assignments(i)~=0 %if assigned
        displayStr{i} = [displayStr{i} ' --> ' data.SubjectName{data.assignments(i)}];
    end
end
set(handles.Montreal_listbox,'string',displayStr)

setappdata(fig,'data',data);   





function varargout = channelClick_Callback

handles = getappdata(0,'phantom_channel_assignment_handles'); %access tesselation tool
fig = handles.phantom_channel_assignment; % make sure we have the handle
data = getappdata(fig,'data');

%number of points
phantom_points = size(data.MontrealName,2);
subject_points = size(data.SubjectName,2);

%get coordinates of point
figure(data.plotHandle)
[p v vi face facei] = select3d;
if(isempty(p) & isempty(v)) %if user did not click on a tesselation
    return
end
if (isempty(p)) %if uses chooses the same point again
    p=v;
end

%show marker
set(data.channelMarker,'visible','on','xdata',p(1),'ydata',p(2),'zdata',p(3));

%change listbox selection
vi = find(sum(abs(data.MontrealLoc - p'*ones(1,phantom_points)))==0);
vj = find(sum(abs(data.SubjectLoc - p'*ones(1,subject_points)))==0);
if(~isempty(vi)) %if a phantom channel is selected
    set(handles.Montreal_listbox,'value',vi);
end
if(~isempty(vj)) %if a phantom channel is selected
    set(handles.Subject_listbox,'value',vj);
end




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

fig = handles.phantom_channel_assignment; % make sure we have the handle
handles = guidata(fig);
data = getappdata(fig,'data');

%ask if channels already aligned
if sum(data.assignments~=0)<5 %if less than 5 points selected
	reply = questdlg('At least 5 channels must be assigned. Choose more points?');
    if(strcmp(reply,'No'))
        bst_message_window('append','Process canceled by user because not enough channels where assigned'); 
        return
    end
    if(strcmp(reply,'Cancel'))
        bst_message_window('append','Please assign more channels'); 
        return
    end
    if(strcmp(reply,'Yes'))
        bst_message_window('append','Please assign more channels'); 
        return
    end
end

%ask if NAS,PAL,PAR not already assigned
if sum(data.assignments(1:3)~=0)<3 %if NAS/PAL/PAR
    bst_message_window('append','...');
    bst_message_window('append','Please assign Nasion, Left Preauricular, Right Preauricular'); 
    bst_message_window('append','These points are necessary to align the MR scan'); 
    return;
end

phantom_points = size(data.MontrealName,2);

%return locations of common channels (notice , NAS,PAL,PAR will be returned
%first in this order
assigned_locs.phantom = [];
assigned_locs.subject = [];
for i = 1:phantom_points
    if data.assignments(i)~=0 %if sensor assigned
        assigned_locs.phantom = [assigned_locs.phantom data.MontrealLoc(:,i)];
        assigned_locs.subject = [assigned_locs.subject data.SubjectLoc(:,data.assignments(i))];
    end
end
data.assigned_locs = assigned_locs;

setappdata(fig,'data',data);

uiresume;


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

fig = handles.phantom_channel_assignment; % make sure we have the handle
handles = guidata(fig);
data = getappdata(fig,'data');

data.assigned_locs.phantom = [];
data.assigned_locs.subject = [];
setappdata(fig,'data',data);

uiresume;
