/**********************************************************************
** This program is part of 'MOOSE', the
** Messaging Object Oriented Simulation Environment.
**           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.
**********************************************************************/

#ifndef _STOICH_H
#define _STOICH_H

/**
 * Stoich is the class that handles the stoichiometry matrix for a
 * reaction system, and also setting up the computations for reaction 
 * rates. It has to coordinate the operation of a number of model 
 * definition classes, most importantly: Pools, Reacs and Enz(yme)s.
 * It also coordinates the setup of a large number of numerical solution
 * engines, or solvers: Ksolve, Gsolve, Dsolve, and SteadyState.
 * The setup process has to follow a tight order, most of which is
 * internally manged by the Stoich.
 * The Stoich itself does not do any 'process' functions. It just sets up
 * data structures for the other objects that do the crunching.
 *
 * 1. Compartment is set up to a cell (neuroMesh) or volume (other meshes)
 * 2. Compartment assigned to Stoich. Here it assigns unique vols.  
 * 3. Dsolve and Ksolve assigned to Stoich using setKsolve and setDsolve.
 * 	 3.1 At this point the Stoich::useOneWay_ flag is set if it is a Gsolve.
 * 4. Call Stoich::setPath. All the rest happens internally, done by Stoich:
 * 		4.1 assign compartment to Dsolve and Ksolve.
 * 		4.2 assign numPools and compts to Dsolve and Ksolve. 
 * 		4.3 During Zombification, zeroth vector< RateTerm* > is built.  
 * 		4.4 afterZombification, stoich builds rateTerm vector for all vols.
 * 		4.5 Stoich assigns itself to Dsolve and Ksolve.  
 * 			- Ksolve sets up volIndex on each VoxelPool 
 * 			- Dsolve gets vector of pools, extracts DiffConst and MotorConst
 * 		4.6 Dsolve assigned to Ksolve::dsolve_ field by the Stoich.
 * 	5. Reinit, 
 * 		5.1 Dsolve builds matrix, provided dt has changed. It needs dt.  
 * 		5.2 Ksolve builds solvers if not done already, assigning initDt 
 *
 * As seen by the user, this reduces to just 4 stages:
 * - Make the objects.
 * - Assign compartment, Ksolve and Dsolve to stoich.
 * - Set the stoich path.
 * - Reinit.
 */

class Stoich
{
	public: 
		Stoich();
		~Stoich();

		//////////////////////////////////////////////////////////////////
		// Field assignment stuff
		//////////////////////////////////////////////////////////////////

		void setOneWay( bool v );
		bool getOneWay() const;

		/// Returns number of local pools that are updated by solver
		unsigned int getNumVarPools() const;

		/// Returns number of local buffered pools.
		unsigned int getNumBufPools() const;

		/**
		 *  Returns total number of pools. Includes the pools whose
		 *  actual calculations happen on another solver, but are given a
		 *  proxy here in order to handle cross-compartment reactions.
		 */
		unsigned int getNumAllPools() const;

		/**
		 * Returns number of proxy pools here for
		 * cross-compartment reactions
		 */
		unsigned int getNumProxyPools() const;

		/** 
		 * Map to look up the index of the pool from its Id.  
		 * poolIndex = poolIdMap[ Id::value() - poolOffset ] 
		 * where the poolOffset is the smallest Id::value.  
		 * poolOffset is passed back as the last entry of this vector.  
		 * Any Ids that are not pools return EMPTY=~0. 
		 */
		vector< unsigned int > getPoolIdMap() const;

		/**
		 * Take the provided wildcard path to build the list of elements
		 * managed by this solver.
		 */
		void setPath( const Eref& e, string path );
		string getPath( const Eref& e ) const;

		/// assigns kinetic solver: Ksovle or GSSAsolve.
		void setKsolve( Id v ); 
		Id getKsolve() const;

		/// assigns diffusion solver: Dsovle or a Gillespie voxel stepper
		void setDsolve( Id v ); 
		Id getDsolve() const;

		/// assigns compartment occupied by Stoich.
		void setCompartment( Id v ); 
		Id getCompartment() const;

		/**
		 * Utility function to return # of rates_ entries. This includes
		 * the cross-solver reactions.
		 */
		unsigned int getNumRates() const;

