% NEWCROSSF - Returns estimates and plots event-related coherence (ERCOH) 
%        between two input data time series. A lower panel (optionally) shows 
%        the coherence phase difference between the processes. In this panel: 
%        In the plot output by   > newcrossf(x,y,...);
%            90 degrees (orange) means x leads y by a quarter cycle.
%           -90 degrees (blue)   means y leads x by a quarter cycle.
%        Click on any subplot to view separately and zoom in/out.
%
% Function description:
%        Uses EITHER fixed-window, zero-padded FFTs (fastest) OR constant-Q 
%        0-padded wavelet DFTs (more even sensitivity across frequencies), 
%        both Hanning-tapered.  Output frequency spacing is the lowest 
%        frequency ('srate'/'winsize') divided by the 'padratio'.
%
%        If an 'alpha' value is given, then bootstrap statistics are 
%        computed (from a distribution of 'naccu' (200) surrogate baseline
%        data epochs) for the baseline epoch, and non-significant features 
%        of the output plots are zeroed (and shown in green). The baseline
%        epoch is all windows with center latencies < the given 'baseline' value 
%        or, if 'baseboot' is 1, the whole epoch. 
%
% Usage with single dataset:
%        >> [coh,mcoh,timesout,freqsout,cohboot,cohangles,...
%                  allcoher,alltfX,alltfY] = newcrossf(x,y,frames,tlimits,srate, ...
%                                        cycles, 'key1', 'val1', 'key2', val2' ...);
%
% Example to compare two condition (coh. comp 1-2 EEG versus ALLEEG(2)):
%        >> [coh,mcoh,timesout,freqsout,cohboot,cohangles,...
%                  allcoher,alltfX,alltfY] = newcrossf({EEG.icaact(1,:,:) ...
%                  ALLEEG(2).icaact(1,:,:)},{{EEG.icaact(2,:,:) ...
%                  ALLEEG(2).icaact(2,:,:)}},frames,tlimits,srate, ...
%                                        cycles, 'key1', 'val1', 'key2', val2' ...);
%
% Required inputs:
%       x       = First single-channel data set (1,frames*nepochs)      
%                 Else, cell array {x1,x2} of two such data vectors to also
%                 estimate (significant) coherence differences between two 
%                 conditions.
%       y       = Second single-channel data set (1,frames*nepochs)     
%                 Else, cell array {y1,y2} of two such data vectors.
%       frames  = Frames per epoch                                   {750}
%       tlimits = [mintime maxtime] (ms) Epoch latency limits  {[-1000 2000]}
%       srate   = Data sampling rate (Hz)                            {250}
%       cycles  = 0  -> Use FFTs (with constant window length) 
%               = >0 -> Number of cycles in each analysis wavelet 
%               = [cycles expfactor] -> if 0 < expfactor < 1,  the number 
%                 of wavelet cycles expands with frequency from cycles
%                 If expfactor = 1, no expansion; if = 0, constant
%                 window length (as in FFT)            {default cycles: 0}
%
%    Optional Coherence Type:
%       'type'  = ['coher'|'phasecoher'|'amp'] Compute either linear coherence
%                 ('coher'), phase coherence ('phasecoher') also known
%                 as phase coupling factor', or amplitude correlations ('amp')
%                 {default: 'phasecoher'}. Note that for amplitude correlation,
%                 the significance threshold is computed using the corrcoef
%                 function, so can be set arbitrary low without increase in
%                 computation load. An additional type is 'crossspec' to compute
%                 cross-spectrum between 2 processes (single-trial). This type
%                 is automatically selected if user enter continuous data.
%       'amplag' = [integer vector] allow to compute non 0 amplitude correlation 
%                 (using option 'amp' above). The vector given as parameter 
%                 indicates the point lags ([-4 -2 0 2 4] would compute the 
%                 correlation at time t-4, t-2, t, t+2, t+4, and return the 
%                 maximum correlation at these points).
%       'subitc' = ['on'|'off'] Subtract stimulus locked Inter-Trial Coherence 
%                 from x and y. This computes the  'intrinsic' coherence
%                 x and y not arising from common synchronization to 
%                 experimental events. For cell array input, one may provide
%                 a cell array ({'on','off'} for example). {default: 'off'}
%       'shuffle' = Integer indicating the number of estimates to compute
%                 bootstrap coherence based on shuffled trials. This estimates
%                 the coherence arising only from time locking of x and y
%                 to experimental events (opposite of 'subitc'). For cell array 
%                 input, one may provide a cell array, for example { 1 0 }.
%                 { default 0: no shuffling }.
%
%    Optional Detrend:
%       'detrend'   = ['on'|'off'], Linearly detrend each data epoch   {'off'}
%       'rmerp'     = ['on'|'off'], Remove epoch mean from data epochs {'off'}
%
%    Optional FFT/DFT:
%       'winsize'   = If cycles==0: data subwindow length (fastest, 2^n<frames);
%                     if cycles >0: *longest* window length to use. This
%                     determines the lowest output frequency  {~frames/8}
%       'timesout'  = Number of output latencies (int<frames-winframes). {200) 
%                     A negative value (-S) subsamples the original latencies 
%                     by S. An array of latencies computes spectral 
%                     decompositions at specific latency values (Note: the 
%                     algorithm finds the closest latencies in the data, 
%                     possibly resulting in slightly unevenly spaced 
%                     output latencies. 
%       'padratio'  = FFT-length/winframes (2^k)                    {2}
%                     Multiplies the number of output frequencies by dividing
%                     their spacing (standard FFT padding). When cycles~=0, 
%                     frequency spacing is divided by padratio.
%       'maxfreq'   = Maximum frequency (Hz) to plot (& output if cycles>0) 
%                     If cycles==0, all FFT frequencies are output.{def: 50}
%                     Note: NOW DEPRECATED, use 'freqs' instead,
%       'freqs'     = [min max] Frequency limits. {Default: [minfreq 50],
%                     minfreq being determined by the number of data points, 
%                     cycles and sampling frequency}.
%       'nfreqs'    = Number of output frequencies. For FFT, closest computed
%                     frequency will be returned. Overwrite 'padratio' effects
%                     for wavelets. {Default: use 'padratio'}.
%       'freqscale' = ['log'|'linear'] Frequency scaling. {Default: 'linear'}.
%                     Note that for obtaining 'log' spaced freqs using FFT, 
%                     closest correspondent frequencies in the 'linear' space 
%                     are returned.
%       'baseline'  = Spectral baseline end-time (in ms). NaN imply that no
%                      baseline is used. A range [min max] may also be entered
%                     You may also enter one row per region for baseline
%                     e.g. [0 100; 300 400] considers the window 0 to 100 ms and
%                     300 to 400 ms. This is only valid for the coherence amplitude
%                     not for the coherence phase. { default NaN }
%       'lowmem'    = ['on'|'off'] {'off'} Compute frequency by frequency to 
%                     save memory. 
%
%    Optional Bootstrap:
%       'alpha'    = If non-0, compute two-tailed bootstrap significance prob.
%                    level. Show non-signif output values in neutral green. {0}
%       'naccu'    = Number of bootstrap replications to compute {200}
%       'boottype' = ['shuffle'|'shufftrials'|'rand'|'randall'] Bootstrap type: Either 
%                    shuffle time and trial windows ('shuffle' default) or trials only 
%                    using a separate  bootstrap for each time window ('shufftrials'). 
%                    Option 'rand' randomize the phase. Option 'randall' randomize the 
%                    phase for each individual time/frequency point.
%       'baseboot'  = Bootstrap baseline subtract (1 -> use 'baseline'; Default
%                                                  0 -> use whole trial
%                                                  [min max] -> use time range)
%                     Default is to use the baseline unless no baseline is
%                     specified (then the function uses all sample up to time 0)
%                     You may also enter one row per region for baseline
%                     e.g. [0 100; 300 400] considers the window 0 to 100 ms and
%                     300 to 400 ms.
%       'condboot' = ['abs'|'angle'|'complex'] In comparing two conditions,
%                    either subtract complex spectral values' absolute vales 
%                    ('abs'), angles ('angles') or the complex values themselves
%                    ('complex').     {default: 'abs'}
%       'rboot'    = Input bootstrap coherence limits (e.g., from NEWCROSSF) 
%                    The bootstrap type should be identical to that used
%                    to obtain the input limits. {default: compute from data}
% Optional scalp map plot:
%       'topovec'  = (2,nchans) matrix. Scalp maps to plot {[]}
%                    ELSE [c1,c2], plot two cartoons showing channel locations.
%       'elocs'    = Electrode location file for scalp map       {none}
%                    File should be ascii in format of >> topoplot example   
%       'chaninfo' = Electrode location additional information (nose position...)
%                    {default: none}
%
% Optional plot and compute features:
%       'plottype'  = ['image'|'curve'] plot time frequency images or
%                     curves (one curve per frequency). Default is 'image'.
%       'plotmean'  = ['on'|'off'] For 'curve' plots only. Average all
%                     frequencies given as input. Default: 'on'.
%       'highlightmode'  = ['background'|'bottom'] For 'curve' plots only,
%                     display significant time regions either in the plot background
%                     or underneatht the curve.
%       'plotamp'   = ['on'|'off']. Plot coherence magnitude       {'on'}
%       'maxamp'    = [real] Set the maximum for the amplitude scale {auto}
%       'plotphase' = ['on'|'off']. Plot coherence phase angle     {'on'}
%       'angleunit' = Phase units: 'ms' for msec or 'deg' for degrees or 'rad' 
%                     for radians {'deg'}
%       'title'     = Optional figure title. If two conditions are given
%                     as input, title can be a cell array with two text
%                     string elements {none}
%       'vert'      = Latencies to mark with a dotted vertical line   {none}
%       'linewidth' = Line width for marktimes traces (thick=2, thin=1) {2}
%       'newfig'    = ['on'|'off'] Create new figure for difference plots {'on'}
%       'axesfont'  = Axes font size                               {10}
%       'titlefont' = Title font size                              {8}
%
% Outputs: 
%       coh         = Matrix (nfreqs,timesout) of coherence magnitudes. Not
%                     that for continuous data, the function is returning the
%                     cross-spectrum.
%       mcoh        = Vector of mean baseline coherence at each frequency
%                     see 'baseline' parameter.
%       timesout    = Vector of output latencies (window centers) (ms).
%       freqsout    = Vector of frequency bin centers (Hz).
%       cohboot     = Matrix (nfreqs) of upper coher signif. limits
%                     if 'boottype' is 'trials',  (nfreqs,timesout)
%       cohangle    = (nfreqs,timesout) matrix of coherence angles in radian
%       allcoher    = single trial coherence
%       alltfX      = single trial spectral decomposition of X
%       alltfY      = single trial spectral decomposition of Y
%
% Plot description:
%   Assuming both 'plotamp' and 'plotphase' options are 'on' (=default), the upper panel
%   presents the magnitude of either phase coherence or linear coherence, depending on 
%   the 'type' parameter (above). The lower panel presents the coherence phase difference 
%   (in degrees). Click on any plot to pop up a new window (using 'AXCOPY').
%   -- The upper left marginal panel shows mean coherence during the baseline period
%      (blue), and when significance is set, the significance threshold (dotted black-green).
%   -- The horizontal panel under the coherence magnitude image indicates the maximum 
%      (green) and minimum (blue) coherence values across all frequencies. When significance 
%      is set (using option 'trials' for 'boottype'), an additional curve indicates the 
%      significance threshold (dotted black-green).
%
% Notes: 1) When cycles==0, nfreqs is total number of FFT frequencies.
%        2) 'blue' coherence lag -> x leads y; 'red' -> y leads x
%        3) The 'boottype' should be ideally 'timestrials', but this creates 
%           large memory demands, so 'times' must be used in many cases.
%        4) If 'boottype' is 'trials', the average of the complex bootstrap
%           is subtracted from the coherence to compensate for phase differences
%           (the average is also subtracted from the bootstrap distribution). 
%           For other bootstraps, this is not necessary since there the phase 
%           distribution should be random.
%        5) If baseline is non-NaN, the baseline is subtracted from
%           the complex coherence. On the left hand side of the coherence
%           amplitude image, the baseline is displayed as a magenta line.
%           (If no baseline is selected, this curve represents the average
%           coherence at every given frequency).
%
% Authors: Arnaud Delorme, Sigurd Enghoff & Scott Makeig
%          CNL/Salk Institute 1998-2001; SCCN/INC/UCSD, La Jolla, 2002-
%
% See also: TIMEF

