% EEG_EPOCHFORMAT - Convert the epoch information of a dataset from struct
%                     to array or vice versa.
%
% Usage: >> [epochsout fields] = eeg_epochformat( epochs, 'format', fields, events );
%
% Input:
%   epochs - epoch numerical or cell array or epoch structure
%   format - ['struct'|'array'] convert epoch array to structure and epoch
%            structure to array.
%   fields - [optional] cell array of strings containing the names of
%            the epoch struct fields. If this field is empty, it uses the
%            following list for the names of the fields { 'var1' 'var2' ... }.
%            For structure conversion, this field helps export a given
%            event type. If this field is left empty, the time locking
%            event for each epoch is exported.
%   events - numerical array of event indices associated with each epoch.
%            For array conversion, this field is ignored.
%
% Outputs:
%   epochsout - output epoch array or structure
%   fields    - output cell array with the name of the fields
%
% Epoch format:
%   struct - Epoch information is organised as an array of structs
%   array  - Epoch information is organised as an 2-d array of numbers, 
%            each column representing a user-defined variable (the 
%            order of the variable is a function of its order in the 
%            struct format).
%
% Note: 1) The epoch structure is defined only for epoched data.
%       2) The epoch 'struct' format is more comprehensible.
%          For instance, to see all the properties of epoch i,
%          type >> EEG.epoch(i)
%          Unfortunately, structures are awkward for expert users to deal
%          with from the command line (Ex: To get an array of 'var1' values,
%           >> celltomat({EEG.epoch(:).var1})')
%          In array format, assuming 'var1' is the first variable
%          declared, the same information is obtained by
%           >> EEG.epoch(:,1)
%       3) This function automatically updates the 'epochfields'
%          cell array depending on the format.
%
% Author: Arnaud Delorme, CNL / Salk Institute, 12 Feb 2002
%
% See also: EEGLAB

%123456789012345678901234567890123456789012345678901234567890123456789012

% Copyright (C) Arnaud Delorme, CNL / Salk Institute, 12 Feb 2002, 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.

% $Log: eeg_epochformat.m,v $
% Revision 1.4  2005/05/24 16:57:09  arno
% cell2mat
%
% Revision 1.3  2003/07/20 19:32:20  scott
% typos
%
% Revision 1.2  2002/04/21 01:10:35  scott
% *** empty log message ***
%
% Revision 1.1  2002/04/05 17:32:13  jorn
% Initial revision
%

% 03/13/02 added field arrays options -ad

function [ epoch, fields, epocheventout] = eeg_epochformat( epoch, format, fields, epochevent);

if nargin < 2
   help eeg_epochformat;
   return;
end;	

if nargin < 3
    fields = {};
end
epocheventout = [];
    
switch format
case 'struct'
   if ~isempty(epoch) && ~isstruct(epoch)

      fields = getnewfields( fields, size(epoch,2) - length(fields));   
       
      % generate the structure
      % ----------------------
      command = 'epoch = struct(';
      for index = 1:length(fields)
          if iscell(epoch)
              command = [ command '''' fields{index} ''', epoch(:,' num2str(index) ')'',' ];
          else
              command = [ command '''' fields{index} ''', mattocell( epoch(:,' num2str(index) ')'',' ...
                            '[1], ones(1,size(epoch,1))),' ];
          end;                  
      end
      eval( [command(1:end-1) ');' ] );

      if exist('epochevent') == 1
         for index = 1:size(epoch,2)
             if iscell(epochevent)
                 epoch(index).event = epochevent{index};
             else
                 epoch(index).event = epochevent(index);
             end
         end
      end
   end

case 'array'
    if isstruct(epoch)
        
        % note that the STUDY std_maketrialinfo also gets the epoch info for the
        % time locking event
        
        selectedType = fields;
        if iscell(fields) && ~isempty(fields), selectedType = fields{1}; end
  	    fields = fieldnames( epoch );
        
        eval( [ 'values = { epoch.' fields{1} ' };' ]);
        
        if any(cellfun(@length, values) > 1)
            if ~isfield(epoch, 'eventlatency')
                error('eventlatency field not present in data epochs');
            end
            
            if isempty(selectedType)
                % find indices of time locking events
                for index = 1:length(epoch)
                    epochlat = [ epoch(index).eventlatency{:} ];
                    tmpevent = find( abs(epochlat) < 0.02 );
                    if isempty(tmpevent)
                        error('time locking event missing, cannot convert to array');
                    end
                    epochSubIndex(index) = tmpevent;
                end
            else
                % find indices of specific event type (if several take the
                % first one
                for index = 1:length(epoch)
                    epochtype = epoch(index).eventtype;
                    tmpeventind = strmatch( selectedType, epochtype );
                    if length(tmpeventind) > 1
                        fprintf('Warning: epoch %d has several events of "type" %s, taking the fist one\n', index, selectedType);
                    end
                    if isempty(tmpeventind)
                         epochSubIndex(index) = NaN;
                    else epochSubIndex(index) = tmpeventind(1);
                    end
                end
            end
        else
            epochSubIndex = ones(1, length(epoch));
        end
        
        % copy values to array
        tmp = cell( length(epoch), length( fields ));
        for index = 1:length( fields )
            for trial = 1:length(epoch)
                tmpval = getfield(epoch, {trial}, fields{index});
                if isnan(epochSubIndex(trial))
                     tmp(trial, index) = { NaN };
                elseif iscell(tmpval)
                     tmp(trial, index) = tmpval(epochSubIndex(trial));
                elseif ~ischar(tmpval)
                     tmp(trial, index) = { tmpval(epochSubIndex(trial)) };
                else tmp(trial, index) = { tmpval };
                end
            end
        end
        epoch = tmp;
    end
    otherwise, error('unrecognised format');   
end

return;

% create new field names
% ----------------------
function epochfield = getnewfields( epochfield, nbfields )
   count = 1;
   if nbfields > 0
        while nbfields > 0
            if isempty( strmatch([ 'var' int2str(count) ], epochfield ) )
               epochfield =  { epochfield{:} [ 'var' int2str(count) ] };
               nbfields = nbfields-1;
            else    count = count+1;
            end
        end;                        
   else
        epochfield = epochfield(1:end+nbfields);
   end;     
return;

