#ifndef BLOCKTYPE_H_
#define BLOCKTYPE_H_

#include "../dataType/Matrix.h"
#include "../dataStruct/MultiDegree.h"
#include "../domain_and_range/DomainType.h"
#include "../domain_and_range/DomainMapping.h"
#include "../domain_and_range/RangePoint.h"
#include "../domain_and_range/DomainPoint.h"

/*
 * Variables can be
 * 		Internal: the Bezier coefficients
 * 		External: the real free coefficients
 *
 * Recalling that they are related by the Matrix m
 * such that:
 * 		(Internal)^T = m (External)^T
 * where both internal and external variables are row vectors
 *
 */

class BlockType
{

	friend class Block;


public:
	int blockTypeId;


	DomainType* domainType;

	int  rangeDimension;

	// Vector of MultiDegrees
	// one for each rangeDimension
	MultiDegree** mdeg;


	int nIntVars;
	int nExtVars;
	/*
	 * Matrix of linear transformation
	 * ExtVars --> IntVars
	 */
	Matrix* m;





	/* Methods */

public:
	BlockType();
	virtual ~BlockType();


	/*
	 * Given two blockTypes:
	 * "blkTypeId0"(with domain D0) and "blkTypeId1"(with domain D1)
	 * and a domain mapping "dm" from D0 -> D1
	 *
	 * Returns the matrix M^{CI} such that
	 * a) i M^{CI}=0
	 *    where
	 *    "i" is the concatenation of "i0" and "i1"
	 *    (the internal vars of blkId0 and blkId1 )
	 *
	 * b) e M^{CE}=0
	 *    where
	 *    "e" is the concatenation of "e0" and "e1"
	 *    (the external vars of blkId0 and blkId1 )
	 */
	static Matrix* getIdentityGlueing_int(int blkTypeId0, int blkTypeId1, DomainMapping *dm);
	static Matrix* getIdentityGlueing_ext(int blkTypeId0, int blkTypeId1, DomainMapping *dm);




protected:
	/* Returns a 1D matrix with the
	 * internal variables calculated from
	 * the external variables
	 */
	Matrix* getIntVars(Matrix* extVar_values);


	/* Evaluate the DomainPoint "U" of
	 * i)  a block with variables "extVar_values"
	 * ii) a block w/ variables indexed by "extVar_Ids"
	 *  */
	RangePoint* evaluate(DomainPoint* U, Matrix* extVar_values);
	RangePoint* evaluate(DomainPoint* U, int* extVar_Ids );




	/*
	 * Given a DomainMapping "dm"
	 * from D-> sD
	 * where
	 * D = this->domainType
	 * and
	 * sD is a subspace of D
	 *
	 * Returns:
	 * the subBlockType, that is the
	 * restriction of this BlockType to
	 * the referred subspace
	 *
	 * IMPORTANT!
	 * This subBlockType will also contain a matrix
	 * that relates the external vars (only the relevant ones)
	 * of the original block to the internal ones
	 */
	BlockType* getSubBlockType(DomainMapping* dm);




	BlockType* getDirDerivativeBlockType(DomainVector* xi);


};

#endif /*BLOCKTYPE_H_*/