		/**
		 * Utility function to return # of core rates for reacs which are
		 * entirely located on current compartment, including all reactants
		 */
		unsigned int getNumCoreRates() const;

		/// Utility function to return a rates_ entry
		const RateTerm* rates( unsigned int i ) const;

		/// Returns a reference to the entire rates_ vector.
		const vector< RateTerm* >& getRateTerms() const;

		unsigned int getNumFuncs() const;
		const FuncTerm* funcs( unsigned int i ) const;

		vector< int > getMatrixEntry() const;
		vector< unsigned int > getColIndex() const;
		vector< unsigned int > getRowStart() const;

		vector< Id > getProxyPools( Id i ) const;

		/**
		 * getStatus(): Flag to track status of Stoich object.
		 * -1: No path yet assigned.
		 *  0: Success
		 *  1: Warning: Missing reactant in Reac or Enz
		 *  2: Warning: Missing substrate in MMenz
		 *  4: Warning: Compartment not defined
		 *  8: Warning: Neither Ksolve nor Dsolve defined
		 *  16: Warning: No objects found on path
		 */
		int getStatus() const;
		//////////////////////////////////////////////////////////////////
		// Model traversal and building functions
		//////////////////////////////////////////////////////////////////
		/**
		 * Internal function which sets up the model based on the provided
		 * elist of all elements managed by this solver.
		 */
		void setElist( const Eref& e, const vector< ObjId >& elist );

		/**
		 * Scans through elist to find any reactions that connect to
		 * pools not located on solver. Removes these reactions from the
		 * elist and maintains Ids of the affected reactions, and their 
		 * off-solver pools, in offSolverReacs_ and offSolverPools_.
		 */
		void locateOffSolverReacs( Id myCompt, vector< Id >& elist );
	
		/**
		 * Builds the objMap vector, which maps all Ids to 
		 * the internal indices for pools and reacs that are used in the
		 * solver. In addition to the elist, it also scans through the
		 * offSolverPools and offSolverReacs to build the map.
		void allocateObjMap( const vector< Id >& elist );
		 */

		/// Using the computed array sizes, now allocate space for them.
		void resizeArrays();
		/// Identifies and allocates objects in the Stoich.
		void allocateModelObject( Id id );
		/// Calculate sizes of all arrays, and allocate them.
		void allocateModel( const vector< Id >& elist );

		/// Functions to build the maps between Ids and internal indices
		void buildPoolLookup();
		void buildRateTermLookup();
		void buildFuncLookup();

		/**
		 * This function is used when the stoich class is employed by a 
		 * Gsolver for doing stochastic calculations.
		 * Here we fix the issue of having a single substrate at
		 * more than first order. As the first molecule of the substrate is
		 * consumed, the number is depleted by one and so its forward rate 
		 * is reduced. And so on. This also protects against going negative
		 * in mol number or concentration.
		 */
		void convertRatesToStochasticForm();

		/**
		 * Builds cross-reaction terms between current stoich and 
		 * otherStoich. The function scans the voxels at which there
		 * are jucntions between different compartments, and orchestrates
		 * setup of interfaces between the Ksolves that implement the
		 * cross-reactions at these junctions.
		 */
		void buildXreacs( const Eref& e, Id otherStoich );

		void filterXreacs();

		/// Used to handle run-time size updates for spines.
		void scaleBufsAndRates( unsigned int index, double volScale );

		/**
		 * Expands out list of compartment mappings of proxy reactions to
		 * the appropriate entries on the rates_vector.
		void comptsOnCrossReacTerms( vector< pair< Id, Id > >& xr ) const;
		 */

		/**
		 * Used to set up and update all cross solver reac terms and
		 * their rates, if there has been a change in volumes. Should
		 * also work if there has been a change in voxelization.
		 */
		void setupCrossSolverReacVols() const;

		/**
		 * Finds all the input molecules contributing to any of the
		 * Function cases: poolFunc, incrementFunc or reacFunc
		void inputsToPoolFuncs( 
				vector< pair< Id, vector< unsigned int > > >& ret ) const;
		 */
		//////////////////////////////////////////////////////////////////
		// Zombification functions.
		//////////////////////////////////////////////////////////////////

