#ifndef _HHChannel_h
#define _HHChannel_h
/**********************************************************************
** This program is part of 'MOOSE', the
** Messaging Object Oriented Simulation Environment,
** also known as GENESIS 3 base code.
**           copyright (C) 2003-2014 Upinder S. Bhalla. and NCBS
** It is made available under the terms of the
** GNU Lesser General Public License version 2.1
** See the file COPYING.LIB for the full notice.
*********************************************************************
*/

/**
 * The HHChannel class sets up a Hodkin-Huxley type ion channel.
 * The form used here is quite general and can handle up to 3 
 * gates, named X, Y and Z. The Z gate can be a function of 
 * concentration as well as voltage. The gates are normally computed
 * using the form
 *
 *            alpha(V)
 * closed <------------> open
 *          beta(V)
 *
 * where the rates for the transition are alpha and beta, and both
 * are functions of V.
 * The state variables for each gate (X_, Y_, and Z_) are 
 * the fraction in the open state.
 *
 * Gates can also be computed instantaneously, giving the instantaneous
 * ratio of alpha to beta rather than solving the above conversion
 * process.
 * The actual functions alpha and beta are provided by an auxiliary
 * class, the HHGate. The idea is that all copies of a channel share the
 * same gate, thus saving a great deal of space. It also makes it 
 * possible to cleanly change the parameters of all the channels of
 * a give class, all at once. Should one want to mutate a subset
 * of channels, they just need to set up separate gates.
 *
 * HHGates are implemented as a special category of FieldElement, so that
 * they can be accessed as readonly pointers available to the HHChannel. 
 * The FieldElement containing the HHGate appears as a child Element of
 * the HHChannel. The HHChannel Element can be an array; the associated
 * HHGate is a singleton. So there has to be a local copy of the HHGate
 * on each node.
 */

class HHChannel: public HHChannelBase, public ChanCommon
{
#ifdef DO_UNIT_TESTS
	friend void testHHChannel();
	friend void testHHGateCreation();
#endif // DO_UNIT_TESTS
	public:
		HHChannel();
		~HHChannel();

		/////////////////////////////////////////////////////////////
		// Value field access function definitions
		/////////////////////////////////////////////////////////////

		void vSetXpower( const Eref& e, double Xpower );
		void vSetYpower( const Eref& e, double Ypower );
		void vSetZpower( const Eref& e, double Zpower );
		void vSetInstant( const Eref& e, int Instant );
		int vGetInstant( const Eref& e ) const;
		void vSetX( const Eref& e, double X );
		double vGetX( const Eref& e ) const;
		void vSetY( const Eref& e, double Y );
		double vGetY( const Eref& e ) const;
		void vSetZ( const Eref& e, double Z );
		double vGetZ( const Eref& e ) const;
		void vSetUseConcentration( const Eref& e, int value );
		void vSetModulation( const Eref& e, double modulation );
		double vGetModulation( const Eref& e ) const;

		void innerSetXpower( double Xpower );
		void innerSetYpower( double Ypower );
		void innerSetZpower( double Zpower );

		/////////////////////////////////////////////////////////////
		// Dest function definitions
		/////////////////////////////////////////////////////////////

		/**
		 * processFunc handles the update and calculations every
		 * clock tick. It first sends the request for evaluation of
		 * the gate variables to the respective gate objects and
		 * recieves their response immediately through a return 
		 * message. This is done so that many channel instances can
		 * share the same gate lookup tables, but do so cleanly.
		 * Such messages should never go to a remote node.
		 * Then the function does its own little calculations to
		 * send back to the parent compartment through regular 
		 * messages.
		 */
		void vProcess( const Eref& e, ProcPtr p );

		/**
		 * Reinitializes the values for the channel. This involves
		 * computing the steady-state value for the channel gates
		 * using the provided Vm from the parent compartment. It 
		 * involves a similar cycle through the gates and then 
		 * updates to the parent compartment as for the processFunc.
		 */
		void vReinit( const Eref& e, ProcPtr p );

		/**
		 * Assign the local Vm_ to the incoming Vm from the compartment
		void handleVm( double Vm );
		 */

		/**
		 * Assign the local conc_ to the incoming conc from the
		 * concentration calculations for the compartment. Typically
		 * the message source will be a CaConc object, but there
		 * are other options for computing the conc.
		 */
		void vHandleConc( const Eref& e, double conc );

		/////////////////////////////////////////////////////////////
		// Gate handling functions
		/////////////////////////////////////////////////////////////
		/**
		 * Access function used for the X gate. The index is ignored.
		 */
		HHGate* vGetXgate( unsigned int i ) const;

		/**
		 * Access function used for the Y gate. The index is ignored.
		 */
		HHGate* vGetYgate( unsigned int i ) const;

		/**
		 * Access function used for the Z gate. The index is ignored.
		 */
		HHGate* vGetZgate( unsigned int i ) const;

		/// Inner utility function for creating the gate.
		void innerCreateGate(
			 const string& gateName,
			HHGate** gatePtr, Id chanId, Id gateId );

		/// Returns true if channel is original, false if copy.
		bool checkOriginal( Id chanId ) const;

		void vCreateGate( const Eref& e, string gateType );
		/**
		 * Utility function for destroying gate. Works only on original
		 * HHChannel. Somewhat dangerous, should never be used after a 
		 * copy has been made as the pointer of the gate will be in use
		 * elsewhere.
		 */
		void destroyGate( const Eref& e, string gateType );

		/**
		 * Inner utility for destroying the gate
		 */
		void innerDestroyGate( const string& gateName,
			HHGate** gatePtr, Id chanId );

		/**
		 * Utility for altering gate powers
		 */
		bool setGatePower( const Eref& e, double power,
			double* assignee, const string& gateType );

		/////////////////////////////////////////////////////////////
		static const Cinfo* initCinfo();

	private:
		/// Conc_ is input variable for Ca-dependent channels.
		double conc_;

		double ( *takeXpower_ )( double, double );
		double ( *takeYpower_ )( double, double );
		double ( *takeZpower_ )( double, double );

		/// bitmapped flag for X, Y, Z, to do equil calculation for gate
		int instant_;
		/// Channel actual conductance depending on opening of gates.
		/// State variable for X gate
		double X_;
		/// State variable for Y gate
		double Y_;
		/// State variable for Z gate
		double Z_;

        bool xInited_, yInited_, zInited_; // true when a state variable
        	// has been initialized
		double g_;	/// Internal variable used to calculate conductance

		double integrate( double state, double dt, double A, double B );

		/**
		 * HHGate data structure for the xGate. This is writable only
		 * on the HHChannel that originally created the HHGate, for others
		 * it must be treated as readonly.
		 */
		HHGate* xGate_;

		/// HHGate data structure for the yGate. 
		HHGate* yGate_;

		/// HHGate data structure for the yGate. 
		HHGate* zGate_;

		Id myId_;

		static const double EPSILON;
		static const int INSTANT_X;
		static const int INSTANT_Y;
		static const int INSTANT_Z;
};


#endif // _HHChannel_h