function singleplotER(cfg, varargin)

% singleplotER plots the event-related fields or potentials for one
% sensors.
%
% Use as:
%   sinlgeplotER(cfg, data)
%   singleplotER(cfg, data1, data2, ..., dataN)
%
% The data can be an ERF produced by TIMELOCKANALYSIS, a powerspectrum
% produced by FREQANALYSIS or a coherencespectrum produced by
% FREQDESCRIPTIVES. If you specify multiple datasets they must contain
% the same channels, etc.
%
% The cfg structure contains all configurations details for the plotting
%
% cfg.layout           = specification of the layout, see below
% cfg.baseline         = 'yes','no' or [time1 time2]     (default = 'no')
% cfg.xparam           = field to be plotted on x-axis   (default = 'time')
% cfg.xlim             = 'maxmin' or [xmin xmax]         (default = 'maxmin')
% cfg.yparam           = field to be plotted on y-axis   (default = 'avg')
% cfg.ylim             = 'maxmin' or [ymin ymax]         (default = 'maxmin')
% cfg.fontsize         = size of font                    (default = 8)
% cfg.interactive      = 'yes', 'no'                     (default = 'no')
%
% If you use the output of freqdescriptives as an input and if you want to visualise
% coherence with respect to a reference-channel, you should specify:
%
% cfg.zparam        =  'cohspctrm'
% cfg.cohrefchannel =  name of reference-channel
%
% The layout defines how the channels are arranged and what the size of each
% subplot is. You can specify the layout in a variety of ways:
%  - you can give the name of an ascii layout file with extension *.lay
%  - you can give the name of an electrode file
%  - you can give an electrode definition, i.e. "elec" structure
%  - you can give a gradiometer definition, i.e. "grad" structure
% If you do not specify any of these and the data structure contains an
% electrode or gradiometer structure (common for MEG data, since the header
% of the MEG datafile contains the gradiometer information), that will be
% used for creating a layout. If you want to have more fine-grained control
% over the layout of the subplots, you should create your own layout file.
%
% See also:
%   singleplotTFR, multiplotER, multiplotTFR, topoplotER, topoplotTFR.

% Copyright (C) 2003, Ole Jensen
%
% $Log: singleplotER.m,v $
% Revision 1.8  2006/03/10 09:24:16  jansch
% made a fix in assigning a default to zparam, this has to be cleaned up!
%
% Revision 1.7  2006/03/02 13:54:59  jansch
% fixed multiple small bugs
%
% Revision 1.6  2006/02/28 12:43:15  roboos
% made plotting of coherence consistent between all xxxplotER functions
% made baselining consistent, use cfg.xparam to decide between freqbaseline and timelockbaseline
%
% Revision 1.5  2006/02/27 15:03:03  denpas
% many changes, most important is added interactive functionality
% made data selection consistent between different plot functions
% changed dimord for consistency
%
% Revision 1.3  2005/05/17 17:50:38  roboos
% changed all "if" occurences of & and | into && and ||
% this makes the code more compatible with Octave and also seems to be in closer correspondence with Matlab documentation on shortcircuited evaluation of sequential boolean constructs
%
% Revision 1.2  2005/04/17 18:51:05  olejen
% Option colorgraph added
%
% Revision 1.1  2005/04/06 13:59:05  olejen
% Plot EF for a single channel. Modified from multiplotER.m
%
% Revision 1.5  2005/02/07 17:12:00  roboos
% changed handling of layout files (using new function createlayout), now also supports automatic layout creation based on gradiometer/electrode definition in data, updated help, cleaned up indentation
%
% Revision 1.4  2005/01/27 09:31:49  roboos
% applied autoindentation on code, removed many empty lines and spaces,
% replaced layoutfile reading with read_lay, applied doudavs code to all input arguments
% implemented automatic detection of arguments to plot,
% updated help, changed input from p1, p2, p3... to varargin
%
% Revision 1.3  2004/09/24 15:54:54  roboos
% included the suggested improvements by Doug Davidson: added option cfg.cohtargetchannel
% and updated the help
%
% Revision 1.2  2004/09/01 17:59:28  roboos
% added copyright statements to all filed
% added cfg.version to all functions that give configuration in their output
% added cfg.previous to all functions with input data containing configuration details
%

clf

% for backward compatibility with old data structures
for i=1:length(varargin)
  varargin{i} = fixdimord(varargin{i});
end

if isfield(cfg,'cohtargetchannel'),
  % replace the powspctrm field with the respective coherence
  % implemented by doudav
  for i=1:length(varargin)
    varargin{i} = pwrspctm2cohspctrm(cfg, varargin{i});
  end
end