		/**
		 * zombifyModel marches through the specified id list and 
		 * converts all entries into zombies. The first arg e is the
		 * Eref of the Stoich itself.
		 */
		void zombifyModel( const Eref& e, const vector< Id >& elist );

		/**
		 * Converts back to ExpEuler type basic kinetic Elements.
		 */
		void unZombifyModel();

		/// unZombifies Pools. Helper for unZombifyModel.
		void unZombifyPools();

		void zombifyChemCompt( Id compt );

		/**
		 * Utility function to find if incoming message assigns N or conc,
		 * and to appropriately zombify the function and set up its 
		 * parameters including volume scaling.
		 */
		Id zombifyPoolFuncWithScaling( Id pool );

		unsigned int convertIdToReacIndex( Id id ) const;
		unsigned int convertIdToPoolIndex( Id id ) const;
		unsigned int convertIdToFuncIndex( Id id ) const;

		/// Utility function to make a half reac and return the rate term.
		ZeroOrder* makeHalfReaction( 
						double rate, const vector< Id >& reactants );

		/*
		 * This takes the specified Reac and its substrate and product
		 * list, and installs them into the Stoich. It also builds up the
		 * vectors to store which compartment each substrate/product 
		 * belongs to, needed for cross-reaction computations.
		 * This is the high-level interface function.
		 */
		void installReaction( Id reacId,
				const vector< Id >& subs, const vector< Id >& prds );
		/*
		 * This takes the specified subs and prds belonging
		 * to the specified Reac, and builds them into the Stoich.
		 * It is a low-level function used internally.
		 */
		unsigned int innerInstallReaction( Id reacId, 
				const vector< Id >& subs, const vector< Id >& prds );

		/**
		 * This takes the baseclass for an MMEnzyme and builds the
		 * MMenz into the Stoich.
		 */
		void installMMenz( Id enzId, const vector< Id >& enzMolId,
			const vector< Id >& subs, const vector< Id >& prds );
		/**
		 * This is the inner function to do the installation.
		 */
		void installMMenz( MMEnzymeBase* meb, unsigned int rateIndex,
			const vector< Id >& subs, const vector< Id >& prds );

		/*
		 * This takes the specified Reac and its substrate and product
		 * list, and installs them into the Stoich. This is the high-level
		 * interface function.
		 */
		void installEnzyme( Id enzId, Id enzMolId, Id cplxId,
				const vector< Id >& subs, const vector< Id >& prds );
		/**
		 * This takes the forward, backward and product formation half-reacs
		 * belonging to the specified Enzyme, and builds them into the
		 * Stoich. This is the low-level function.
		 */
		void installEnzyme( ZeroOrder* r1, ZeroOrder* r2, ZeroOrder* r3,
			Id enzId, Id enzMolId, const vector< Id >& prds );

		/// This is used when the enzyme lacks sub or prd.
		void installDummyEnzyme( Id enzId, Id enzMolId);

		/**
		 * This installs a FuncTerm, which evaluates a function to specify
		 * the conc of the specific pool. The pool is a BufPool.
		 */
		void installAndUnschedFunc( Id func, Id pool, double volScale );

		/**
		 * This installs a FuncRate, which evaluates a function to specify
		 * the rate of change of conc of the specific pool. 
		 * The pool is a Pool.
		 */
		void installAndUnschedFuncRate( Id func, Id pool );

		/**
		 * This installs a FuncReac, which evaluates a function to specify
		 * the rate (Kf) of the specified reaction. 
		 */
		void installAndUnschedFuncReac( Id func, Id reac );

		//////////////////////////////////////////////////////////////////

		/**
		 * Returns SpeciesId of specified pool
		 */
		unsigned int getSpecies( unsigned int poolIndex ) const;

		/**
		 * Assigns SpeciesId of specified pool
		 */
		void setSpecies( unsigned int poolIndex, unsigned int s );

		/**
		 * Sets the forward rate v (given in millimoloar concentration units)
		 * for the specified reaction throughout the compartment in which the
		 * reaction lives. Internally the stoich uses #/voxel units so this 
		 * involves querying the volume subsystem about volumes for each
		 * voxel, and scaling accordingly.
		 */
		void setReacKf( const Eref& e, double v ) const;

