function res = spm_eeg_reduce_imagcsd(S)
% Plugin for data reduction based on the imaginary part of CSD
% with a reference chhannel
% FORMAT res = spm_eeg_reduce_imagcsd(S)
%
% S                     - input structure
% fields of S:
%   
%
% Output:
%  res -
%   If no input is provided the plugin returns a cfg branch for itself
%
%   If input is provided:
%      montage struct implementing projection to PCA subspace
%______________________________________________________________________________________
% Copyright (C) 2014 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak
% $Id: spm_eeg_reduce_imagcsd.m 6253 2014-10-30 16:29:39Z vladimir $


if nargin == 0
    
    origchan = cfg_branch;
    origchan.tag = 'origchan';
    origchan.name = 'Channels to reduce';
    origchan.val = {spm_cfg_eeg_channel_selector};
    
    refchan = cfg_branch;
    refchan.tag = 'refchan';
    refchan.name = 'Reference channels';
    refchan.val = {spm_cfg_eeg_channel_selector};    
    
    
    outlabel = cfg_entry;
    outlabel.tag = 'outlabel';
    outlabel.name = 'Output channel label';
    outlabel.strtype = 's';
    outlabel.num = [1 Inf];
    outlabel.help = {'Label for the output channel(s).'};
    
    foi = cfg_entry;
    foi.tag = 'foi';
    foi.name = 'Frequency band of interest';
    foi.strtype = 'r';
    foi.num = [1 2];
    foi.val = {[0 Inf]};
    foi.help = {'Frequency window to optimize for'};       
    
    chanset = cfg_branch;
    chanset.tag = 'chanset';
    chanset.name = 'Set';
    chanset.val = {origchan, refchan, outlabel, foi};
    
    chansets = cfg_repeat;
    chansets.tag = 'chansets';
    chansets.name = 'Channel sets';
    chansets.values = {chanset};
    chansets.num = [1 Inf];
    chansets.val = {chanset};
    
    
    imagcsd = cfg_branch;
    imagcsd.tag = 'imagcsd';
    imagcsd.name = 'Imaginary part of CSD';
    imagcsd.val = {chansets};
    
    res = imagcsd;
    
    return
end

flag_tbx = license('checkout','signal_toolbox') && ~isempty(ver('signal'));
if flag_tbx
    taper = 'dpss';
else
    taper = 'sine';
end

D = S.D;

nsets = numel(S.chanset);
badind = D.badchannels;

% Assuming projecting to columns
montage = [];
montage.labelorg    = D.chanlabels;
montage.labelnew    = {};
montage.chantypenew = {};
montage.tra         = zeros(0, D.nchannels);

spm('Pointer', 'Watch');drawnow;
spm_progress_bar('Init', nsets, 'Channel sets processed'); drawnow;
if nsets > 100, Ibar = floor(linspace(1, nsets,100));
else Ibar = 1:nsets; end

for i = 1:nsets
    
    spm_progress_bar('Set','ylabel','preparing data...');
    
    origind = setdiff(D.selectchannels(spm_cfg_eeg_channel_selector(S.chanset(i).origchan.channels)), badind);
    refind = setdiff(D.selectchannels(spm_cfg_eeg_channel_selector(S.chanset(i).refchan.channels)), badind);     
    
    if length(refind)~=1
        error(sprintf('One reference chhannel is necessary, found %d.', length(refind)));
    end
    
    Y  = D(origind, :, :);
    Yr = D(refind, :, :);
    
       
    spm_progress_bar('Set','ylabel','computing CSD...');
    
    foi =  S.chanset(i).foi;
    foi(isinf(foi)) = 0.5*D.fsample;
    
    fY =[];
    for c = 1:size(Y, 1)
        [spectrum,ntaper,freqoi] = ft_specest_mtmfft(spm_squeeze(Y(c, :, :), 1)', D.time, 'taper', taper, 'freqoi', mean(foi), 'tapsmofrq', 0.5*diff(foi), 'verbose', 0);
        fY = [fY spectrum(:)];
    end
    
    fYr = ft_specest_mtmfft(spm_squeeze(Yr, 1)', D.time, 'taper', taper, 'freqoi', mean(foi), 'tapsmofrq', 0.5*diff(foi), 'verbose', 0);
    
    fYr = fYr(:);
    
    csd = mean(fY.*repmat(conj(fYr), 1, size(fY, 2)));
    
    mom = imag(csd)./norm(imag(csd));
    
    
    montage.labelnew{end+1, 1} = S.chanset(i).outlabel;
    
    montage.tra(end+1, end)  = 0;
    montage.tra(end, origind) = mom;
    
    montage.chantypenew{end+1}='LFP';
    
    if ismember(i, Ibar)
        spm_progress_bar('Set', i); drawnow;
    end
end

spm_progress_bar('Clear');

if ~isempty(S.chanind)
    montage.labelnew = [montage.labelnew; D.chanlabels(S.chanind)'];
    I = eye(D.nchannels);
    montage.tra = [montage.tra; I(S.chanind, :)];
    montage.chantypenew = [montage.chantypenew, D.chantype(S.chanind)];
end

res = montage;
