
// Title:	Block.h
// Date:	28-8-08 (start)

#ifndef BLOCK_H
	#define BLOCK_H					// inclusion guard

	#include <vector>				// rqd. for vector (below)
	using namespace std;

	// User defined consts/vars.
	const int FILE_IO_PRECISION = 20;	// precision specifying no. of digits after dec pt. (15 signif. digits for a double)
	const int L_FILE_IO_STR = 100;		// length of string used in file i/o 
	const double PI = 3.14159265359;	// pi in radians (rounded)
	
	// User defined types
	enum EBlockShape {e_ellipse, e_rectangle, e_triangle};								// block shapes
	enum EBlockDirection {e_left, e_right, e_up, e_down};								// block direction (triangle specific)
	enum EPortArrowDirection {e_left_arrow, e_up_arrow, e_right_arrow, e_down_arrow};	// left '<', up '^', right '>', and, down 'v'

	// BlockShape
	class CBlockShape
	{
	public:
		CBlockShape(const CBlockShape &bs);
		void ReadBlockShapeDataFromFile(ifstream &fin);
		void WriteBlockShapeDataToFile(ofstream &fout);
		void SetBlockDirection(EBlockDirection e_blk_direc);
		void SetBlockWidth(double blk_width);
		double GetBlockHeight(void) const;
		void SetBlockHeight(double blk_height);
		EBlockDirection GetBlockDirection() const;
		double GetBlockWidth() const;
		EBlockShape GetBlockShapeType() const;
		void SetBlockShapeType(EBlockShape e_blk_shape);
		CBlockShape(void);
		~CBlockShape(void);
	
	private:
		double m_dBlockHeight;
		double m_dBlockWidth;
		EBlockDirection m_eBlockDirection;
		EBlockShape m_eBlockShape;
	};

	// Port
	class CBlock;				// predefining CBlock as it's rqd. by CPort, additionally CBlock rqes. CPort
	class CPort
	{
	public:
		CPort(const CPort &port, CBlock &blk);
		void ReadPortDataFromFile(ifstream &fin);
		void WritePortDataToFile(ofstream &fout);
		CBlock &GetRefToBlock(void);
		CPoint GetPortSignPosition(void) const;
		void SetPortSignPosition(CPoint sign_posn);
		CPoint CalculatePortSignPosition(double scale);
		void DrawPortSign(CDC *pDC);
		CPoint CalculatePortPosition(void);
		EPortArrowDirection GetPortArrowDirection(void) const;
		void SetPortArrowDirection(EPortArrowDirection arrow_direc);
		double GetPortPositionAngle() const;
		void SetPortPositionAngle(double angle);
		void DrawPort(CDC *pDC);
		void SetPortPosition(CPoint port_posn);
		CPoint GetPortPosition(void) const;
		void SetPortName(CString name);
		CString GetPortName(void) const;
		CPort(CBlock &block_ref);
		~CPort(void);
	
	private:
		CPoint m_ptPortSignPosition;
		EPortArrowDirection m_ePortArrowDirec;	// '>' arrow pts away/towards block center for output/input (left, up, right, down)
		double	m_dPortPositionAngle;			// angle w.r.t the horiz x-axiz, defining the loc. of the port on the block bndy.
		CBlock	&m_rRefToBlock;					// reference to its parent/own block upon which the port resides
		CPoint	m_ptPortPosition;				// posn of port in generalized coords (not relative coords).
		CString m_strPortName;					// name of either input or output port
	};
	
	// Block
	class CSystemModel;			// predefining CSystemModel as it's rqd. by CBlock, additionally CSystemModel rqes. CBlock
	class CBlock
	{
	public:
		const vector<CPort*> *GetVectorOfInputPortsCopy(void) const;
		const vector<CPort*> *GetVectorOfOutputPortsCopy(void) const;
		CSystemModel * GetSubSystemModel(void) const;
		CBlock(const CBlock &blk);
		virtual CBlock *CopyBlockData(void);
		CSystemModel* GetParentSystemModel(void) const;
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		virtual void ResetBlockData(void);
		virtual void AssignBlockOutputSignal(void);
		int CheckBlockOutputSignalDataValidity(void);
		int ReadDataFromSingleInputSignal(double **&matrix_in, int *nrows_in, int *ncols_in);
		int WriteDataToOutputSignal(double **matrix_out, int nrows, int ncols);
		virtual int OperateOnData(int t_cnt, double t, double delta_t);
		void ReverseBlockDirection(void);
		virtual int SetPortProperties(CPoint point);
		int CheckPortConnection(CPort *port);
		virtual void BlockDlgWndParameterInput(void);
		void SetBlockPosition(CPoint blk_posn);
		void DrawBlockPorts(CDC *pDC);
		void CheckBlockPorts(void);
		vector<CPort*> &GetVectorOfOutputPorts(void);
		vector<CPort*> &GetVectorOfInputPorts(void);
		CBlockShape& GetBlockShape(void);
		CPoint GetBlockPosition() const;
		CBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CBlock(void);
		virtual ~CBlock(void);

		virtual void DrawBlock(CDC *pDC);
		void DrawEllipseBlock(CDC *pDC);
		void DrawRectangleBlock(CDC *pDC);
		void DrawTriangleBlock(CDC *pDC);
		CString GetBlockName(void) const;
		int GetPenColor() const;
		int GetPenWidth() const;
		void SetBlockName(CString blk_name);
	
	private:
		int m_iPenColor;
		int m_iPenWidth;
		CPoint			m_ptBlockPosition;		// ordered pair denoting (x,y) location of CofM of block	
		CString			m_strBlockName;			// block name
		CBlockShape		m_BlockShape;			// member object of type CBlockShape
		vector<CPort*>	m_vecInputPorts;		// vector of ptrs to CPort
		vector<CPort*>	m_vecOutputPorts;		// vector of ptrs to CPort
		CSystemModel	*m_pParentSystemModel;	// ptr to parent system model, i.e. the system model containing the block
		CSystemModel	*m_pSubSystemModel;		// ptr = NULL => no contained system/sub model, ptr != NULL => system model
	};

	// ChirpSignalBlock
	class CChirpSignalBlock : public CBlock
	{
	public:
		virtual void DrawBlock(CDC *pDC);
		CChirpSignalBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CChirpSignalBlock(void);
		~CChirpSignalBlock(void);

	private:
		double	m_dInitFrequency;	// initial frequency
		double	m_dTargetFrequency;	// target frequency
		double	m_dSignalDuration;	// signal duration
	};

	// ConstantBlock
	class CConstantBlock : public CBlock
	{
	public:
		virtual CBlock* CopyBlockData(void);
		CString GetStringConstValue(void) const;
		CConstantBlock(const CConstantBlock &blk);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		virtual int OperateOnData(int t_cnt, double t, double delta_t);
		void BlockDlgWndParameterInput(void);
		virtual void DrawBlock(CDC *pDC);		// OVERRIDING CBlock::DrawBlock(). virtual is a comment
		CConstantBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CConstantBlock(void);
		~CConstantBlock(void);

	private:
		int m_iNcols;
		int m_iNrows;
		double **m_dConstMatrix;
		CString m_strConstValue;
	};

	// DerivativeBlock
	class CDerivativeBlock : public CBlock
	{
	public:
		virtual CBlock* CopyBlockData(void);
		int GetDerivativeMethod(void) const;
		CDerivativeBlock(const CDerivativeBlock &blk);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		void ResetBlockData(void);
		double CalculateFivePointDerivative(double m_f_at_t_minus_2h, double m_f_at_t_minus_h, double f_at_t, double delta_t);
		double CalculateThreePointDerivative(double m_f_at_t_minus_h, double f_at_t, double delta_t);
		virtual int OperateOnData(int t_cnt, double t, double delta_t);
		void BlockDlgWndParameterInput(void);
		virtual void DrawBlock(CDC *pDC);
		CDerivativeBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CDerivativeBlock(void);
		~CDerivativeBlock(void);

	private:
		int	m_i_t_cnt_ref;			// ref time cnt
		int	m_iDerivativeMethod;	// 3-pt method, 5-pt method
		int	m_iNcallsPerTimeCnt;	// no. of times the fn is call per t_cnt (time point)
		int m_iNrows;				// no. of rows of incoming signal matrix
		double *m_f_at_t_minus_h;	// f(t-h)
		double *m_f_at_t_minus_2h;	// f(t-2h)
		double **m_dMatrixOut;		// matrix data of output signals
	};
	
	// DivideBlock
	class CConnection;					// predefining CConnection as it's rqd. by CDivideBlock
	class CDivideBlock : public CBlock
	{
	public:
		virtual CBlock* CopyBlockData(void);
		CString GetStringInitialSignal(void) const;
		int GetMultType(void) const;
		int GetNDivideInputs(void) const;
		int GetNMultiplyInputs(void) const;
		CDivideBlock(const CDivideBlock &blk);
		double** GetInitialSignalMatrix(int &nrows, int &ncols);
		virtual void AssignBlockOutputSignal(void);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		double **DivideMultiplyOperation(double **A, int nrows_A, int ncols_A, CConnection *ptr_to_con,  CString sign, int &nrows_R, int &ncols_R, int &valid);
		virtual int OperateOnData(int t_cnt, double t, double delta_t);
		void ResetOutputPorts(void);
		void UpdateSignCount(void);
		int SetPortProperties(CPoint point);
		void CalculatePortPositionAngles(int n_inputs);
		void ResetInputPorts(int n_mult_ports, int n_divide_ports);
		void BlockDlgWndParameterInput(void);
		virtual void DrawBlock(CDC *pDC);
		CDivideBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CDivideBlock(void);
		~CDivideBlock(void);

	private:
		int m_iMultType;
		int m_iNcolsInitSignal;
		int m_iNDivideInputs;
		int m_iNMultiplyInputs;
		int m_iNrowsInitSignal;
		double **m_dInitSignal;
		CString m_strInitSignal;
	};

	// GainBlock
	class CGainBlock : public CBlock
	{
	public:
		virtual CBlock* CopyBlockData(void);
		CString GetStringGainValue(void) const;
		int GetGainType(void) const;
		CGainBlock(const CGainBlock &blk);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		virtual int OperateOnData(int t_cnt, double t, double delta_t);
		void BlockDlgWndParameterInput();
		virtual void DrawBlock(CDC *pDC);
		CGainBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CGainBlock(void);
		~CGainBlock(void);

	private:
		int	m_iGainType;			// gain type
		int m_iNcols;				// no. of cols of gain matrix
		int m_iNrows;				// no. of rows of gain matrix
		double **m_dGainMatrix;		// gain matrix
		CString m_strGainValue;		// string gain matrix entered by the user
	};

	// IntegratorBlock
	class CIntegratorBlock : public CBlock
	{
	public:
		virtual CBlock* CopyBlockData(void);
		int GetLengthICVector(void) const;
		CString GetStringICVector(void) const;
		CIntegratorBlock(const CIntegratorBlock &blk);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		virtual void ResetBlockData(void);
		int EulerMethod(double *y_at_t, double *m_y_at_t_minus_h, double *m_y_dot_at_t_minus_h, double delta_t, int length_y);
		virtual int OperateOnData(int t_cnt, double t, double delta_t);
		double *ConvertStringToDoubleVector(CString string, int &nrows, int &ncols);
		void BlockDlgWndParameterInput(void);
		virtual void DrawBlock(CDC *pDC);
		CIntegratorBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CIntegratorBlock(void);
		~CIntegratorBlock(void);

	private:
		int m_i_t_cnt_ref;				// ref time cnt
		int m_iLength;					// length of IC vector
		int m_iNcallsPerTimeCnt;		// no. of times the fn is call per t_cnt (time point)
		int m_iNcols;					// no. of cols of the IC vector
		int m_iNrows;					// no. of rows of the IC vector
		int m_iNrowsOut;				// no. of rows of the output matrix m_dMatrixOut
		double *m_dICVector;			// initial condition vector
		double *m_y_at_t_minus_h;		// y_i-1 (y_i at previous iteration)
		double *m_y_dot_at_t_minus_h;	// y_dot_i-1 = f(y_i-1,t_i-1) 
		double **m_dMatrixOut;			// matrix data of output signals
		CString m_strICVector;			// string IC vector entered by the user
	};

	// LinearFnBlock
	class CLinearFnBlock : public CBlock	
	{
	public:
		virtual CBlock* CopyBlockData(void);
		double GetDerivative(void) const;
		double GetValueInitial(void) const;
		double GetTimeFinal(void) const;
		double GetTimeInitial(void) const;
		CLinearFnBlock(const CLinearFnBlock &blk);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		virtual int OperateOnData(int t_cnt, double t, double delta_t);
		void BlockDlgWndParameterInput(void);
		virtual void DrawBlock(CDC *pDC);
		CLinearFnBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CLinearFnBlock(void);
		~CLinearFnBlock(void);

	private:
		double m_dDerivative;	// derivative or slope of linear fn or "curve"
		double m_dTimeInit;		// initial time of signal
		double m_dTimeFinal;	// final time of signal
		double m_dValueInit;	// init value of signal (at time t0)
	};

	// OutputBlock
	class COutputBlock : public CBlock
	{
	public:
		virtual CBlock* CopyBlockData(void);
		COutputBlock(const COutputBlock &blk);
		void WriteNumericalOutputDataToFile(ofstream &fout);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		int GetTimePtDisplay(void) const;
		int GetNotation(void) const;
		void GetDataDimensions(int &nrows, int &ncols) const;
		double** GetOutputMatrix(void) const;
		virtual int OperateOnData(int t_cnt, double t, double delta_t);
		void BlockDlgWndParameterInput(void);
		virtual void DrawBlock(CDC *pDC);
		COutputBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		COutputBlock(void);
		~COutputBlock(void);

	private:
		int m_iNcols;
		int m_iNrows;
		int m_iNotation;
		int m_iTimePtDisplay;
		double **m_dOutputMatrix;
	};

	// SignalGeneratorBlock
	class CSignalGeneratorBlock : public CBlock
	{
	public:
		virtual CBlock* CopyBlockData(void);
		CString GetUnits(void) const;
		CString GetFnType(void) const;
		double GetPhase(void) const;
		double GetFrequency(void) const;
		double GetAmplitude(void) const;
		CSignalGeneratorBlock(const CSignalGeneratorBlock &blk);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		virtual int OperateOnData(int t_cnt, double t, double delta_t);
		void BlockDlgWndParameterInput(void);
		virtual void DrawBlock(CDC *pDC);
		CSignalGeneratorBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CSignalGeneratorBlock(void);
		~CSignalGeneratorBlock(void);

	private:	// externally generated signal is being ignored for now.
		double	m_dAmplitude;
		double	m_dFrequency;
		double	m_dPhase;
		CString	m_strFnType;
		CString m_strUnits;
	};

	// SubsystemBlock
	class CSubsystemBlock : public CBlock
	{
	public:
		virtual CBlock* CopyBlockData(void);
		CString GetOutputPortName(void) const;
		CString GetInputPortName(void) const;
		CSubsystemBlock(const CSubsystemBlock &blk);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		void BlockDlgWndParameterInput(void);
		virtual void DrawBlock(CDC *pDC);
		CSubsystemBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CSubsystemBlock(void);
		~CSubsystemBlock(void);

	private:
		CString		m_strInputPortName;
		CString		m_strOutputPortName;
	};

	// SubsystemInBlock
	class CSubsystemInBlock : public CBlock
	{
	public:
		virtual CBlock* CopyBlockData(void);
		CString GetInputPortName(void) const;
		CSubsystemInBlock(const CSubsystemInBlock &blk);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		void BlockDlgWndParameterInput(void);
		virtual void DrawBlock(CDC *pDC);
		CSubsystemInBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CSubsystemInBlock(void);
		~CSubsystemInBlock(void);

	private:
		CString		m_strInputPortName;
	};

	// SubsystemOutBlock
	class CSubsystemOutBlock : public CBlock
	{
	public:
		virtual CBlock* CopyBlockData(void);
		CString GetOutputPortName(void) const;
		CSubsystemOutBlock(const CSubsystemOutBlock &blk);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		void BlockDlgWndParameterInput(void);
		virtual void DrawBlock(CDC *pDC);
		CSubsystemOutBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CSubsystemOutBlock(void);
		~CSubsystemOutBlock(void);

	private:
		CString		m_strOutputPortName;	// signal identifier (name) to appear as the port label
	};

	// SumBlock
	class CSumBlock : public CBlock
	{
	public:
		virtual CBlock* CopyBlockData(void);
		int GetNSubtractInputs(void) const;
		int GetNAddInputs(void) const;
		CSumBlock(const CSumBlock &blk);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		virtual int OperateOnData(int t_cnt, double t, double delta_t);
		void ResetOutputPorts();
		void UpdateSignCount(void);
		int SetPortProperties(CPoint point);
		void CalculatePortPositionAngles(int n_inputs);
		void ResetInputPorts(int n_add_ports, int n_subtract_ports);
		void BlockDlgWndParameterInput(void);
		virtual void DrawBlock(CDC *pDC);
		CSumBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CSumBlock(void);
		~CSumBlock(void);

	private:
		int m_iNAddInputs;
		int m_iNSubtractInputs;
	};

	// TransferFnBlock
	class CTransferFnBlock : public CBlock
	{
	public:
		virtual CBlock* CopyBlockData(void);
		CString GetStringDenomCoeffs(void) const;
		CString GetStringNumerCoeffs(void) const;
		CTransferFnBlock(const CTransferFnBlock &blk);
		virtual void ReadBlockDataFromFile(ifstream &fin);
		virtual void WriteBlockDataToFile(ofstream &fout);
		double *ConvertStringToDoubleVector(CString string, int &length);
		void BlockDlgWndParameterInput(void);
		virtual void DrawBlock(CDC *pDC);
		CTransferFnBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape);
		CTransferFnBlock(void);
		~CTransferFnBlock(void);

	private:
		int m_iLengthDenom;			// length of the denominator coeff vector
		int m_iLengthNumer;			// length of the numerator coeff vector
		double *m_dNumerVector;		// vector of numerator coeffs
		double *m_dDenomVector;		// vector of denominator coeffs
		CString m_strNumerCoeffs;	// string of numerator coeffs
		CString m_strDenomCoeffs;	// string of denominator coeffs
	};

#endif

// eof