/**************************************************************************

	Spiker.h													JJS 3/07/96
	
		part of CONICAL, the Computational Neuroscience Class Library
	
	Spiker is a special type of cylindrical compartment, which fires a
	square, stereotyped action potential when its membrane voltage crosses
	a threshold.  The membrane voltage is set to V_high for 
	time_high seconds, then set to V_reset for time_Reset seconds.
	After that, normal membrane kinetics resume.

	Requires:
		Cylinder		-- base class

**************************************************************************/

#ifndef SPIKER_H
#define SPIKER_H

#include "Cylinder.h"

#define kSpikerNormal 0
#define kSpikerInSpike 1
#define kSpikerAfterSpike 2

class Spiker : public Cylinder
{
  public:
  
  	Spiker( void )							// default constructor
  	: Cylinder(),
  	  threshold(-0.020), V_high(0.01), time_high(0.005),
  	  V_reset(-0.050), time_reset(0.010), itsMode(kSpikerNormal) {}

  	Spiker( real pRadius, real pLength )	// constructor (given dimensions)
  	: Cylinder(pRadius,pLength),
  	  threshold(-0.020), V_high(0.01), time_high(0.005),
  	  V_reset(-0.050), time_reset(0.010), itsMode(kSpikerNormal) {}
  	
	inline virtual void Step( const real dt );	// update V[]

	// public variables
	
	real	threshold;		// voltage at which spike is triggered
	real	V_high;			// voltage at top of spike
	real	time_high;		// duration of spike
	real	V_reset;		// voltage to reset to
	real	time_reset;		// absolute refractory period
	
  protected:
	
	// protected variables
	int	itsMode;
	real	itsTimeToGo;
};

inline void Spiker::Step( const real dt )
{
	if (itsMode==kSpikerNormal && GetV() < threshold) {
		Compartment::Step(dt);				// normal kinetics
	}

	else if (itsMode==kSpikerInSpike) {		// at top of spike
		itsTimeToGo -= dt;
		if (itsTimeToGo < 0) {					// top is over
			V[0] = V[1] = V_reset;
			itsMode = kSpikerAfterSpike;
			itsTimeToGo += time_reset;
		}
	}
	
	else if (itsMode==kSpikerAfterSpike) {	// in the after-spike
		itsTimeToGo -= dt;
		if (itsTimeToGo < 0) {					// resume normal function
			itsMode = kSpikerNormal;
		}
	}
	
	else {									// time to initiate a spike
		V[0] = V[1] = V_high;
		itsMode = kSpikerInSpike;
		itsTimeToGo = time_high;
	}
}

#endif