% NOTE: one hidden parameter 'savecoher', 0 or 1

% Copyright (C) 8/1/98  Arnaud Delorme, Sigurd Enghoff & Scott Makeig, SCCN/INC/UCSD
%
% 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.

% 11-20-98 defined g.linewidth constant -sm
% 04-01-99 made number of frequencies consistent -se
% 06-29-99 fixed constant-Q freq indexing  -se 
% 08-13-99 added cohangle plotting -sm
% 08-20-99 made bootstrap more efficient -sm
% 08-24-99 allow nan values introduced by possible EVENTLOCK preproc. -sm
% 03-16-00 added lead/lag interpretation to help msg - sm & eric visser
% 03-16-00 added AXCOPY feature -sm & tpj
% 04-20-00 fixed Rangle sign for wavelets, added verts array -sm
% 01-22-01 corrected help msg when nargin<2 -sm & arno delorme
% 01-25-02 reformated help & license, added links -ad 
% 03-09-02 function restructuration -ad
%  add 'key', val arguments (+ external baseboot, baseline, color axis, angleunit...)
%  add detrending (across time and trials) + 'coher' option for amplitude coherence
%  significance only if alpha is given, plotting options in 'plotamp' and 'plotphase'
% 03-16-02 timeout automatically adjusted if too high -ad 
% 04-03-02 added new options for bootstrap -ad 

% There are 3 "objects" Tf, Coher and Boot which are handled
% - by specific functions under Matlab
%    (Tf) function Tf = tfinit(...) - create object Time Frequency (Tf) associated with some data
%    (Tf) function [Tf, itcvals] = tfitc(...) - compute itc for the selected data
%    (Tf) function [Tf, itcvals] = tfitcpost(Tf, trials) - itc normalisation 
%    (Tf) function [Tf, tmpX] = tfcomp(Tf, trials, times) - compute time freq. decomposition
%    (Coher) function Coher = coherinit(...) - initialize coherence object
%    (Coher) function Coher = cohercomp(Coher, tmpX, tmpY, trial, time) - compute coherence
%    (Coher) function Coher = cohercomppost(Coher, trials) - coherence normalization
%    (Boot) function Boot = bootinit(...) - initialize bootstrap object
%    (Boot) function Boot = bootcomp(...) - compute bootstrap
%    (Boot) function [Boot, Rbootout] = bootcomppost(...) - bootstrap normalization
% - by real objects under C++ (see C++ code)

function [R,mbase,timesout,freqs,Rbootout,Rangle, coherresout, alltfX, alltfY] = newcrossf(X, Y, frame, tlimits, Fs, varwin, varargin)

%varwin,winsize,nwin,oversmp,maxfreq,alpha,verts,caxmax)

% Commandline arg defaults:
DEFAULT_ANGLEUNITS = 'deg';     % angle plotting units - 'ms' or 'deg'
DEFAULT_EPOCH	= 750;			% Frames per epoch
DEFAULT_TIMELIM = [-1000 2000];	% Time range of epochs (ms)
DEFAULT_FS		= 250;			% Sampling frequency (Hz)
DEFAULT_NWIN	= 200;			% Number of windows = horizontal resolution
DEFAULT_VARWIN	= 0;			% Fixed window length or base on cycles.
% =0: fix window length to nwin
% >0: set window length equal varwin cycles
%     bounded above by winsize, also determines
%     the min. freq. to be computed.
DEFAULT_OVERSMP	= 2;			% Number of times to oversample = vertical resolution
DEFAULT_MAXFREQ = 50;			% Maximum frequency to display (Hz)
DEFAULT_TITLE	= 'Event-Related Coherence';			% Figure title
DEFAULT_ALPHA   = NaN;			% Default two-sided significance probability threshold

%disp('WARNING: this function is not part of the EEGLAB toolbox and should not be distributed');
%disp('         you must contact Arnaud Delorme (arno@salk.edu) for terms of use');

if (nargin < 2)
   help newcrossf
   return
end
coherresout = [];

if ~iscell(X)
	if (min(size(X))~=1 || length(X)<2)
		fprintf('crossf(): x must be a row or column vector.\n');
		return
	elseif (min(size(Y))~=1 || length(Y)<2)
		fprintf('crossf(): y must be a row or column vector.\n');
		return
	elseif (length(X) ~= length(Y))
		fprintf('crossf(): x and y must have same length.\n');
		return
	end
end

if (nargin < 3)
   frame = DEFAULT_EPOCH;
elseif (~isnumeric(frame) || length(frame)~=1 || frame~=round(frame))
   fprintf('crossf(): Value of frames must be an integer.\n');
   return
elseif (frame <= 0)
   fprintf('crossf(): Value of frames must be positive.\n');
   return
elseif ~iscell(X) && (rem(size(X,2),frame) ~= 0) && (rem(size(X,1),frame) ~= 0)
   fprintf('crossf(): Length of data vectors must be divisible by frames.\n');
   return
end

if (nargin < 4)
   tlimits = DEFAULT_TIMELIM;
elseif (~isnumeric(tlimits) || sum(size(tlimits))~=3)
   error('crossf(): Value of tlimits must be a vector containing two numbers.');
elseif (tlimits(1) >= tlimits(2))
   error('crossf(): tlimits interval must be [min,max].');
end

if (nargin < 5)
   Fs = DEFAULT_FS;
elseif (~isnumeric(Fs) || length(Fs)~=1)
   error('crossf(): Value of srate must be a number.');
