% PLOTCURVE - plot curve(s) with optional significance highlighting.
%
% Usage: >> plotcurve(times, data, 'key1', 'val1', 'key2', val2' ...);
%
% Required inputs:
%   times - [float] vector of time indices
%   data  - [float] data array, size of [n x times]. If n>1 several
%           curves are plotted (unless 'plotmean' option is used).
%
% Optional inputs:
%  'maskarray' = Input bootstrap limits. Can be 1-D [min max], 2-D (min
%                and max for all ordinate) or 3-D (min and max for all
%                ordinates at all time points).
%  'val2mask'  = Value to use for generating mask. By default use data.
%  '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.
%  'xlabel'    = [string] x label
%  'ylabel'    = [string] y label
%  'legend'    = [cell] legend. Cell array of string, with one string
%                per curve.
%  'ylim'      = [min max] or [min] limits for the ordinate axis.
%  '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}
%  'chanlocs'  = channel location structure.
%  'plottopo'  = [min max] plot topography within the time limits defined
%                in this function. If several lines are given as input, one
%                scalp map is plot for each line.
%  'traceinfo' = [string|cell array] information shown on the command line
%                when the user click on a specific trace. Default none.
%
% Authors: Arnaud Delorme, 2004, Bhaktivedanta Institute

% Copyright (C) 2004  Arnaud Delorme
%
% 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 plotcurve( times, R, varargin)

	if nargin < 2
        help plotcurve;
        return;
    end
	g = finputcheck( varargin, { 'maskarray' ''        []       [];
                             'val2mask'      'real'    []           R;
                             'highlightmode' 'string'  { 'background','bottom' } 'background';
                             'plotmean'      'string'  { 'on','off' }            'off';
                             'plotindiv'     'string'  { 'on','off' }            'on';
                             'traceinfo'   { 'string' 'cell' } { { } {} }        'off';
                             'logpval'       'string'  { 'on','off' }            'off';
                             'title'         'string'  []                        '';
                             'xlabel'        'string'  []                        '';
                             'plotmode'      'string'  {'single','topo'}         'single';
                             'plotstderr'    'real'    []                        []; 
                             'ylabel'        'string'  []                        '';
                             'legend'        'cell'    []                        {};
                             'transparent'   'real'    []                        0.5;
                             'colors'        'cell'    []                        {};
                             'plottopotitle' 'cell'    []                        {};
                             'chanlocs'      'struct'  []                        struct;
                             'ylim'          'real'    []                        [];
                             'vert'          'real'    []                        [];
                             'plottopo'      'real'    []                        [];
                             'linewidth'     'real'    []                        2;
                             'marktimes'     'real'    []                        [] });
   if ischar(g), error(g); end
  % keyboard;
   if isempty(g.colors), g.colors = { 'r' 'g' 'b' 'c' 'm' 'r' 'b' 'g' 'c' 'm' 'r' 'b' 'g' 'c' 'm' 'r' 'b' ...
                   'g' 'c' 'm' 'r' 'b' 'g' 'c' 'm' 'r' 'b' 'g' 'c' 'm' 'r' 'b' 'g' 'c' 'm' }; end
   if strcmpi(g.plotindiv, 'off'), g.plotmean = 'on'; end
   
   if ~any(length(times) == size(R))
       try
           R = reshape(R, length(times), length(R)/length(times))';
       catch, error('Size of time input and array input does not match');
       end
   else
       if size(R,3) > 1 && size(R,1) == 1
           R = permute(R, [3 2 1]);
       end
   end
   
   % regions of significance
   % -----------------------
   if ~isempty(g.maskarray)
       if length(unique(g.maskarray)) < 4
          Rregions = g.maskarray;
       else
          Rregions = ones(size(g.val2mask));
          switch dims(g.maskarray)
               case 3, Rregions  (find(g.val2mask > g.maskarray(:,:,1) & (g.val2mask < g.maskarray(:,:,2)))) = 0;
               case 2, if size(g.val2mask,2) == size(g.maskarray,2)
                           Rregions  (find(g.val2mask < g.maskarray)) = 0;
                       elseif size(g.val2mask,1) == size(g.maskarray,1)
                           Rregions(find((g.val2mask > repmat(g.maskarray(:,1),[1 length(times)])) ...
                             & (g.val2mask < repmat(g.maskarray(:,2),[1 length(times)])))) = 0;
                       else
                           Rregions(find((g.val2mask > repmat(g.maskarray(:,1),[1 length(times)])) ...
                             & (g.val2mask < repmat(g.maskarray(:,2),[1 length(times)])))) = 0;
                       end
               case 1, Rregions  (find(g.val2mask < repmat(g.maskarray(:),[1 size(g.val2mask,2)]))) = 0;
           end
           Rregions = sum(Rregions,1);
       end
   else 
       Rregions = [];
   end

  % plot error in shaded area
  % -------------------------
  if ~isempty(g.plotstderr)
      minR = R-g.plotstderr;
      maxR = R+g.plotstderr;
      allpointsx = [times times(end:-1:1)]';
      allpointsy = [ minR maxR(end:-1:1)]';
      h = fill(allpointsx, allpointsy, g.colors{1});
      set(h, 'edgecolor', g.colors{1});
      xlim([ times(1) times(end) ]);
      if ~isempty(g.transparent)
          numfaces = size(get(h, 'Vertices'),1);
          set(h, 'FaceVertexCData', repmat([1 1 1], [numfaces 1]), 'Cdatamapping', 'direct', 'facealpha', g.transparent, 'edgecolor', 'none');
      end
      hold on
      % ordinate limits
      if isempty(g.ylim)
          yll = min(reshape(minR, [1 numel(R)]));
          ylh = max(reshape(maxR, [1 numel(R)]));
          yll2 = yll - (ylh-yll)/10;
          ylh2 = ylh + (ylh-yll)/10;
          if ~isnan(yll), g.ylim = [yll2 ylh2]; end
      end
  end

  % plotting
  % --------
  if size(R,1) == length(times), R = R'; end
  if strcmpi(g.plotmean, 'on') || strcmpi(g.plotindiv, 'off')
      if strcmpi(g.plotindiv, 'on')
          R = [ R; mean(R,1) ];
      else
          R = mean(R,1);
      end
  end
  ax = gca;
  if ~isempty(g.maskarray) && strcmpi(g.highlightmode, 'bottom')
      pos = get(gca, 'position');
      set(gca, 'position', [ pos(1)+pos(3)*0.1 pos(2)+pos(4)*0.1 pos(3)*0.9 pos(4)*0.85 ]);
  end
  
  % plot topographies
  % -----------------
  if ~isempty(g.plottopo)
      tmpax = gca;
      pos = get(gca, 'position');
      set(gca, 'position', [ pos(1) pos(2) pos(3) pos(4)/2 ]);
      
      for index = 1:size(g.plottopo)
          axes('position', [ (index-1)*pos(3)/size(g.plottopo,1)+pos(1) pos(2)+pos(4)/2 pos(3)/size(g.plottopo,1) pos(4)/2 ]);
          %topoplot(g.plottopo(index,:), g.chanlocs, 'maplimits', 'minmax');
          topoplot(g.plottopo(index,:), g.chanlocs);
          if ~isempty(g.plottopotitle)
              title(g.plottopotitle{index}, 'interpreter', 'none');
          end
      end
      
      axes(tmpax);
  end
      
  for ind = 1:size(R,1)
      if ind == size(R,1) && strcmpi(g.plotmean, 'on') && size(R,1) > 1
           plot(times,R(ind,:), 'k', 'linewidth', 2);
      elseif ~isempty(g.colors)
           tmp = plot(times,R(ind,:), 'k'); 
           tmpcol = g.colors{mod(ind-1, length(g.colors))+1};
           if length(tmpcol) > 1, tmpstyle = tmpcol(2:end); tmpcol = tmpcol(1); else tmpstyle = '-'; end
           set(tmp, 'color', tmpcol, 'linestyle', tmpstyle); 
           
           if ~isempty(g.traceinfo)
               if ischar(g.traceinfo) && strcmpi(g.traceinfo, 'on')
                   set(tmp, 'ButtonDownFcn', [ 'disp(''Trace ' int2str(ind) ''');' ]);
               elseif iscell(g.traceinfo)
                   try
                       set(tmp, 'ButtonDownFcn', g.traceinfo{ind});
                   catch,
                       error('Trace info cell array does not contain the same number of element as trace in the graph')
                   end
               end
           end
           
           % change the line style when number of plots exceed number of colors in g.colors
           %lineStyles = {'-', '--',':','-.'};
           %set(tmp,'LineStyle',lineStyles{min(ceil(ind/length(g.colors)),length(lineStyles))});
          
           hold on;
      else plot(times,R(ind,:));
      end
  end
  
  % ordinate limits
  % ---------------
  if isempty(g.ylim)
      yll = min(reshape(R, [1 numel(R)]));
      ylh = max(reshape(R, [1 numel(R)]));
      yll2 = yll - (ylh-yll)/10;
      ylh2 = ylh + (ylh-yll)/10;
      if ~isnan(yll), g.ylim = [yll2 ylh2]; end
  end
  if ~isempty(g.ylim) && length(g.ylim) == 2 
      if any(g.ylim)
          ylim(g.ylim);
      else
          ylim([0 1]);
          axis off;
          box off;
      end
  elseif ~isempty(g.ylim)
      yl = ylim;
      ylim([g.ylim yl(2)]);
  end
  yl = ylim; 

  % highlight regions
  % -----------------
  if ~isempty(g.maskarray)
      axsignif = highlight(ax, times, Rregions, g.highlightmode, g.xlabel);

      % replot data (above highlighted regions)
      % ---------
      axes(ax);
      for ind = 1:size(R,1)
          if ind == size(R,1) && strcmpi(g.plotmean, 'on') && size(R,1) > 1
               plot(times,R(ind,:), 'k', 'linewidth', 2);
          elseif ~isempty(g.colors)          
              tmp = plot(times,R(ind,:), 'k'); set(tmp, 'color', g.colors{mod(ind-1, length(g.colors))+1} ); hold on;
          else plot(times,R(ind,:));
          end
      end
      if strcmpi(g.highlightmode, 'bottom'), xlabel(''); set(ax, 'xtick', []); end
  end
  box on;
  
  ylim(yl);
  if strcmpi(g.logpval, 'on')
      set(gca, 'ytickmode', 'manual', 'yticklabel', round(10.^-get(gca, 'ytick')*1000)/1000, 'ydir', 'reverse');
  end
  
  % vertical lines
  % --------------
  hold on
  xl = xlim;
  if ~isnan(g.marktimes) % plot marked time
      for mt = g.marktimes(:)'
          plot([mt mt],[yl(1) yl(2)],'--k','LineWidth',g.linewidth);
      end
  end
  hold off
  if ~isempty(g.vert)
      for index = 1:length(g.vert)
          line([g.vert(index), g.vert(index)], [yl(1) yl(2)], 'linewidth', 1, 'color', 'm');
      end
  end
  xlim([times(1) times(end)]);

  % title and legend
  % ----------------
  if strcmpi(g.plotmode, 'topo') % plot in scalp array
      NAME_OFFSETX = 0.1;
      NAME_OFFSETY = 0.2;
      xx = xlim; xmin = xx(1); xdiff = xx(2)-xx(1); xpos = double(xmin+NAME_OFFSETX*xdiff);
      yy = ylim; ymax = yy(2); ydiff = yy(2)-yy(1); ypos = double(ymax-NAME_OFFSETY*ydiff);
      t=text(xpos, ypos,g.title);
      axis off;
      line([0 0], [yl(1) yl(2)], 'linewidth', 1, 'color', 'k');
      line([xl(1) xl(2)], [0 0], 'linewidth', 1, 'color', 'k');
      set(ax, 'userdata', { g.xlabel g.ylabel g.legend });
  else
      title(g.title, 'interpreter', 'none')
      if ~isempty(g.legend)
          hh = legend(g.legend(:), 'location', 'southeast');
          set(hh, 'unit', 'pixels', 'interpreter', 'none')
      end
      if isempty(g.maskarray)
          xlabel(g.xlabel);
      end
      ylabel(g.ylabel)
  end
  
% -----------------
% highlight regions
% -----------------
function axsignif = highlight(ax, times, regions, highlightmode, myxlabel);
color1 = [0.75 0.75 0.75];
color2 = [0 0 0];
yl  = ylim; 
yl(1) = yl(1)-max(abs(yl));
yl(2) = yl(2)+max(abs(yl));

if ~strcmpi(highlightmode, 'background')
    pos = get(ax, 'position');
    set(gca, 'xtick', []);
    axsignif = axes('position', [pos(1) pos(2)-pos(4)*0.05 pos(3) pos(4)*0.05 ]);
    plot(times, times, 'w');
    set(axsignif, 'ytick', []);
    yl2 = ylim;
    yl2(1) = yl2(1)-max(abs(yl2));
    yl2(2) = yl2(2)+max(abs(yl2));
    xlim([times(1) times(end)]);
    xlabel(myxlabel);
else
    axsignif = [];
    xlabel(myxlabel);
end

if ~isempty(regions)
    axes(ax);
    in_a_region = 0;
    for index=1:length(regions)
        if regions(index) && ~in_a_region
            tmpreg(1) = times(index);
            in_a_region = 1;
        end
        if (~regions(index) || index == length(regions)) && in_a_region
            tmpreg(2) = times(min(length(times), index));
            in_a_region = 0;
            if strcmpi(highlightmode, 'background')
                tmph = patch([tmpreg(1) tmpreg(2) tmpreg(2) tmpreg(1)], ...
                    [yl(1) yl(1) yl(2) yl(2)], color1); hold on;
                set(tmph, 'edgecolor', color1);
            else
                oldax = ax;
                axes(axsignif);
                tmph = patch([tmpreg(1) tmpreg(2) tmpreg(2) tmpreg(1)], ...
                    [yl2(1) yl2(1) yl2(2) yl2(2)], color2); hold on;
                set(tmph, 'edgecolor', color2);
                axes(oldax);
            end
        end
    end
    ylim(yl);
end
  

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