		/**
		 * Sets the reverse rate v (given in millimoloar concentration units)
		 * for the specified reaction throughout the compartment in which the
		 * reaction lives. Internally the stoich uses #/voxel units so this 
		 * involves querying the volume subsystem about volumes for each
		 * voxel, and scaling accordingly.
		 */
		void setReacKb( const Eref& e, double v ) const;

		/**
		 * Sets the Km for MMenz, using appropriate volume conversion to
		 * go from the argument (in millimolar) to #/voxel.
		 * This may do the assignment among many voxels containing the enz
		 * in case there are different volumes.
		 */
		void setMMenzKm( const Eref& e, double v ) const;
		double getMMenzNumKm( const Eref& e ) const;

		/**
		 * Sets the kcat for MMenz. No conversions needed.
		 */
		void setMMenzKcat( const Eref& e, double v ) const;
		double getMMenzKcat( const Eref& e ) const;

		/**
		 * Sets the rate v (given in millimoloar concentration units)
		 * for the forward enzyme reaction of binding substrate to enzyme.
		 * Does this throughout the compartment in which the
		 * enzyme lives. Internally the stoich uses #/voxel units so this 
		 * involves querying the volume subsystem about volumes for each
		 * voxel, and scaling accordingly.
		 */
		void setEnzK1( const Eref& e, double v ) const;
		double getEnzNumK1( const Eref& e ) const;

		/// Set rate k2 (1/sec) for enzyme
		void setEnzK2( const Eref& e, double v ) const;
		/// Get rate k2 (1/sec) for enzyme
		double getEnzK2( const Eref& e ) const;

		/// Set rate k3 (1/sec) for enzyme
		void setEnzK3( const Eref& e, double v ) const;
		/// Get rate k3, aka kcat, for enzyme
		double getEnzK3( const Eref& e ) const;

		/**
		 * Returns the internal rate in #/voxel, for R1, for the specified
		 * Eref.
		 */
		double getR1( const Eref& e ) const;
		/**
		 * Returns internal rate R1 in #/voxel, for the rate term 
		 * following the one directly referred to by the Eref e. Enzymes
		 * define multiple successive rate terms, so we look up the first,
		 * and then select one after it.
		 */
		double getR1offset1( const Eref& e ) const;
		/**
		 * Returns internal rate R1 in #/voxel, for the rate term 
		 * two after the one directly referred to by the Eref e. Enzymes
		 * define multiple successive rate terms, so we look up the first,
		 * and then select the second one after it.
		 */
		double getR1offset2( const Eref& e ) const;

		/**
		 * Returns the internal rate in #/voxel, for R2, for the specified
		 * reacIndex and voxel index. In some cases R2 is undefined, and it
		 * then returns 0.
		 */
		double getR2( const Eref& e ) const;

		/**
		 * Sets the arithmetic expression used in a FuncRate or FuncReac
		 */
		void setFunctionExpr( const Eref& e, string expr );

		/**
		 * This function scans all reacs and enzymes and recalculates the
		 * internal rate terms depending on the reference terms stored in
		 * the original chemical object.
		 */
		void updateRatesAfterRemesh();

		/// Utility function, prints out N_, used for debugging
		void print() const;

		/// Another utility function, prints out all Kf, kf, Kb, kb.
		void printRates() const;
		//////////////////////////////////////////////////////////////////
		// Utility funcs for numeric calculations
		//////////////////////////////////////////////////////////////////

		/**
		 * Updates the yprime array, rate of change of each molecule
		 * The volIndex specifies which set of rates to use, since the
		 * rates are volume dependent.
		 * Moved to VoxelPools
		void updateRates( const double* s, double* yprime,
					   unsigned int volIndex ) const;
		 */
		
		/**
		 * Computes the velocity of each reaction, vel.
		 * The volIndex specifies which set of rates to use, since the
		 * rates are volume dependent.
		 */
		void updateReacVelocities( const double* s, vector< double >& vel,
					   unsigned int volIndex ) const;

		/// Updates the function values, within s.
		void updateFuncs( double* s, double t ) const;