elseif (Fs <= 0)
   error('crossf(): Value of srate must be positive.');
end

if (nargin < 6)
   varwin = DEFAULT_VARWIN;
elseif (~isnumeric(varwin) || length(varwin)>2)
   error('crossf(): Value of cycles must be a number or a (1,2) vector.');
elseif (varwin < 0)
   error('crossf(): Value of cycles must be either zero or positive.');
end

% consider structure for these arguments
% --------------------------------------
vararginori = varargin;
for index=1:length(varargin)
	if iscell(varargin{index}), varargin{index} = { varargin{index} }; end
end
if ~isempty(varargin)
    [tmp indices] = unique_bc(varargin(1:2:end)); % keep the first one
    varargin = varargin(sort(union(indices*2-1, indices*2))); % these 2 line remove duplicate arguments    
    try, g = struct(varargin{:}); 
    catch, error('Argument error in the {''param'', value} sequence'); end; 
else 
	g = [];
end

try, g.condboot;   catch, g.condboot = 'abs'; end
try, g.shuffle;    catch, g.shuffle = 0; end
try, g.title;      catch, g.title = DEFAULT_TITLE; end
try, g.winsize;    catch, g.winsize = max(pow2(nextpow2(frame)-3),4); end
try, g.pad;        catch, g.pad = max(pow2(nextpow2(g.winsize)),4); end
try, g.timesout;   catch, g.timesout = DEFAULT_NWIN; end
try, g.padratio;   catch, g.padratio = DEFAULT_OVERSMP; end
try, g.topovec;    catch, g.topovec = []; end
try, g.elocs;      catch, g.elocs = ''; end
try, g.alpha;      catch, g.alpha = DEFAULT_ALPHA; end;  
try, g.marktimes;  catch, g.marktimes = []; end; % default no vertical lines
try, g.marktimes = g.vert;       catch, g.vert = []; end; % default no vertical lines
try, g.rboot;      catch, g.rboot = []; end
try, g.plotamp;    catch, g.plotamp = 'on'; end
try, g.plotphase;  catch, g.plotphase  = 'on'; end
try, g.plotbootsub;  catch, g.plotbootsub  = 'on'; end
try, g.detrend;    catch, g.detrend = 'off'; end
try, g.rmerp;      catch, g.rmerp = 'off'; end
try, g.baseline;   catch, g.baseline = NaN; end
try, g.baseboot;   catch, g.baseboot = 1; end
try, g.linewidth;  catch, g.linewidth = 2; end
try, g.maxfreq;    catch, g.maxfreq = DEFAULT_MAXFREQ; end
try, g.freqs;      catch, g.freqs = [0 g.maxfreq]; end
try, g.nfreqs;     catch, g.nfreqs = []; end
try, g.freqscale;  catch, g.freqscale = 'linear'; end
try, g.naccu;      catch, g.naccu = 200; end
try, g.angleunit;  catch, g.angleunit = DEFAULT_ANGLEUNITS; end
try, g.type;       catch, g.type = 'phasecoher'; end; 
try, g.newfig;     catch, g.newfig = 'on'; end
try, g.boottype;   catch, g.boottype = 'shuffle'; end; 
try, g.subitc;     catch, g.subitc = 'off'; end
try, g.compute;    catch, g.compute = 'matlab'; end
try, g.maxamp;     catch, g.maxamp = []; end
try, g.savecoher;  catch, g.savecoher = 0; end
try, g.amplag;     catch, g.amplag = 0; end
try, g.noinput;    catch, g.noinput = 'no'; end
try, g.lowmem;     catch, g.lowmem = 'off'; end
try, g.plottype;   catch, g.plottype = 'image'; end
try, g.plotmean;   catch, g.plotmean = 'on'; end
try, g.highlightmode;   catch, g.highlightmode = 'background'; end
try, g.chaninfo;   catch, g.chaninfo = []; end

if isfield(g, 'detret'), g.detrend = g.detret; end
if isfield(g, 'detrep'), g.rmerp   = g.detrep; end
if ~isnan(g.alpha) && frame == length(X)
    error('Cannot compute significance for continuous data (functionality not implemented)');
end
    