% set the defaults:
if ~isfield(cfg,'baseline'),    cfg.baseline = 'no';                          end
if ~isfield(cfg,'xlim'),        cfg.xlim = 'maxmin';                          end
if ~isfield(cfg,'ylim'),        cfg.ylim = 'maxmin';                          end
if ~isfield(cfg,'fontsize'),    cfg.fontsize = 8;                             end
if ~isfield(cfg,'graphcolor')   cfg.graphcolor = ['brgkywrgbkywrgbkywrgbkyw'];end
if ~isfield(cfg,'interactive'), cfg.interactive = 'no';                       end

GRAPHCOLOR = ['k' cfg.graphcolor ];

if ~isfield(cfg,'yparam'),
  % determine the type of data
  if isfield(varargin{1}, 'avg'),       cfg.yparam = 'avg';          end
  if isfield(varargin{1}, 'powspctrm'), cfg.yparam = 'powspctrm';    end
end

if ~isfield(cfg,'xparam'),
  % determine the x-axis that matches the type of data
  if isfield(varargin{1}, 'avg'),       cfg.xparam = 'time';         end
  if isfield(varargin{1}, 'powspctrm'), cfg.xparam = 'freq';         end
end

%FIXME: THIS IS AN UGLY FIX TO GET IT WORKING PRIOR TO THE MET-TOOLKIT,HAS TO BE CLEANED UP!
if ~isfield(cfg,'zparam'),
  cfg.zparam = cfg.yparam;
end

% Old style coherence plotting with cohtargetchannel is no longer supported:
if isfield(cfg,'cohtargetchannel'), 
  error('cfg.cohtargetchannel is obsolete, check the documentation for help about coherence plotting.');
end

for k=1:length(varargin)
  % Check for unconverted coherence spectrum data:
  if (strcmp(cfg.zparam,'cohspctrm')) & (isfield(varargin{k}, 'labelcmb'))
    % A reference channel is required:
    if ~isfield(cfg,'cohrefchannel'),
      error('no reference channel specified');
    end
    % Convert 2-dimensional channel matrix to a single dimension:
    sel1                  = strmatch(cfg.cohrefchannel, varargin{k}.labelcmb(:,2));
    sel2                  = strmatch(cfg.cohrefchannel, varargin{k}.labelcmb(:,1));
    fprintf('selected %d channels for coherence\n', length(sel1)+length(sel2));
    varargin{k}.cohspctrm = varargin{k}.cohspctrm([sel1;sel2],:,:);
    varargin{k}.labelcmb  = varargin{k}.labelcmb([sel1;sel2],:);
    varargin{k}.label     = [varargin{k}.labelcmb(sel1,1);varargin{k}.labelcmb(sel2,2)];
    varargin{k}           = rmfield(varargin{k}, 'labelcmb');
  end

  % Apply baseline correction:
  if ~strcmp(cfg.baseline, 'no')
    if strcmp(cfg.yparam, 'time')
      varargin{k} = timelockbaseline(cfg, varargin{k});
    elseif strcmp(cfg.yparam, 'freq')
      varargin{k} = freqbaseline(cfg, varargin{k});
    end
  end
end

% Determine x-axis range:
if strcmp(cfg.xlim,'maxmin')
  % Find maxmin throughout all varargins:
  xmin = [];
  xmax = [];
  for i=1:length(varargin)
    xmin = min([xmin varargin{i}.(cfg.xparam)]);
    xmax = max([xmax varargin{i}.(cfg.xparam)]);
  end
else
  xmin = cfg.xlim(1);
  xmax = cfg.xlim(2);
end

% Pick the channel(s):
if isfield(cfg,'channelindex') && isfield(cfg,'channelname')
  warning('You have defined both cfg.channelindex and cfg.channelname; cfg.channelname will be used');
  cfg = rmfield(cfg,'channelindex');
end

if ~isfield(cfg,'channelindex') && ~isfield(cfg,'channelname')
  error('cfg.channelindex or cfg.channelname must be defined.');
end

if isfield(cfg,'channelname')
  % Convert channelname string to cell array:
  if ischar(cfg.channelname)
    cfg.channelname = {cfg.channelname};
  end

  % Convert channel name(s) to channel index array:
  cfg.channelindex = [];
  for i=1:length(cfg.channelname)
    cfg.channelname{i} = channelselection(cfg.channelname{i}, varargin{1}.label);
    if isempty(cfg.channelname{i})
      error(['Channel ' cfg.channelname{i} ' not found']);
    else
      cfg.channelindex = [cfg.channelindex match_str(varargin{1}.label, cfg.channelname{i})];
    end
  end
end

% Convert the layout to Ole's style of variable names:
cfg.GraphCol = GRAPHCOLOR(1);

hold on;
colorLabels = [];
ymin = [];
ymax = [];