		/// Updates the rates for cross-compartment reactions.
		/*
		void updateJunctionRates( const double* s,
			   const vector< unsigned int >& reacTerms, double* yprime );
			   */

		/** 
		 * Get the rate for a single reaction specified by r, as per all 
		 * the mol numbers in s.
		double getReacVelocity( unsigned int r, const double* s,
					   unsigned int volIndex ) const;
		 */

		/// Returns the stoich matrix. Used by gsolve.
		const KinSparseMatrix& getStoichiometryMatrix() const;
		//////////////////////////////////////////////////////////////////
		// Access functions for cross-node reactions.
		//////////////////////////////////////////////////////////////////
		const vector< Id >& getOffSolverPools() const;

		/**
		 * List all the compartments to which the current compt is coupled,
		 * by cross-compartment reactions. Self not included.
		 */
		vector< Id > getOffSolverCompts() const;

		/**
		 * Looks up the vector of pool Ids originating from the specified
		 * compartment, that are represented on this compartment as proxies.
		 */
		const vector< Id >& offSolverPoolMap( Id compt ) const;

		/**
		 * Returns the index of the matching volume,
		 * which is also the index into the RateTerm vector.
		unsigned int indexOfMatchingVolume( double vol ) const;
		 */
		
		//////////////////////////////////////////////////////////////////
		static const unsigned int PoolIsNotOnSolver;
		static const Cinfo* initCinfo();
	private:
		/**
		 * True if the stoich matrix is set up to handle only one-way 
		 * reactions, as is needed in the case of the Gillespie algorithm.
		 */
		bool useOneWay_;
		string path_;

		/// This contains the Id of the Kinetic solver.
		Id ksolve_;

		/// This contains the Id of the Diffusion solver. Optional.
		Id dsolve_;

		/// Contains Id of compartment holding reac system. Optional
		Id compartment_;

		/// Pointer for ksolve
		ZombiePoolInterface* kinterface_;
		/// Pointer for dsolve
		ZombiePoolInterface* dinterface_;

		/**
		 * Lookup from each molecule to its Species identifer
		 * This will eventually be tied into an ontology reference.
		 */
		vector< unsigned int > species_;

		/**
		 * The RateTerms handle the update operations for reaction rate v_.
		 * This is the master vector of RateTerms, and it is scaled to
		 * a volume such that the 'n' units and the conc units are
		 * identical.
		 * Duplicates of this vector are made in each voxel with a different
		 * volume. The duplicates have rates scaled as per volume.
		 * The RateTerms vector also includes reactions that have 
		 * off-compartment products. These need special volume scaling 
		 * involving all the interactiong compartments.
		 */
		vector< RateTerm* > rates_;

		/**
		 * This tracks the unique volumes handled by the reac system.
		 * Maps one-to-one with the vector of vector of RateTerms.
		vector< double > uniqueVols_;
		 */

		/// Number of voxels in reac system.
		unsigned int numVoxels_;

		/// The FuncTerms handle mathematical ops on mol levels.
		vector< FuncTerm* > funcs_;

		/// N_ is the stoichiometry matrix. All pools * all reac terms.
		KinSparseMatrix N_;

		/**
		 * Maps Ids to objects in the S_, RateTerm, and FuncTerm vectors.
		 * There will be holes in this map, but look up is very fast.
		 * The calling Id must know what it wants to find: all it
		 * gets back is an integer.
		 * The alternative is to have multiple maps, but that is slower.
		 * Assume no arrays. Each Pool/reac etc must be a unique
		 * Element. Later we'll deal with diffusion.
		 */
		// vector< unsigned int > objMap_;
		/**
		 * Minor efficiency: We will usually have a set of objects that are
		 * nearly contiguous in the map. May as well start with the first of
		 * them.
		 */
		// unsigned int objMapStart_;
		//
		///////////////////////////////////////////////////////////
		// Here we have the vectors of the different kinds of objects
		// managed by the Stoich
		///////////////////////////////////////////////////////////

		/**
		 * Vector of variablePool Ids.
		 */
		vector< Id > varPoolVec_;

		/**
		 * Vector of bufPool Ids.
		 */
		vector< Id > bufPoolVec_;