allfields = fieldnames(g);
for index = 1:length(allfields)
	switch allfields{index}
	 case { 'shuffle' 'title' 'winsize' 'pad' 'timesout' 'padratio' 'maxfreq' 'topovec' 'elocs' 'alpha' ...
		  'marktimes' 'vert' 'rboot' 'plotamp' 'plotphase' 'plotbootsub' 'detrep' 'rmerp' 'detret' 'detrend' ...
		  'baseline' 'baseboot' 'linewidth' 'naccu' 'angleunit' 'type' 'boottype' 'subitc' 'lowmem' 'plottype' ...
		  'compute' 'maxamp' 'savecoher' 'noinput' 'condboot' 'newfig' 'freqs' 'nfreqs' 'freqscale' 'amplag' ...
          'highlightmode' 'plotmean' 'chaninfo' };
	  case {'plotersp' 'plotitc' }, disp(['crossf warning: timef option ''' allfields{index} ''' ignored']);
	 otherwise disp(['crossf error: unrecognized option ''' allfields{index} '''']); beep; return;
	end
end

g.tlimits = tlimits;
g.frame = frame;
if ~iscell(X)
    g.trials = prod(size(X)) / g.frame;
else          g.trials = prod(size(X{1}))/g.frame;
end
g.srate   = Fs;
g.cycles  = varwin;
g.type       = lower(g.type);
g.boottype   = lower(g.boottype);
g.rmerp     = lower(g.rmerp);
g.detrend     = lower(g.detrend);
g.plotphase  = lower(g.plotphase);
g.plotbootsub = lower(g.plotbootsub);
g.subitc     = lower(g.subitc);
g.plotamp    = lower(g.plotamp);
g.compute    = lower(g.compute);
g.AXES_FONT  = 10;
g.TITLE_FONT = 14;

% change type if necessary
if g.trials == 1 && ~strcmpi(g.type, 'crossspec')
    disp('Continuous data: switching to crossspectrum');
    g.type = 'crossspec';
end
if strcmpi(g.freqscale, 'log') && g.freqs(1) == 0, g.freqs(1) = 3; end

% reshape 3D inputs
% -----------------
if ndims(X) == 3
    X = reshape(X, size(X,1), size(X,2)*size(X,3));
    Y = reshape(Y, size(Y,1), size(Y,2)*size(Y,3));
end

% testing arguments consistency
% -----------------------------
if strcmpi(g.title, DEFAULT_TITLE)
    switch g.type
     case 'coher',       g.title	= 'Event-Related Coherence';			% Figure title
     case 'phasecoher',  g.title	= 'Event-Related Phase Coherence';		
     case 'phasecoher2', g.title	= 'Event-Related Phase Coherence 2';			
     case 'amp'  ,       g.title	= 'Event-Related Amplitude Correlation';		
     case 'crossspec',   g.title	= 'Event-Related Amplitude Correlation';		
    end
end

if ~ischar(g.title) && ~iscell(g.title) 
   error('Title must be a string or a cell array.');
end

if isempty(g.topovec)
   g.topovec = [];
elseif min(size(g.topovec))==1
   g.topovec = g.topovec(:);
   if size(g.topovec,1)~=2
      error('topovec must be a row or column vector.');
   end
end

if isempty(g.elocs)
   g.elocs = '';
elseif (~ischar(g.elocs)) && ~isstruct(g.elocs)
   error('Channel location file must be a valid text file.');
end

if (~isnumeric(g.alpha) || length(g.alpha)~=1)
   error('timef(): Value of g.alpha must be a number.\n');
elseif (round(g.naccu*g.alpha) < 2)
   fprintf('Value of g.alpha is out of the normal range [%g,0.5]\n',2/g.naccu);
   g.naccu = round(2/g.alpha);
   fprintf('  Increasing the number of bootstrap iterations to %d\n',g.naccu);
end
if g.alpha>0.5 || g.alpha<=0
   error('Value of g.alpha is out of the allowed range (0.00,0.5).');
end
switch lower(g.newfig)
    case { 'on', 'off' }, ;
    otherwise error('newfig must be either on or off');
end
switch g.angleunit
case { 'ms', 'deg', 'rad' },;
otherwise error('Angleunit must be either ''deg'', ''rad'', or ''ms''');
end;    
switch g.type
case { 'coher', 'phasecoher' 'phasecoher2' 'amp' 'crossspec' },;
otherwise error('Type must be either ''coher'', ''phasecoher'', ''crossspec'', or ''amp''');
end;    
switch g.boottype
case { 'shuffle' 'shufftrials' 'rand' 'randall'},;
otherwise error('Invalid boot type');
end;    
if ~isnumeric(g.shuffle) && ~iscell(g.shuffle)
   error('Shuffle argument type must be numeric');
end
switch g.compute
case { 'matlab', 'c' },;
otherwise error('compute must be either ''matlab'' or ''c''');
end
if ~strcmpi(g.condboot, 'abs') && ~strcmpi(g.condboot, 'angle') ...
		& ~strcmpi(g.condboot, 'complex')
	error('Condboot must be either ''abs'', ''angle'' or ''complex''.');
end
if g.tlimits(2)-g.tlimits(1) < 30
    disp('Crossf WARNING: time range is very small (<30 ms). Times limits are in milliseconds not seconds.'); 
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% compute frequency by frequency if low memory
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if strcmpi(g.lowmem, 'on') && ~iscell(X) && length(X) ~= g.frame && (isempty(g.nfreqs) || g.nfreqs ~= 1)
    
    % compute for first 2 trials to get freqsout
    XX = reshape(X, 1, frame, length(X)/g.frame);    
    YY = reshape(Y, 1, frame, length(Y)/g.frame);    
    [coh,mcoh,timesout,freqs] = newcrossf(XX(1,:,1), YY(1,:,1), frame, tlimits, Fs, varwin, 'plotamp', 'off', 'plotphase', 'off',varargin{:});
    
    % scan all frequencies
    for index = 1:length(freqs)
        if nargout < 6
            [R(index,:),mbase(index),timesout,tmpfreqs(index),Rbootout(index,:),Rangle(index,:)] = ...
                newcrossf(X, Y, frame, tlimits, Fs, varwin, 'freqs', [freqs(index) freqs(index)], 'nfreqs', 1, ...
                          'plotamp', 'off', 'plotphase', 'off',varargin{:}, 'lowmem', 'off', 'timesout', timesout);
        elseif nargout == 7 % requires RAM
            [R(index,:),mbase(index),timesout,tmpfreqs(index),Rbootout(index,:),Rangle(index,:), ...
             coherresout(index,:,:)] = ...
                newcrossf(X, Y, frame, tlimits, Fs, varwin, 'freqs', [freqs(index) freqs(index)], 'nfreqs', 1, ...
                          'plotamp', 'off', 'plotphase', 'off',varargin{:}, 'lowmem', 'off', 'timesout', timesout);
        else
            [R(index,:),mbase(index),timesout,tmpfreqs(index),Rbootout(index,:),Rangle(index,:), ...
             coherresout(index,:,:),alltfX(index,:,:),alltfY(index,:,:)] = ...
                newcrossf(X, Y, frame, tlimits, Fs, varwin, 'freqs', [freqs(index) freqs(index)], 'nfreqs', 1, ...
                          'plotamp', 'off', 'plotphase', 'off',varargin{:}, 'lowmem', 'off', 'timesout', timesout);
        end
    end
    
    % plot and return
    plotall(R.*exp(j*Rangle), Rbootout, timesout, freqs, mbase, g);
    return;
end;    


%%%%%%%%%%%%%%%%%%%%%%%%%%%
% compare 2 conditions part
%%%%%%%%%%%%%%%%%%%%%%%%%%%
if iscell(X)
	if length(X) ~= 2 || length(Y) ~= 2
		error('crossf: to compare conditions, X and Y input must be 2-elements cell arrays');
	end

    % deal with titles
    % ----------------
	for index = length(vararginori)-1:-2:1
		if index<=length(vararginori) % needed: if elements are deleted
			if strcmp(vararginori{index}, 'title') , vararginori(index:index+1) = []; end
			if strcmp(vararginori{index}, 'subitc'), vararginori(index:index+1) = []; end
			if strcmp(vararginori{index}, 'shuffle'), vararginori(index:index+1) = []; end
		end
	end
    if ~iscell(g.subitc)
        g.subitc = { g.subitc g.subitc };
    end
    if ~iscell(g.shuffle)
        g.shuffle = { g.shuffle g.shuffle };
    end
	if iscell(g.title) 
		if length(g.title) <= 2,
			g.title{3} = 'Condition 1 - condition 2';
		end
	else
		g.title = { 'Condition 1', 'Condition 2', 'Condition 1 - condition 2' };
	end
	
	fprintf('Running newcrossf on condition 1 *********************\n');
	fprintf('Note: if an out-of-memory error occurs, try reducing the\n');
	fprintf('      number of time points or number of frequencies\n');
	fprintf('      (the ''coher'' options takes 3 times more memory than other options)\n');
    
	if strcmpi(g.plotamp, 'on') || strcmpi(g.plotphase, 'on')
        if strcmpi(g.newfig, 'on'), figure; end; 
        subplot(1,3,1); 
	end

    if ~strcmp(g.type, 'coher') && nargout < 9
		[R1,mbase,timesout,freqs,Rbootout1,Rangle1, savecoher1] = newcrossf(X{1}, Y{1}, ...
				frame, tlimits, Fs, varwin, 'savecoher', 1, 'title', g.title{1}, ...
                          'shuffle', g.shuffle{1}, 'subitc', g.subitc{1}, vararginori{:});
	else
		[R1,mbase,timesout,freqs,Rbootout1,Rangle1, savecoher1, Tfx1, Tfy1] = newcrossf(X{1}, Y{1}, ...
				frame, tlimits, Fs, varwin, 'savecoher', 1, 'title', g.title{1}, ...
                          'shuffle', g.shuffle{1}, 'subitc', g.subitc{1},  vararginori{:});
	end
	R1 = R1.*exp(j*Rangle1/180*pi);
	
	fprintf('\nRunning newcrossf on condition 2 *********************\n');
	if strcmpi(g.plotamp, 'on') || strcmpi(g.plotphase, 'on')
        subplot(1,3,2);
	end
    if ~strcmp(g.type, 'coher') && nargout < 9
		[R2,mbase,timesout,freqs,Rbootout2,Rangle2, savecoher2] = newcrossf(X{2}, Y{2}, ...
				frame, tlimits, Fs, varwin,'savecoher', 1, 'title', g.title{2}, ...
                            'shuffle', g.shuffle{2}, 'subitc', g.subitc{2}, vararginori{:});
	else
		[R2,mbase,timesout,freqs,Rbootout2,Rangle2, savecoher2, Tfx2, Tfy2] = newcrossf(X{2}, Y{2}, ...
				frame, tlimits, Fs, varwin,'savecoher', 1, 'title', g.title{2}, ...
                            'shuffle', g.shuffle{2}, 'subitc', g.subitc{2}, vararginori{:} );
	end
	%figure; imagesc(abs( sum( savecoher1 ./ abs(savecoher1), 3)) - abs( sum( savecoher2 ./ abs(savecoher2), 3)  )); cbar; return;
	%figure; imagesc(abs( R2 ) - abs( R1)  ); cbar; return;
	R2 = R2.*exp(j*Rangle2/180*pi);
    
    if strcmpi(g.plotamp, 'on') || strcmpi(g.plotphase, 'on')
        subplot(1,3,3);
	end
    if isnan(g.alpha)
        switch(g.condboot)
            case 'abs',  Rdiff = abs(R1)-abs(R2);
            case 'angle',  Rdiff = angle(R1)-angle(R2);
            case 'complex',  Rdiff = R1-R2;
        end
        g.title = g.title{3};
        if strcmpi(g.plotamp, 'on') || strcmpi(g.plotphase, 'on')
            plotall(Rdiff, [], timesout, freqs, mbase, g);
        end
        Rbootout = [];
	else 
		% preprocess data and run condstat
		% --------------------------------
		switch g.type
		 case 'coher' % take the square of alltfx and alltfy first to speed up
		  Tfx1_ = Tfx1.*conj(Tfx1); Tfx2_ = Tfx2.*conj(Tfx2);
		  Tfy1_ = Tfy1.*conj(Tfy1); Tfy2_ = Tfy2.*conj(Tfy2);
		  formula = 'sum(arg1(:,:,X),3) ./ sqrt(sum(arg2(:,:,X),3)) ./ sqrt(sum(arg3(:,:,X),3))';
          if strcmpi(g.lowmem, 'on')
              for ind = 1:2:size(savecoher1,1)
                  if ind == size(savecoher1,1), indarr = ind; else indarr = [ind:ind+1]; end
                  [Rdiff(indarr,:,:) coherimages(indarr,:,:) coher1(indarr,:,:) coher2(indarr,:,:)] = condstat(formula, g.naccu, g.alpha, ...
                      'both', g.condboot, { savecoher1(indarr,:,:) savecoher2(indarr,:,:) }, ...
                     { Tfx1_(indarr,:,:) Tfx2_(indarr,:,:) }, { Tfy1_(indarr,:,:) Tfy2_(indarr,:,:) });
              end
          else
              [Rdiff coherimages coher1 coher2] = condstat(formula, g.naccu, g.alpha, ...
                 'both', g.condboot, { savecoher1 savecoher2 }, { Tfx1_ Tfx2_ }, { Tfy1_ Tfy2_ });
          end
          
         case 'amp' % amplitude correlation
		  error('Cannot compute difference of amplitude correlation images yet');
         
         case 'crossspec' % amplitude correlation
		  error('Cannot compute difference of cross-spectral decomposition');
          
         case 'phasecoher', % normalize first to speed up
		  savecoher1 = savecoher1 ./ sqrt(savecoher1.*conj(savecoher1));
		  savecoher2 = savecoher2 ./ sqrt(savecoher2.*conj(savecoher2)); % twice faster than abs()
		  formula = 'sum(arg1(:,:,X),3) ./ length(X)';
          if strcmpi(g.lowmem, 'on')
              for ind = 1:2:size(savecoher1,1)
                  if ind == size(savecoher1,1), indarr = ind; else indarr = [ind:ind+1]; end
                  [Rdiff(indarr,:,:) coherimages(indarr,:,:) coher1(indarr,:,:) coher2(indarr,:,:)] = condstat(formula, g.naccu, g.alpha, ...
                      'both', g.condboot, { savecoher1(indarr,:,:) savecoher2(indarr,:,:) } );
              end;     
          else
              [Rdiff coherimages coher1 coher2] = condstat(formula, g.naccu, g.alpha, 'both', g.condboot, ...
														   { savecoher1 savecoher2 });
          end
		 case 'phasecoher2',
		  savecoher1 = savecoher1 ./ sqrt(savecoher1.*conj(savecoher1));
		  savecoher2 = savecoher2 ./ sqrt(savecoher2.*conj(savecoher2)); % twice faster than abs()
		  formula = 'sum(arg1(:,:,X),3) ./ sum(sqrt(arg1(:,:,X).*conj(arg1(:,:,X)))),3)'; 
		  % sqrt(a.*conj(a)) is about twice faster than abs()
          if strcmpi(g.lowmem, 'on')
              for ind = 1:2:size(savecoher1,1)
                  if ind == size(savecoher1,1), indarr = ind; else indarr = [ind:ind+1]; end
                  [Rdiff(indarr,:,:) coherimages(indarr,:,:) coher1(indarr,:,:) coher2(indarr,:,:)] = condstat(formula, g.naccu, g.alpha, ...
                      'both', g.condboot, { savecoher1(indarr,:,:) savecoher2(indarr,:,:) } );
              end;     
          else
              [Rdiff coherimages coher1 coher2] = condstat(formula, g.naccu, g.alpha, 'both', g.condboot, ...
														   { savecoher1 savecoher2 });
          end
		end
        
		%Boot = bootinit( [], size(savecoher1,1), g.timesout, g.naccu, 0, g.baseboot, 'noboottype', g.alpha, g.rboot);
		%Boot.Coherboot.R = coherimages;
		%Boot = bootcomppost(Boot, [], [], []);
		g.title = g.title{3};
		g.boottype = 'shufftrials';
        if strcmpi(g.plotamp, 'on') || strcmpi(g.plotphase, 'on')
            plotall(Rdiff, coherimages, timesout, freqs, mbase, g);
        end
        
        % outputs
        Rbootout = {Rbootout1 Rbootout2 coherimages};
	end
    if size(Rdiff,3) > 1, Rdiff = reshape(Rdiff, 1, size(Rdiff,3)); end
    R        = { abs(R1) abs(R2) fastif(isreal(Rdiff), Rdiff, abs(Rdiff)) };
    Rangle   = { angle(R1) angle(R2) angle(Rdiff) };
    coherresout = [];
    if nargout >=9
        alltfX = { Tfx1 Tfx2 };
        alltfY = { Tfy1 Tfy2 };
    end
	return; % ********************************** END FOR SEVERAL CONDITIONS
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% shuffle trials if necessary
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if g.shuffle ~= 0
   fprintf('x and y data trials being shuffled %d times\n',g.shuffle);
   XX = reshape(X, 1, frame, length(X)/g.frame);
   YY = Y;
   X = [];
   Y = [];
   for index = 1:g.shuffle
      XX = shuffle(XX,3);
      X = [X XX(:,:)];
      Y = [Y YY];
   end
end

% detrend over epochs (trials) if requested
% -----------------------------------------
switch g.rmerp
case 'on'
   X = reshape(X, g.frame, length(X)/g.frame);
   X = X - mean(X,2)*ones(1, length(X(:))/g.frame);
   Y = reshape(Y, g.frame, length(Y)/g.frame);
   Y = Y - mean(Y,2)*ones(1, length(Y(:))/g.frame);
end;        

%%%%%%%%%%%%%%%%%%%%%%
% display text to user
%%%%%%%%%%%%%%%%%%%%%%
fprintf('\nComputing the Event-Related \n');
switch g.type
    case 'phasecoher',  fprintf('Phase Coherence (ITC) images based on %d trials\n',g.trials);
    case 'phasecoher2', fprintf('Phase Coherence 2 (ITC) images based on %d trials\n',g.trials);
    case 'coher',       fprintf('Linear Coherence (ITC) images based on %d trials\n',g.trials);
    case 'amp',         fprintf('Amplitude correlation images based on %d trials\n',g.trials);
    case 'crossspec',   fprintf('Cross-spectral images based on %d trials\n',g.trials);
end
if ~isnan(g.alpha)
   fprintf('Bootstrap confidence limits will be computed based on alpha = %g\n', g.alpha);
else
   fprintf('Bootstrap confidence limits will NOT be computed.\n'); 
end
switch g.plotphase
case 'on', fprintf(['Coherence angles will be imaged in ',g.angleunit,'\n']);
end


%%%%%%%%%%%%%%%%%%%%%%%
% main computation loop
%%%%%%%%%%%%%%%%%%%%%%%

% -------------------------------------
% compute time frequency decompositions
% -------------------------------------
if length(g.timesout) > 1, tmioutopt = { 'timesout' , g.timesout };
else                       tmioutopt = { 'ntimesout', g.timesout };
end
spectraloptions = { tmioutopt{:}, 'winsize', g.winsize, 'tlimits', g.tlimits, 'detrend', ...
            g.detrend, 'subitc', g.subitc, 'wavelet', g.cycles, 'padratio', g.padratio, ...
            'freqs' g.freqs 'freqscale' g.freqscale 'nfreqs' g.nfreqs };
if ~strcmpi(g.type, 'amp') && ~strcmpi(g.type, 'crossspec')
    spectraloptions = { spectraloptions{:} 'itctype' g.type };
end

fprintf('\nProcessing first input\n');
X = reshape(X, g.frame, g.trials);
[alltfX freqs timesout] = timefreq(X, g.srate, spectraloptions{:});
fprintf('\nProcessing second input\n');
Y = reshape(Y, g.frame, g.trials);
[alltfY] = timefreq(Y, g.srate, spectraloptions{:});

% ------------------
% compute coherences
% ------------------
tmpprod = alltfX .* conj(alltfY);
if nargout > 6 || strcmpi(g.type, 'phasecoher2') ||  strcmpi(g.type, 'phasecoher')
    coherresout = alltfX .* conj(alltfY);
end
switch g.type
 case 'crossspec',
  coherres = alltfX .* conj(alltfY); % no normalization

 case 'coher',
  coherres = sum(alltfX .* conj(alltfY), 3) ./ sqrt( sum(abs(alltfX).^2,3) .* sum(abs(alltfY).^2,3) );

 case 'amp'
  alltfX = abs(alltfX);
  alltfY = abs(alltfY);
  coherres = ampcorr(alltfX, alltfY, freqs, timesout, g);
  g.alpha = NaN;
  coherresout = [];

 case 'phasecoher2',
  coherres = sum(coherresout, 3) ./ sum(abs(coherresout),3);

 case 'phasecoher',
  coherres = sum( coherresout ./ abs(coherresout), 3) / g.trials;
end

%%%%%%%%%%
% baseline
%%%%%%%%%%
if size(g.baseline,2) == 2
    baseln = [];
    for index = 1:size(g.baseline,1)
        tmptime   = find(timesout >= g.baseline(index,1) & timesout <= g.baseline(index,2));
        baseln = union_bc(baseln, tmptime);
    end
    if length(baseln)==0
        error('No point found in baseline');
    end
else
    if ~isempty(find(timesout < g.baseline))
        baseln = find(timesout < g.baseline); % subtract means of pre-0 (centered) windows
    else
        baseln = 1:length(timesout); % use all times as baseline
    end
end
if ~isnan(g.alpha) && length(baseln)==0
    fprintf('timef(): no window centers in baseline (times<%g) - shorten (max) window length.\n', g.baseline)
    return
end
mbase = mean(abs(coherres(:,baseln)'));     % mean baseline coherence magnitude

% -----------------
% compute bootstrap
% -----------------
if ~isempty(g.rboot)
    Rbootout = g.rboot;
else
    if ~isnan(g.alpha)
        % getting formula for coherence
        % -----------------------------
        switch g.type
           case 'coher', 
            inputdata = { alltfX alltfY }; % default
            formula = 'sum(arg1 .* conj(arg2), 3) ./ sqrt( sum(abs(arg1).^2,3) .* sum(abs(arg2).^2,3) );';
           case 'amp', % not implemented 
            inputdata = { abs(alltfX) abs(alltfY) }; % default
           case 'phasecoher2',
            inputdata = { alltfX alltfY }; % default
            formula = [ 'tmp = arg1 .* conj(arg2);' ...
                        'res = sum(tmp, 3) ./ sum(abs(tmp),3);' ];
           case 'phasecoher',
            inputdata = { alltfX./abs(alltfX) alltfY./abs(alltfY) };
            formula = [ 'mean(arg1 .* conj(arg2),3);' ];
           case 'crossspec',
            inputdata = { alltfX./abs(alltfX) alltfY./abs(alltfY) };
            formulainit = [ 'arg1 .* conj(arg2);' ];
        end

        % finding baseline for bootstrap
        % ------------------------------
        if size(g.baseboot,2) == 1
            if g.baseboot == 0, baselntmp = [];
            elseif ~isnan(g.baseline(1))
                 baselntmp = baseln;
            else baselntmp = find(timesout <= 0); % if it is empty use whole epoch
            end
        else
            baselntmp = [];
            for index = 1:size(g.baseboot,1)
                tmptime   = find(timesout >= g.baseboot(index,1) & timesout <= g.baseboot(index,2));
                baselntmp = union_bc(baselntmp, tmptime);
            end
        end
        if prod(size(g.baseboot)) > 2
            fprintf('Bootstrap analysis will use data in multiple selected windows.\n');
        elseif size(g.baseboot,2) == 2
            fprintf('Bootstrap analysis will use data in range %3.2g-%3.2g ms.\n', g.baseboot(1),  g.baseboot(2));
        elseif g.baseboot
            fprintf('   %d bootstrap windows in baseline (times<%g).\n', length(baselntmp), g.baseboot)
        end;        

        if strcmpi(g.boottype, 'shuffle') || strcmpi(g.boottype, 'rand')
            Rbootout = bootstat(inputdata, formula, 'boottype', g.boottype, 'label', 'coherence', ...
                    'bootside', 'upper', 'shuffledim', [2 3], 'dimaccu', 2, ...
                    'naccu', g.naccu, 'alpha', g.alpha, 'basevect', baselntmp);
        elseif strcmpi(g.boottype, 'randall') 
             % randomize phase but do not accumulate over time
             % dimension (NOT TESTED)
             % note the absence of dimaccu and the shuffledim 3
            Rbootout = bootstat(inputdata, formula, 'boottype', 'rand', ...
                    'bootside', 'upper', 'shuffledim', 3, ...
                    'naccu', g.naccu, 'alpha', g.alpha, 'basevect', baselntmp);
        else % shuffle only trials (NOT TESTED)
             % note the absence of dimaccu and the shuffledim 3
            Rbootout = bootstat(inputdata, formula, 'boottype', 'shuffle', ...
                    'bootside', 'upper', 'shuffledim', 3, ...
                    'naccu', g.naccu, 'alpha', g.alpha, 'basevect', baselntmp);
        end;                    
    else Rbootout = [];
    end
    % note that the bootstrap thresholding is actually performed in the display subfunction plotall()
end;	

% plot everything
% ---------------
if strcmpi(g.plotamp, 'on') || strcmpi(g.plotphase, 'on')
    if strcmpi(g.plottype, 'image')
        plotall  ( coherres, Rbootout, timesout, freqs, mbase, g);
    else    
        plotallcurves( coherres, Rbootout, timesout, freqs, mbase, g);
    end
end

% process outputs
% --------------
Rangle = angle(coherres);
R = abs(coherres);

return; 
% ***********************************************************************

% ------------------------------
% amplitude correlation function
% ------------------------------
function [coherres, lagmap] = ampcorr(alltfX, alltfY, freqs, timesout, g)
    
    % initialize variables
    % --------------------
    coherres  = zeros(length(freqs), length(timesout), length(g.amplag));
    alpha = zeros(length(freqs), length(timesout), length(g.amplag));
    countlag = 1;
    for lag = g.amplag
        fprintf('Computing %d point lag amplitude correlation, please wait...\n', lag);
        for i1 = 1:length(freqs)
            for i2 = max(1, 1-lag):min(length(timesout)-lag, length(timesout))
                if ~isnan(g.alpha)
                    [tmp1 tmp2] = corrcoef( squeeze(alltfX(i1,i2,:)), squeeze(alltfY(i1,i2+lag,:)) );
                    coherres(i1,i2,countlag)   = tmp1(1,2);
                    alpha(i1,i2,countlag)      = tmp2(1,2);
                else
                    tmp1 = corrcoef( squeeze(alltfX(i1,i2,:)), squeeze(alltfY(i1,i2+lag,:)) );
                    coherres(i1,i2,countlag)   = tmp1(1,2);
                end
            end
        end
        countlag = countlag + 1;
    end

    % find max corr if different lags
    % -------------------------------
    if length(g.amplag) > 1
        [coherres lagmap] = max(coherres, [], 3);
        dimsize = length(freqs)*length(timesout);
        alpha = reshape(alpha((lagmap(:)-1)*dimsize+[1:dimsize]'),length(freqs), length(timesout));
        % above is same as (but faster)
        % for i1 = 1:length(freqs)
        %    for i2 = 1:length(timesout)
        %        alphanew(i1, i2) = alpha(i1, i2, lagmap(i1, i2));
        %    end
        % end
        lagmap = g.amplag(lagmap); % real lag
        coherres = coherres.*exp(j*lagmap/max(abs(g.amplag))); % encode lag in the phase
    else
        lagmap = [];
    end
    
    % apply significance mask
    % -----------------------
    if ~isnan(g.alpha)
        tmpind = find(alpha(:) > g.alpha);
        coherres(tmpind) = 0;
    end

% ------------------
% plotting functions
% ------------------
function plotall(R, Rboot, times, freqs, mbase, g) 

switch lower(g.plotphase)
case 'on',  
   switch lower(g.plotamp), 
   case 'on', ordinate1 = 0.67; ordinate2 = 0.1; height = 0.33; g.plot = 1;
   case 'off', ordinate2 = 0.1; height = 0.9; g.plot = 1;
   end;     
case 'off', ordinate1 = 0.1; height = 0.9; 
   switch lower(g.plotamp), 
   case 'on', ordinate1 = 0.1; height = 0.9;  g.plot = 1;
   case 'off', g.plot = 0;
   end;     
end; 

% compute angles
% --------------
Rangle = angle(R);
if ~isreal(R)
    R = abs(R);
    Rraw =R; % raw coherence values
    setylim = 1;
    if ~isnan(g.baseline)
     	R = R - repmat(mbase',[1 g.timesout]); % remove baseline mean
    end
else
    Rraw = R;
    setylim = 0;
end

if g.plot
   fprintf('\nNow plotting...\n');
   set(gcf,'DefaultAxesFontSize',g.AXES_FONT)
   icadefs;
   colormap(feval(DEFAULT_COLORMAP, 256));
   pos = get(gca,'position'); % plot relative to current axes
   q = [pos(1) pos(2) 0 0];
   s = [pos(3) pos(4) pos(3) pos(4)];
   axis('off')
end

switch lower(g.plotamp)
case 'on' 
   %
   % Image the coherence [% perturbations] 
   %
   RR = R;
   if ~isnan(g.alpha) % zero out (and 'green out') nonsignif. R values
       switch dims(Rboot)
           case 3, RR  (find(RR > Rboot(:,:,1) & (RR < Rboot(:,:,2)))) = 0;
                   Rraw(find(RR > Rboot(:,:,1) & (RR < Rboot(:,:,2)))) = 0;
           case 2, RR  (find(RR < Rboot)) = 0;
                   Rraw(find(RR < Rboot)) = 0;
           case 1, RR  (find(RR < repmat(Rboot(:),[1 size(RR,2)]))) = 0;
                   Rraw(find(RR < repmat(Rboot(:),[1 size(Rraw,2)]))) = 0;
       end; 
   end
    
   h(6) = axes('Units','Normalized', 'Position',[.1 ordinate1 .8 height].*s+q);
   
   map=hsv(300); % install circular color map - green=0, yellow, orng, red, violet = max
   %                                         cyan, blue, violet = min
   map = flipud([map(251:end,:);map(1:250,:)]);
   map(151,:) = map(151,:)*0.9; % tone down the (0=) green!
   colormap(map);
   
   if ~strcmpi(g.freqscale, 'log')
       try, imagesc(times,freqs,RR,max(max(RR))*[-1 1]); % plot the coherence image
       catch, imagesc(times,freqs,RR,[-1 1]); end
   else 
       try, imagesclogy(times,freqs,RR,max(max(RR))*[-1 1]); % plot the coherence image
       catch, imagesclogy(times,freqs,RR,[-1 1]); end
   end
   
  set(gca,'ydir','norm'); 
   
   if ~isempty(g.maxamp)
	   caxis([-g.maxamp g.maxamp]);
   end
   tmpscale = caxis;
   
   hold on
   plot([0 0],[0 freqs(end)],'--m','LineWidth',g.linewidth)
   for i=1:length(g.marktimes)
      plot([g.marktimes(i) g.marktimes(i)],[0 freqs(end)],'--m','LineWidth',g.linewidth);
   end
   hold off
   set(h(6),'YTickLabel',[],'YTick',[])
   set(h(6),'XTickLabel',[],'XTick',[])
   
   h(8) = axes('Position',[.95 ordinate1 .05 height].*s+q);
     
   if setylim 
        cbar(h(8),151:300, [0 tmpscale(2)]); % use only positive colors (gyorv) 
   else cbar(h(8),1:300  , [-tmpscale(2) tmpscale(2)]); % use only positive colors (gyorv) 
   end
   
   %
   % Plot delta-mean min and max coherence at each time point on bottom of image
   %
   
   h(10) = axes('Units','Normalized','Position',[.1 ordinate1-0.1 .8 .1].*s+q); % plot marginal means below
   Emax = max(R); % mean coherence at each time point
   Emin = min(R); % mean coherence at each time point
   plot(times,Emin, times, Emax, 'LineWidth',g.linewidth); hold on;
   plot([times(1) times(length(times))],[0 0],'LineWidth',0.7);
   plot([0 0],[-500 500],'--m','LineWidth',g.linewidth);
   for i=1:length(g.marktimes)
       plot([g.marktimes(i) g.marktimes(i)],[-500 500],'--m','LineWidth',g.linewidth);
   end
   if ~isnan(g.alpha) && dims(Rboot) > 1
      % plot bootstrap significance limits (base mean +/-)
      switch dims(Rboot)
       case 2, plot(times,mean(Rboot(:,:),1),'g' ,'LineWidth',g.linewidth);
               plot(times,mean(Rboot(:,:),1),'k:','LineWidth',g.linewidth);
       case 3, plot(times,mean(Rboot(:,:,1),1),'g' ,'LineWidth',g.linewidth);
               plot(times,mean(Rboot(:,:,1),1),'k:','LineWidth',g.linewidth);
               plot(times,mean(Rboot(:,:,2),1),'g' ,'LineWidth',g.linewidth);
               plot(times,mean(Rboot(:,:,2),1),'k:','LineWidth',g.linewidth);
      end
      axis([min(times) max(times) 0 max([Emax(:)' Rboot(:)'])*1.2])
   else
      axis([min(times) max(times) 0 max(Emax)*1.2])
   end
   
   tick = get(h(10),'YTick');
   set(h(10),'YTick',[tick(1) ; tick(length(tick))])
   set(h(10),'YAxisLocation','right')
   xlabel('Time (ms)')
   ylabel('coh.')
   
   %
   % Plot mean baseline coherence at each freq on left side of image
   %   
   
   h(11) = axes('Units','Normalized','Position',[0 ordinate1 .1 height].*s+q); % plot mean spectrum
   E = abs(mbase); % baseline mean coherence at each frequency
   if ~strcmpi(g.freqscale, 'log')
       plot(freqs,E,'b','LineWidth',g.linewidth); % plot mbase
   else
       semilogx(freqs,E,'b','LineWidth',g.linewidth); % plot mbase
       set(h(11),'View',[90 90])
       divs = linspace(log(freqs(1)), log(freqs(end)), 10);
       set(gca, 'xtickmode', 'manual');
       divs = ceil(exp(divs)); divs = unique_bc(divs); % ceil is critical here, round might misalign
                                                    % out-of border label with within border ticks
       set(gca, 'xtick', divs);       
   end;       
   if ~isnan(g.alpha) % plot bootstrap significance limits (base mean +/-)
       hold on
       if ~strcmpi(g.freqscale, 'log')
           switch dims(Rboot)
            case 1, plot(freqs,Rboot(:),'g' ,'LineWidth',g.linewidth);
                    plot(freqs,Rboot(:),'k:','LineWidth',g.linewidth);
            case 2, plot(freqs,mean(Rboot(:,:),2),'g' ,'LineWidth',g.linewidth);
                    plot(freqs,mean(Rboot(:,:),2),'k:','LineWidth',g.linewidth);
            case 3, plot(freqs,mean(Rboot(:,:,1),2),'g' ,'LineWidth',g.linewidth);
                    plot(freqs,mean(Rboot(:,:,1),2),'k:','LineWidth',g.linewidth);
                    plot(freqs,mean(Rboot(:,:,2),2),'g' ,'LineWidth',g.linewidth);
                    plot(freqs,mean(Rboot(:,:,2),2),'k:','LineWidth',g.linewidth);
           end;  
       else
           switch dims(Rboot)
            case 1, semilogy(freqs,Rboot(:),'g' ,'LineWidth',g.linewidth);
                    semilogy(freqs,Rboot(:),'k:','LineWidth',g.linewidth);
            case 2, semilogy(freqs,mean(Rboot(:,:),2),'g' ,'LineWidth',g.linewidth);
                    semilogy(freqs,mean(Rboot(:,:),2),'k:','LineWidth',g.linewidth);
            case 3, semilogy(freqs,mean(Rboot(:,:,1),2),'g' ,'LineWidth',g.linewidth);
                    semilogy(freqs,mean(Rboot(:,:,1),2),'k:','LineWidth',g.linewidth);
                    semilogy(freqs,mean(Rboot(:,:,2),2),'g' ,'LineWidth',g.linewidth);
                    semilogy(freqs,mean(Rboot(:,:,2),2),'k:','LineWidth',g.linewidth);
           end;  
       end;           
       if ~isnan(max(E))
           axis([freqs(1) freqs(end) 0 max([E Rboot(:)'])*1.2]);
       end
   else             % plot marginal mean coherence only
      if ~isnan(max(E))
          axis([freqs(1) freqs(end) 0 max(E)*1.2]);
      end
   end
   
   set(gca,'xdir','rev'); % nima
   
   tick = get(h(11),'YTick');
   set(h(11),'YTick',[tick(1) ; tick(length(tick))]); % crashes for log
   set(h(11),'View',[90 90])
   xlabel('Freq. (Hz)')
   ylabel('coh.')
end

switch lower(g.plotphase)
case 'on'
   %
   % Plot coherence phase lags in bottom panel
   %
   h(13) = axes('Units','Normalized','Position',[.1 ordinate2 .8 height].*s+q);
   if setylim
       if strcmpi(g.type, 'amp') % currently -1 to 1
           maxangle = max(abs(g.amplag)) * mean(times(2:end) - times(1:end-1));
           Rangle   = Rangle * maxangle;
           maxangle = maxangle+5; % so that the min and the max does not mix
       else
           if strcmp(g.angleunit,'ms')  % convert to ms
               Rangle = (Rangle/(2*pi)).*repmat(1000./freqs(:)',1,length(times)); 
               maxangle = max(max(abs(Rangle)));
           elseif strcmpi(g.angleunit,'deg')  % convert to degrees
               Rangle = Rangle*180/pi; % convert to degrees
               maxangle = 180; % use full-cycle plotting 
           else
               maxangle = pi;
           end           
       end
       Rangle(find(Rraw==0)) = 0; % set angle at non-signif coher points to 0
       
       if ~strcmpi(g.freqscale, 'log')
           imagesc(times,freqs,Rangle,[-maxangle maxangle]); % plot the coherence phase angles
       else
           imagesclogy(times,freqs,Rangle,[-maxangle maxangle]); % plot the coherence phase angles
       end;           
       hold on                                             
       plot([0 0],[0 freqs(end)],'--m','LineWidth',g.linewidth); % zero-time line
       for i=1:length(g.marktimes)
           plot([g.marktimes(i) g.marktimes(i)],[0 freqs(end)],'--m','LineWidth',g.linewidth);
       end
       
       set(gca,'ydir','norm'); % nima
       
       ylabel('Freq. (Hz)')
       xlabel('Time (ms)')
       
       h(14)=axes('Position',[.95 ordinate2 .05 height].*s+q);
       cbar(h(14),0,[-maxangle maxangle]); % two-sided colorbar
   else 
       axis off;
       text(0, 0.5, 'Real values, no angles');
   end
end

if g.plot
   try, icadefs; set(gcf, 'color', BACKCOLOR); catch, end
   if (length(g.title) > 0) % plot title
      axes('Position',pos,'Visible','Off');               
      h(13) = text(-.05,1.01,g.title);
      set(h(13),'VerticalAlignment','bottom')
      set(h(13),'HorizontalAlignment','left')
      set(h(13),'FontSize',g.TITLE_FONT)
   end
   %
   %%%%%%%%%%%%%%% plot topoplot() %%%%%%%%%%%%%%%%%%%%%%%
   %
   if (~isempty(g.topovec)) && strcmpi(g.plotamp, 'on') && strcmpi(g.plotphase, 'on')
      h(15) = subplot('Position',[-.1 .43 .2 .14].*s+q);
      if size(g.topovec,2) <= 2
         topoplot(g.topovec(1),g.elocs,'electrodes','off', ...
            'style', 'blank', 'emarkersize1chan', 10, 'chaninfo', g.chaninfo);
      else
         topoplot(g.topovec(1,:),g.elocs,'electrodes','off', 'chaninfo', g.chaninfo);
      end
      axis('square')
      
      h(16) = subplot('Position',[.9 .43 .2 .14].*s+q);
      if size(g.topovec,2) <= 2
         topoplot(g.topovec(2),g.elocs,'electrodes','off', ...
            'style', 'blank', 'emarkersize1chan', 10, 'chaninfo', g.chaninfo);
      else
         topoplot(g.topovec(2,:),g.elocs,'electrodes','off', 'chaninfo', g.chaninfo);
      end
      axis('square')
   end
   
   try, axcopy(gcf); catch, end
end

% ---------------
% Plotting curves
% ---------------
function plotallcurves(R, Rboot, times, freqs, mbase, g) 

	% compute angles
	% --------------
	Rangle = angle(R);
	pos = get(gca,'position'); % plot relative to current axes
	q     = [pos(1) pos(2) 0 0];
	s = [pos(3) pos(4) pos(3) pos(4)];
	if ~isreal(R)
        R = abs(R);
        Rraw =R; % raw coherence values
        if ~isnan(g.baseline)
         	R = R - repmat(mbase',[1 g.timesout]); % remove baseline mean
        end
	else
        Rraw = R;
        setylim = 0;
	end

    % time unit
    % ---------
    if times(end) > 10000
        times = times/1000;
        timeunit = 's';
    else
        timeunit = 'ms';
    end

    % legend
    % ------
    alllegend = {};
    if strcmpi(g.plotmean, 'on') && freqs(1) ~= freqs(end)
      alllegend = { [ num2str(freqs(1)) '-' num2str(freqs(end)) 'Hz' ] };
    else
      for index = 1:length(freqs)
         alllegend{index} = [ num2str(freqs(index)) 'Hz' ];
      end
    end
    
	fprintf('\nNow plotting...\n');
	if strcmpi(g.plotamp, 'on')
      %
      % Plot coherence amplitude in top panel
      %
      if strcmpi(g.plotphase, 'on'), subplot(2,1,1); end; 
      if isempty(g.maxamp), g.maxamp = 0; end
      plotcurve(times, R, 'maskarray', Rboot, 'title', 'Coherence amplitude', ...
                'xlabel', [ 'Time (' timeunit ')' ], 'ylabel', '0-1', 'ylim', g.maxamp, ...
                'vert', g.vert, 'marktimes', g.marktimes, 'legend', alllegend, ...
                'linewidth', g.linewidth, 'highlightmode', g.highlightmode, 'plotmean', g.plotmean);
	end
	
	if strcmpi(g.plotphase, 'on')
      %
      % Plot coherence phase lags in bottom panel
      %
      if strcmpi(g.plotamp, 'on'), subplot(2,1,2); end; 
      plotcurve(times, Rangle/pi*180, 'maskarray', Rboot, 'val2mask', R, 'title', 'Coherence phase', ...
                'xlabel', [ 'Time (' timeunit ')' ], 'ylabel', 'Angle (deg.)', 'ylim', [-180 180], ...
                'vert', g.vert, 'marktimes', g.marktimes, 'legend', alllegend, ...
                'linewidth', g.linewidth, 'highlightmode', g.highlightmode, 'plotmean', g.plotmean);
	end
	
	if strcmpi(g.plotamp, 'on') || strcmpi(g.plotphase, 'on')
       try, icadefs; set(gcf, 'color', BACKCOLOR); catch, end
       if (length(g.title) > 0) % plot title
          h(13) = textsc(g.title, 'title');
       end
	
       %
       %%%%%%%%%%%%%%% plot topoplot() %%%%%%%%%%%%%%%%%%%%%%%
       %
       if (~isempty(g.topovec))
          h(15) = subplot('Position',[-.1 .43 .2 .14].*s+q);
          if size(g.topovec,2) <= 2
             topoplot(g.topovec(1),g.elocs,'electrodes','off', ...
                'style', 'blank', 'emarkersize1chan', 10);
          else
             topoplot(g.topovec(1,:),g.elocs,'electrodes','off');
          end
          axis('square')
          
          h(16) = subplot('Position',[.9 .43 .2 .14].*s+q);
          if size(g.topovec,2) <= 2
             topoplot(g.topovec(2),g.elocs,'electrodes','off', ...
                'style', 'blank', 'emarkersize1chan', 10);
          else
             topoplot(g.topovec(2,:),g.elocs,'electrodes','off');
          end
          axis('square')
       end
       
       try, axcopy(gcf); catch, end
	end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    COHERENCE OBSOLETE   %%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% function for coherence initialisation
% -------------------------------------
function Coher = coherinit(nb_points, trials, timesout, type);
Coher.R  = zeros(nb_points,timesout);       % mean coherence
%Coher.RR = repmat(nan,nb_points,timesout); % initialize with nans
Coher.type = type;
Coher.Rn=zeros(trials,timesout);
switch type
 case 'coher',
  Coher.cumulX = zeros(nb_points,timesout);
  Coher.cumulY = zeros(nb_points,timesout);
 case 'phasecoher2',
  Coher.cumul  = zeros(nb_points,timesout);
end

% function for coherence calculation
% -------------------------------------
%function Coher = cohercomparray(Coher, tmpX, tmpY, trial);
%switch Coher.type
%   case 'coher',
%      Coher.R = Coher.R + tmpX.*conj(tmpY); % complex coher.
%      Coher.cumulXY = Coher.cumulXY + abs(tmpX).*abs(tmpY);
%   case 'phasecoher',
%      Coher.R = Coher.R + tmpX.*conj(tmpY) ./ (abs(tmpX).*abs(tmpY)); % complex coher.
%      Coher.Rn(trial,:) = 1;
%end % ~any(ISNAN)

function [Coher,tmptrialcoh] = cohercomp(Coher, tmpX, tmpY, trial, time);
tmptrialcoh = tmpX.*conj(tmpY);
switch Coher.type
 case 'coher',
      Coher.R(:,time) = Coher.R(:,time) + tmptrialcoh; % complex coher.
      Coher.cumulX(:,time) = Coher.cumulX(:,time) + abs(tmpX).^2;
      Coher.cumulY(:,time) = Coher.cumulY(:,time) + abs(tmpY).^2;
 case 'phasecoher2',
      Coher.R(:,time) = Coher.R(:,time) + tmptrialcoh; % complex coher.
      Coher.cumul(:,time) = Coher.cumul(:,time) + abs(tmptrialcoh);
 case 'phasecoher',
      Coher.R(:,time) = Coher.R(:,time) + tmptrialcoh ./ abs(tmptrialcoh); % complex coher.
	  %figure; imagesc(abs(tmpX.*conj(tmpY) ./ (abs(tmpX).*abs(tmpY))));
      Coher.Rn(trial,time) = Coher.Rn(trial,time)+1;
end % ~any(isnan())

% function for post coherence calculation
% ---------------------------------------
function Coher = cohercomppost(Coher, trials);
switch Coher.type
 case 'coher',
   Coher.R = Coher.R ./ sqrt(Coher.cumulX) ./ sqrt(Coher.cumulY);
 case 'phasecoher2',
   Coher.R = Coher.R ./ Coher.cumul;
 case 'phasecoher',
   Coher.Rn = sum(Coher.Rn, 1);
   Coher.R  = Coher.R ./ (ones(size(Coher.R,1),1)*Coher.Rn); % coherence magnitude
end

% function for 2 conditions coherence calculation
% -----------------------------------------------
function [coherimage, coherimage1, coherimage2] = coher2conddiff( allsavedcoher, alltrials, cond1trials, type, tfx, tfy);
	t1s = alltrials(1:cond1trials);
	t2s = alltrials(cond1trials+1:end);
	switch type
	 case 'coher',
	  coherimage1 = sum(allsavedcoher(:,:,t1s),3) ./ sqrt(sum(tfx(:,:,t1s))) ./ sqrt(sum(tfy(:,:,t1s)));
	  coherimage2 = sum(allsavedcoher(:,:,t2s),3) ./ sqrt(sum(tfx(:,:,t2s))) ./ sqrt(sum(tfy(:,:,t1s)));
	 case 'phasecoher2',
	  coherimage1 = sum(allsavedcoher(:,:,t1s),3) ./ sum(abs(allsavedcoher(:,:,t1s)),3);
	  coherimage2 = sum(allsavedcoher(:,:,t2s),3) ./ sum(abs(allsavedcoher(:,:,t2s)),3);
	 case 'phasecoher',
	  coherimage1 = sum(allsavedcoher(:,:,t1s),3) / cond1trials;
	  coherimage2 = sum(allsavedcoher(:,:,t2s),3) / (size(allsavedcoher,3)-cond1trials);
	end
	coherimage = coherimage2 - coherimage1;

function w = hanning(n)
if ~rem(n,2)
   w = .5*(1 - cos(2*pi*(1:n/2)'/(n+1)));
   w = [w; w(end:-1:1)];
else
   w = .5*(1 - cos(2*pi*(1:(n+1)/2)'/(n+1)));
   w = [w; w(end-1:-1:1)];
end

function res = dims(array)
    res = min(ndims(array), max(size(array,2),size(array,3)));
