% POP_LOADBCI - import a BCI2000 ascii file into EEGLAB
%
% Usage:
%   >> OUTEEG = pop_loadbci( filename, srate );
%
% Inputs:
%   filename       - file name
%   srate          - sampling rate
%
% Outputs:
%   OUTEEG         - EEGLAB data structure
%
% Author: Arnaud Delorme, CNL / Salk Institute, 9 July 2002
%
% See also: EEGLAB

% Copyright (C) 2002 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

function [EEG, command] = pop_loadbci(filename, srate); 

    EEG = [];
    command = '';
    
    if nargin < 1
        % ask user
        [filename, filepath] = uigetfile('*.*', 'Choose a BCI file -- pop_loadbci'); 
        drawnow;
        if filename == 0 return; end
        filename = [filepath filename];
        promptstr    = { 'Sampling rate' };
        inistr       = { '256' };
        result       = inputdlg2( promptstr, 'Import BCI2000 data -- pop_loadbci()', 1,  inistr, 'pop_loadbci');
        if length(result) == 0 return; end
        srate   = eval( result{1} );
    end
    
    % import data
    % -----------
    EEG = eeg_emptyset;
    fprintf('Pop_loadbci: importing BCI file...\n');
    try
        % try to read as matlab
        % ---------------------
        bci = load( filename, '-mat');
        allfields = fieldnames(bci);
        allfields = setdiff_bc(allfields, 'signal');
        for index = 1:size(bci.signal,2)
            chanlabels{index} = [ 'C' int2str(index) ];
        end
        for index = 1:length(allfields)
            bci.signal(:,end+1) = getfield(bci, allfields{index});
        end
        EEG.chanlocs = struct('labels', { chanlabels{:} allfields{:} });
        EEG.data     = bci.signal';
        EEG.nbchan   = size(EEG.data, 1);
        EEG.pnts     = size(EEG.data, 2);
        EEG.trials   = 1;
        EEG.srate    = srate;
        EEG.comments = [ 'Original file: ' filename ];
        EEG = eeg_checkset(EEG);
        return;
    catch
        % get file names
        % --------------
        fields = loadtxt(filename, 'nlines', 1, 'verbose', 'off');
        if length(fields) > 300
            error('Not a BCI ASCII file');
        end
        
        % read data
        % ---------
        fid = fopen(filename, 'r');
        allcollumns = fgetl(fid);
        tmpdata = fscanf(fid, '%d', Inf);
        tmpdata = reshape(tmpdata, length(fields), length(tmpdata)/length(fields));
        
        EEG.data = tmpdata;
        EEG.chanlocs = struct('labels', fields);
        EEG.nbchan = size(EEG.data, 1);
        EEG.pnts   = size(EEG.data, 2);
        EEG.trials = 1;
        EEG.srate  = srate;
        EEG = eeg_checkset(EEG);
        return;

        % data channel range
        % ------------------
        indices = strmatch('ch', fields);
        
        bci = [];
        for index = setdiff_bc(1:length(fields), indices)
            bci = setfield(bci, fields{index}, tmpdata(index,:));
        end
        bci.signal = tmpdata(indices,:);
    end
    
    
    % ask for which event to import
    % -----------------------------
    geom = {[0.7 0.7 0.7]};
    uilist = { { 'style' 'text' 'string' 'State name' 'fontweight' 'bold' } ...
               { 'style' 'text' 'string' '    Import' 'fontweight' 'bold'  } ...
               { 'style' 'text' 'string' 'Type of'  'fontweight' 'bold' } };
    allfields = setdiff_bc(fieldnames(bci), 'signal');
    latencyfields = { '-----' };
    for index = 1:length(allfields)
        if ~isempty(findstr( lower(allfields{index}), 'time')) 
            latencyfields{end+1} = allfields{index};
        end
    end
    for index = 1:length(allfields)
        geom   = { geom{:} [1.3 0.3 0.3 0.3 1] };
        uilist{end+1} = { 'style' 'text' 'string' allfields{index} };
        if ~isempty(findstr( lower(allfields{index}), 'time'))
            uilist{end+1} = { 'style' 'checkbox' 'value' 0 };
            uilist{end+1} = { };
            uilist{end+1} = { };
            uilist{end+1} = { };
        else
            uilist{end+1} = { 'style' 'checkbox' };
            uilist{end+1} = { };
            uilist{end+1} = { };
            uilist{end+1} = { 'style' 'listbox' 'string' strvcat(latencyfields) };
        end
    end
    geom   = { geom{:} [1] [0.08 1] };
    uilist{end+1} = { };
    uilist{end+1} = { 'style' 'checkbox' 'value' 0 };
    uilist{end+1} = { 'style' 'text' 'string' 'Attempt to adjust event latencies using sourcetime?' };
    
    result = inputgui( geom, uilist, 'pophelp(''pop_loadbci'')', 'Import BCI2000 data files - pop_loadbci()');
    if isempty(result), return; end
    
    % convert results to command line input
    % -------------------------------------
    listimport = {};
    count = 1;
    for index = 1:length(allfields)
        if ~isempty(findstr( lower(allfields{index}), 'time')) 
            if result{count}, listimport{end+1} = 'event'; listimport{end+1} = { allfields{index} }; end
            count = count+1;
        else 
            if result{count}
                if result{count+1} ~= 1
                    listimport{end+1} = 'event'; listimport{end+1} = { allfields{index}  allfields{result{count+1}-1} };
                else
                    listimport{end+1} = 'event'; listimport{end+1} = { allfields{index} };
                end
            end
            count = count+2;                
        end
    end
    if result{end}, adjust = 1; else adjust = 0; end
    
    % decode command line input 
    % -------------------------
    count = 1;
    for index = 2:2:length(listimport)
        tmpindmatch = strmatch(listimport{index}{1}, allfields, 'exact');
        if ~isempty(tmpindmatch), indeximport(count) = tmpindmatch; 
        else error(['State ''' listimport{index}{1} ''' not found']); 
        end
        if length( listimport{index} ) > 1
            tmpindmatch = strmatch(listimport{index}{2}, allfields, 'exact');
            if ~isempty(tmpindmatch), corresp(count) = tmpindmatch; 
            else error(['State ''' listimport{index}{2} ''' not found']); 
            end
        else
            corresp(count) = 0;
        end
        count = count+1;
    end
        
    % find block size
    % ---------------
    tmpevent = find( diff(getfield(bci, 'SourceTime')) ~= 0);
    diffevent = tmpevent(2:end)-tmpevent(1:end-1);
    blocksize = unique_bc(diffevent);
    if length(blocksize) > 1, error('Error in determining block size'); 
    else                      fprintf('Blocksize: %d\n', blocksize); 
    end
    
    % find types
    % ----------
    tmpcorresp      = find(corresp);
    indexcorresp    = corresp(tmpcorresp);
    indexcorrespval = indeximport(tmpcorresp);
    if length(tmpcorresp) ~= length(intersect(corresp, indeximport))
        disp('Warning: correspondence problem, some information will be lost');
    end
    
    % remove type from latency array
    % ------------------------------
    indeximport(tmpcorresp) = [];
    if adjust
        fprintf('Latency of event will be adjusted\n');
    else fprintf('WARNING: Latency of event will not be adjusted (latency uncertainty %2.1f ms)\n', ...
                 blocksize/srate*1000);
    end
    
	% process events
	% --------------
	fprintf('Pop_loadbci: importing events...\n');
	counte = 1; % event counter
	events(10000).latency = 0;
    indexsource =  strmatch('sourcetime', lower( allfields ), 'exact' );
    sourcetime  = getfield(bci, allfields{ indexsource });
	for index = 1:length(indeximport)
        tmpdata  = getfield(bci, allfields{indeximport(index)});
		tmpevent = find( diff(tmpdata) > 0);
		tmpevent = tmpevent+1;
        tmpcorresp = find(indexcorresp == indeximport(index));
        
		for tmpi = tmpevent'
            if ~isempty(tmpcorresp)
                events(counte).type = allfields{ indexcorrespval(tmpcorresp) };
            else 
                events(counte).type = allfields{ indeximport(index) };
            end
            if adjust
                baselatency = sourcetime(tmpi); % note that this is the first bin a block
                realtmpi    = tmpi+blocksize;   % jump to the end of the block+1
                if curlatency < baselatency, curlatency = curlatency+65536; end; % in ms
                events(counte).latency = realtmpi+(curlatency-baselatency)/1000*srate;
                % (curlatency-baselatency)/1000*srate
                % there is still a potentially large error between baselatency <-> realtmpi
            else
                events(counte).latency = tmpi+(blocksize-1)/2;
            end
            counte = counte+1;
		end
	end; 
           
	EEG.data = bci.signal';
	EEG.nbchan = size(EEG.data, 1);
	EEG.pnts   = size(EEG.data, 2);
	EEG.trials = 1;
	EEG.srate  = srate;
	EEG = eeg_checkset(EEG);
	EEG.event = events(1:counte-1);	
	EEG = eeg_checkset( EEG, 'eventconsistency' );
	EEG = pop_editeventvals( EEG, 'sort', { 'latency', [0] } );
    
% $$$ 
% $$$ 
% $$$ 
% $$$ 
% $$$ 
% $$$ 
% $$$ 
% $$$ 
% $$$ 
% $$$ 
% $$$ 
% $$$ 
% $$$ 
% $$$ 
% $$$ dsffd
% $$$         
% $$$ 	% find electrode indices
% $$$ 	% ----------------------
% $$$ 	indices = [];
% $$$ 	for index = 1:length(colnames)
% $$$ 		if strcmp( colnames{index}(1:2), 'ch')
% $$$ 			indices = [indices index ];
% $$$ 		end
% $$$ 	end
% $$$     
% $$$     EEG.data = tmpdata(indices,:);
% $$$     EEG.nbchan = size(EEG.data, 1);
% $$$     EEG.srate  = srate;
% $$$     try
% $$$         eventindices = setdiff_bc(1:length(colnames), indices);
% $$$         ISIind = eventindices(3 + 9);
% $$$         eventindices(3 + [ 1 2 3 4 7 8 9 10 11 12]) = [];
% $$$         eventindices(1:3) = []; % suppress these event 
% $$$         
% $$$         % add the trial number
% $$$         % --------------------
% $$$         tmptrial = find( diff(tmpdata(ISIind, :)) ~= 0);
% $$$         tmptrial = tmptrial+1;
% $$$         
% $$$         % process events
% $$$         % --------------
% $$$         fprintf('Pop_loadbci: importing events...\n');
% $$$         counte = 1; % event counter
% $$$         events(10000).latency = 0;
% $$$         for index = eventindices
% $$$             counttrial = 1;
% $$$             tmpevent = find( diff(tmpdata(index, :)) ~= 0);
% $$$             tmpevent = tmpevent+1;
% $$$             for tmpi = tmpevent
% $$$                 if tmpdata(index, tmpi)
% $$$                     events(counte).type    = [ colnames{index} int2str(tmpdata(index, tmpi)) ];
% $$$                     events(counte).latency = tmpi;
% $$$                     %events(counte).value   = tmpdata(index, tmpi);
% $$$                     %while tmpi > tmptrial(counttrial) & counttrial < length(tmptrial)
% $$$                     %	counttrial = counttrial+1;
% $$$                     %end
% $$$                     %events(counte).trial = counttrial;				
% $$$                     counte = counte+1;
% $$$                     %if mod(counte, 100) == 0, fprintf('%d ', counte); end
% $$$                 end
% $$$             end
% $$$         end
% $$$ 	
% $$$         % add up or down events
% $$$         % ---------------------
% $$$         EEG = eeg_checkset(EEG);
% $$$         EEG.event = events(1:counte-1);	
% $$$         EEG = pop_editeventvals( EEG, 'sort', { 'latency', [0] } );
% $$$         for index=1:length(EEG.event)
% $$$             if strcmp(EEG.event(index).type(1:6), 'Target')
% $$$                 targetcode = str2num(EEG.event(index).type(end));
% $$$                 if targetcode == 1
% $$$                     EEG.event(index).type = 'toptarget';
% $$$                 else
% $$$                     EEG.event(index).type = 'bottomtarget';
% $$$                 end
% $$$             else 
% $$$                 if strcmp(EEG.event(index).type(1:6), 'Result')
% $$$                     resultcode = str2num(EEG.event(index).type(end));
% $$$                     if resultcode == 1
% $$$                         EEG.event(index).type = 'topresp';
% $$$                     else
% $$$                         EEG.event(index).type = 'bottomresp';
% $$$                     end
% $$$                     EEG.event(end+1).latency = EEG.event(index).latency;
% $$$                     if (resultcode == targetcode) 
% $$$                         EEG.event(end).type = 'correct';
% $$$                     else
% $$$                         EEG.event(end).type = 'miss';
% $$$                     end
% $$$                 end
% $$$             end
% $$$         end
% $$$         EEG = pop_editeventvals( EEG, 'sort', { 'latency', [0] } );
% $$$         %EEG.data = tmpdata([72 73 75],:);
% $$$     catch, disp('Failed to import data events');
% $$$     end
% $$$ 
% $$$ command = sprintf('EEG = pop_loadbci(''%s'', %f);',filename, srate); 
% $$$ return;