% Plot one line for each data set:
for k=2:nargin
  % Get data matrix:
  P = varargin{k-1}.(cfg.zparam);
  labels = getfield(varargin{k-1}, 'label');

  % User colored labels if more than one data set is plotted:
  if nargin > 2
    colorLabels = [colorLabels inputname(k) '=' GRAPHCOLOR(k) ' '];
  end

  % Average across selected channels:
  P = squeeze(mean(P(cfg.channelindex,:), 1));

  % Update ymin and ymax for the current data set:
  if strcmp(cfg.ylim, 'maxmin')
    ymin = min([ymin P]);
    ymax = max([ymax P]);
  else
    ymin = cfg.ylim(1);
    ymax = cfg.ylim(2);
  end

  style = GRAPHCOLOR(k);
  plot(varargin{k-1}.(cfg.xparam), P, style);
end

% Set xlim and ylim:
xlim([xmin xmax]);
ylim([ymin ymax]);

% Make the figure interactive:
if strcmp(cfg.interactive, 'yes')
  userData.hFigure = gcf;
  userData.hAxes = gca;
  for i=1:1 % no multiple selection regions
    userData.hSelection{i} = plot(0,0);
    set(userData.hSelection{i}, 'XData', mean([xmin xmax]));
    set(userData.hSelection{i}, 'YData', mean([ymin ymax]));
    set(userData.hSelection{i}, 'Color', [0 0 0]);
    set(userData.hSelection{i}, 'EraseMode', 'xor');
    set(userData.hSelection{i}, 'LineStyle', '--');
    set(userData.hSelection{i}, 'LineWidth', 1.5);
    set(userData.hSelection{i}, 'Visible', 'on');
    userData.range{i} = [];
  end
  userData.iSelection = 0;
  userData.plotType = 'singleplot';
  userData.selecting = 0;
  userData.selectionType = '';
  userData.selectAxes = 'x';
  userData.lastClick = [];
  userData.cfg = cfg;
  userData.data = varargin;
  userData.chanX = [];
  userData.chanY = [];
  userData.chanLabels = [];
  tag = sprintf('%.5f', 10000 * rand(1));
  set(gcf, 'Renderer', 'opengl');
  set(gcf, 'Tag', tag);
  set(gcf, 'UserData', userData);
  set(gcf, 'WindowButtonMotionFcn', ['plotSelection(get(findobj(''Tag'', ''' tag '''), ''UserData''), 0);']);
  set(gcf, 'WindowButtonDownFcn', ['plotSelection(get(findobj(''Tag'', ''' tag '''), ''UserData''), 1);']);
  set(gcf, 'WindowButtonUpFcn', ['plotSelection(get(findobj(''Tag'', ''' tag '''), ''UserData''), 2);']);
end

if ~isfield(cfg,'channelname')
  cfg.channelname = varargin{1}.label{cfg.channelindex};
end

% Create title text containing channel name(s) and channel number(s):
if length(cfg.channelname) == 1
  t=[char(cfg.channelname{1}) ' / ' num2str(cfg.channelindex) ];
else
  t=sprintf('mean(%0s)', join(',',cfg.channelname));
end

h=title(t);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function t = join(separator,cells)
if length(cells)==0
  t = '';
  return;
end
t = char(cells{1});

for i=2:length(cells)
  t = [t separator char(cells{i})];
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function l = cellstrmatch(str,strlist)
l = [];
for k=1:length(strlist)
  if strcmp(char(str),char(strlist(k)))
    l = [l k];
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function z = pwrspctm2cohspctrm(cfg, freq)
% This creates a copy of freq with new entries in the freq.pwrspctrm. The
% TFR corresponding to cfg.cohtargetchannel is set to ones, but all other
% channels are replaced with the coherence TFRs from freq.cohspctrm.
%
% [z] = pwrspctrm2cohspctrm(cfg, freq);
%
% freq should be organised in a structure as obtained from
% the freqdescriptives function.
%
% doudav; 24.09.04
z = freq;
[a a1] = match_str( cfg.cohtargetchannel, z.label);
[a b1] = match_str( cfg.cohtargetchannel, z.labelcmb(:,1));
[a b2] = match_str( cfg.cohtargetchannel, z.labelcmb(:,2));
[a c1] = match_str( z.labelcmb(b1,2), z.label);
[a c2] = match_str( z.labelcmb(b2,1), z.label);
targets  = [c1; c2];
targets2 = [b1; b2];
z.powspctrm(a1,:,:) = ones(size(z.powspctrm(a1,:,:)));
for i=1:size(targets,1),
  z.powspctrm(targets(i),:,:) = squeeze(z.cohspctrm(targets2(i),:,:));
end
clear a a1 b1 b2 c1 c2;