		/**
		 * These are pools that were not in the original scope of the 
		 * solver, but have to be brought in because they are reactants
		 * of one or more of the offSolverReacs.
		 */
		vector< Id > offSolverPoolVec_;

		/**
		 * Vector of reaction ids.
		 */
		vector< Id > reacVec_;
		vector< Id > offSolverReacVec_;

		/**
		 * Map back from enz index to Id. Needed to unzombify
		 */
		vector< Id > enzVec_;
		vector< Id > offSolverEnzVec_;

		/**
		 * Map back from enz index to Id. Needed to unzombify
		 */
		vector< Id > mmEnzVec_;
		vector< Id > offSolverMMenzVec_;

		/**
		 * Vector of funcs controlling pool number, that is N.
		 */
		vector< Id > poolFuncVec_;
		
		/**
		 * Vector of funcs controlling pool increment, that is dN/dt
		 * This is handled as a rateTerm.
		 */
		vector< Id > incrementFuncVec_;

		/**
		 * Vector of funcs controlling reac rate, that is numKf
		 * This is handled as a rateTerm.
		 */
		vector< Id > reacFuncVec_;

		///////////////////////////////////////////////////////////////
		// Here we have maps to look up objects from their ids.
		///////////////////////////////////////////////////////////////
		map< Id, unsigned int > poolLookup_;
		map< Id, unsigned int > rateTermLookup_;
		map< Id, unsigned int > funcLookup_;

		/**
		 * Number of variable molecules that the solver deals with,
		 * that are local to the solver.
		 *
		 */
		// unsigned int numVarPools_;

		/**
		 * Number of variable molecules that the solver deals with,
		 * including the proxy molecules which belong in other compartments.
		 *
		unsigned int totVarPools_;
		 */

		/**
		 * Number of buffered molecules
		 */
		// unsigned int numBufPools_;

		/**
		 * Looks up the rate term from the Id for a reac, enzyme, or func.
		map< Id, unsigned int > rateTermLookup_;
		 */
		
		/**
		 * Number functions, currently only the ones controlling molecule
		 * numbers, like sumtotals.
		unsigned int numFunctions_;
		 */

		/**
		 * Number of reactions in the solver model. This includes 
		 * conversion reactions A + B <---> C
		 * enzyme reactions E + S <---> E.S ---> E + P
		 * and MM enzyme reactions rate = E.S.kcat / ( Km + S )
		 * The enzyme reactions count as two reaction steps.
		unsigned int numReac_;
		 */

		/**
		 * Flag to track status of Stoich object.
		 * -1: No path yet assigned.
		 *  0: Success
		 *  1: Warning: Missing reactant in Reac or Enz
		 *  2: Warning: Missing substrate in MMenz
		 *  4: Warning: Compartment not defined
		 *  8: Warning: Neither Ksolve nore Dsolve defined
		 */
		int status_;

		//////////////////////////////////////////////////////////////////
		// Off-solver stuff
		//////////////////////////////////////////////////////////////////

		/**
		 * Map of vectors of Ids of offSolver pools. 
		 * Each map entry contains the vector of Ids of proxy pools 
		 * coming from the specified compartment.
		 * In use, the junction will copy the pool indices over for 
		 * data transfer.
		 */
		map< Id, vector< Id > > offSolverPoolMap_; 

		/**
		 * Tracks the reactions that go off the current solver.
		vector< Id > offSolverReacs_;
		 */

		/**
		 * Which compartment(s) does the off solver reac connect to?
		 * Usually it is just one, in which case the second id is Id()
		 */
		vector< pair< Id, Id > > offSolverReacCompts_;
		vector< pair< Id, Id > > offSolverEnzCompts_;
		vector< pair< Id, Id > > offSolverMMenzCompts_;

		/**
		 * subComptVec_[rateTermIndex][substrate#]: Identifies compts
		 * for each substrate for each cross-compartment RateTerm in 
		 * the rates_vector.
		 */
		vector< vector< Id > > subComptVec_;

		/**
		 * prdComptVec_[rateTermIndex][product#]: Identifies compts
		 * for each product for each cross-compartment RateTerm in 
		 * the rates_vector.
		 */
		vector< vector< Id > > prdComptVec_;
};

#endif	// _STOICH_H