function [init_val, init_idx, rise_time, amplitude, ...
	  peak_mag, peak_idx, max_d1o, a_plot] = ...
      calcInitVm(s, max_idx, min_idx, plotit)

% calcInitVm - Calculates spike threshold related measures of the spike_shape, s. 
%
% Usage:
% [init_val, init_idx, rise_time, amplitude,
%  peak_mag, peak_idx, max_d1o, a_plot] = 
%	calcInitVm(s, max_idx, min_idx)
%
% Description:
%
%   Parameters:
%	s: A spike_shape object.
%	max_idx: The index of the maximal point of the spike_shape [dt].
%	min_idx: The index of the minimal point of the spike_shape [dt].
%	plotit: If non-zero, plot a graph annotating the test results 
%		(optional).
%
%   Returns:
%	init_val: The potential value [dy].
%	init_idx: Its index in the spike_shape [dt].
%	rise_time: Time from initiation to maximum [dt].
%	amplitude: Magnitude from initiation to max [dy].
%	peak_mag: Peak value [dy].
%	peak_idx: Extrapolated spike peak index [dt].
%	max_d1o: Maximal value of first voltage derivative [dy].
%	a_plot: plot_abstract, if requested.
%
% See also: spike_shape
%
% $Id$
%
% Author: 
%   Cengiz Gunay <cgunay@emory.edu>, 2004/08/02
%   Based on @spike_trace/shapestats by Jeremy Edgerton.

% Copyright (c) 2007 Cengiz Gunay <cengique@users.sf.net>.
% This work is licensed under the Academic Free License ("AFL")
% v. 3.0. To view a copy of this license, please look at the COPYING
% file distributed with this software or visit
% http://opensource.org/licenses/afl-3.0.php.

if ~ exist('plotit','var')
  plotit = 0;
end
a_plot = [];

% Constants
min_val = s.trace.data(min_idx);
max_val = s.trace.data(max_idx);
max_d1o = NaN;			% comes from calcInitVmMaxCurvPhasePlane

% Find spike initial voltage
s_props = get(s, 'props');
method = s_props.init_Vm_method;

vs = warning('query', 'verbose');
verbose = vs.state;

if strcmp(verbose, 'on')
  disp([get(s, 'id') ', max_idx=' num2str(max_idx) ])
end

% Filter out some spikes

try
switch method

  % peak of voltage acceleration.
  case 1
    deriv = diff(s.trace.data);
    accel = diff(deriv);
    [val, idx] = max(accel(1 : max_idx)); 

  % threshold voltage acceleration.
  case 2
    deriv = diff(s.trace.data);
    accel = diff(deriv);
    idx = find(accel(1 : max_idx) >= s_props.init_threshold); 
    if length(idx) == 0 
      error('calcInitVm:failed', ...
	    sprintf(['Threshold %f failed to find ', ...
		     ' spike initiation acceleration.'], ...
		    s_props.init_threshold));
    end
    idx = idx(1);

  % threshold voltage slope
  case 3
    [idx, a_plot] = ...
	calcInitVmSlopeThreshold(s, max_idx, min_idx, s_props.init_threshold, plotit);

  % Sekerli's method: maximum second derivative in the phase space
  case 4
    [idx, a_plot] = calcInitVmSekerliV2(s, max_idx, min_idx, plotit);

  % Point of maximum curvature: Kp = V''[1 + (V')^2]^(-3/2)
  case 5
    [idx, a_plot] = calcInitVmLtdMaxCurv(s, max_idx, min_idx, s_props.init_lo_thr, ...
					 s_props.init_hi_thr, plotit);

  % Sekerli's method with a twist
  case 6
    [idx, a_plot] = calcInitVmV2PPLocal(s, max_idx, min_idx, ...
					s_props.init_threshold, plotit);

  % threshold voltage derivative by first supersampling using interpolation
  case 7
    [idx, a_plot] = ...
	calcInitVmSlopeThresholdSupsample(s, max_idx, min_idx, s_props.init_threshold, plotit);

  % Point of maximum curvature in phase-plane: Kp = V''[1 + (V')^2]^(-3/2)
  case 8
    try 
      [idx, max_d1o, a_plot, fail_cond] = ...
	  calcInitVmMaxCurvPhasePlane(s, max_idx, min_idx, plotit);

      if ~ fail_cond
	idx = idx(2);
      else
	warning('calcInitVm:info', ...
		['Warning: Max curv phase plane method signal failure, '...
		 'falling back to supersampled threshold method.']);
	[idx, a_plot] = ...
	    calcInitVmSlopeThresholdSupsample(s, max_idx, min_idx, ...
					      s_props.init_threshold, plotit);
      end

    catch
      err = lasterror;
      if strcmp(err.identifier, 'calcInitVm:failed')
	warning('calcInitVm:info', ...
		['Warning: ' err.message ...
		 ' Falling back to supersampled threshold method.']);
	[idx, a_plot] = ...
	    calcInitVmSlopeThresholdSupsample(s, max_idx, min_idx, ...
					      s_props.init_threshold, plotit);
      else
	warning('calcInitVm:info', ['Rethrowing: ']);
	rethrow(err);
      end
    end


  % Combined methods for time-domain derivatives: h and Kp
  case 9
    [idx, a_plot] = calcInitVmV3hKpTinterp(s, max_idx, min_idx, ...
					   s_props.init_lo_thr, ...
					   s_props.init_hi_thr, plotit);
    idx = idx(1);

  otherwise
    error(sprintf('Incorrect spike initiation method: %f', method));
end
catch
  err = lasterror;
  if strcmp(err.identifier, 'calcInitVm:failed')
    warning('calcInitVm:info', ...
	    ['Warning: ' err.message ...
	     ' Taking the fist point in the trace as AP threshold.']);
    idx = 1;
  else
    rethrow(err);
  end
end

% AP init. time
init_idx = idx;

% AP init. Vm
init_val = interpValByIndex(init_idx, s.trace.data);

% Find the REAL max_val
[peak_mag, peak_idx] = estimate_tip(s.trace.data, max_idx);

rise_time = peak_idx - init_idx;	% Init-max Time
amplitude = peak_mag - init_val; % Spike amplitude
  
% Doesn't work well, the spike tips are round, not sharp.
function [peak_mag, peak_idx] = estimate_tip(data, max_idx)

  % Do cubic spline interpolation:
  times = max_idx - 3 : max_idx + 3;
  interp = spline(times, data(times), max_idx - 1:2/10:max_idx + 1);

  [peak_mag, peak_idx] = max(interp);

  peak_idx = max_idx - 1 + (peak_idx - 1) * 2/10;

  return
  
  % THE FOLLOWING IS NOT USED:
  
  % Find the slopes
  slopes = diff(data(max_idx - 3 : max_idx + 3))

  flips = slopes(1:end-2) .* slopes(3:end)

  % Find the first reduction in slope 
  %reduction = find(diff(slopes) < 0);

  % Find the first sign flip in slope 
  flip = find(flips < 0);

  % That's the left corner of the broken tip
  left_idx = max_idx - 2 + reduction(1)
  right_idx = left_idx + 1

  % Find line coefficients
  left_slope = data(left_idx) - data(left_idx - 1)
  left_const = data(left_idx) - left_slope * left_idx

  right_slope = data(right_idx + 1) - data(right_idx)
  right_const = data(right_idx) - right_slope * right_idx

  % Find intersection point
  peak_idx = (left_const - right_const) / (right_slope - left_slope)
  peak_mag = left_slope * peak_idx + left_const