#ifndef FUNCTION_INST_H_INCLUDED
#define FUNCTION_INST_H_INCLUDED

#include <vector>
#include <string>
using namespace std;

class operation;
class registerV;
class variable;
class functionUser;

/**
 * Abstract class for instantiated functions
 * Each instantiated function class derivated from this abstract class
 **/
class functionInst{
	private :
		friend class operation;

	protected :
		operation *op;

	public :
		functionInst(operation * =0);			// Constructor
		virtual ~functionInst();			// Destructor

		void SetOp(operation *op_);
		operation *GetOp(){return op;};

		/** Evaluate function
		 * Two cases :
		 *  - predifined function :
		 *     * only compute a xor b, ...
		 *  - user function :
		 *     * first copy current value of registers into outputs of register
		 *     * evaluate combinatorial graph
		 *     * copy all inputs of register to current value of registers
		 **/
		virtual void Eval()=0;

		/// Return a copy of this class
		virtual functionInst *Copy()=0;

		// Functions for creating a C program
		virtual void CPutDeclarations(ostream &, const string){};
		virtual void CPutCommands(ostream &, const string , const string)=0;
		virtual void CPutRegistersSave(ostream &, const string){};
		virtual void CPutRegistersNext(ostream &, const string){};
};

/**
 * Class for an instance of functionUser
 * This class keep a copy of all registers owned by functionUser
 **/
class functionUserInst : public functionInst{
	private :
		functionUser *fun;

		/// Real registers of function
		vector<registerV *> registers;

	protected :
		// Internal use only
		void SaveRegisters();
		void NextClockEdge();

	public :
		functionUserInst(functionUser *, operation * = 0, bool = true);
		~functionUserInst();

		bool VerifyNumberOfInputs();
		bool VerifyNumberOfOutputs();

		void Eval();

		functionInst *Copy(){return new functionUserInst(*this);};

		void CPutDeclarations(ostream &, const string);
		void CPutCommands(ostream &, const string, const string);
		virtual void CPutRegistersSave(ostream &, const string);
		virtual void CPutRegistersNext(ostream &, const string);
};

// These class are the class for functions like and, or, xor, ...

class functionAnd : public functionInst{
	public :
		void Eval();
		functionInst *Copy(){return new functionAnd(*this);};
		void CPutCommands(ostream &, const string, const string);

		functionAnd(operation *op_=0) : functionInst(op_){};
};

class functionOr : public functionInst{
	public :
		void Eval();
		functionInst *Copy(){return new functionOr(*this);};
		void CPutCommands(ostream &, const string, const string);

		functionOr(operation *op_=0) : functionInst(op_){};
};

class functionXor : public functionInst{
	public :
		void Eval();
		functionInst *Copy(){return new functionXor(*this);};
		void CPutCommands(ostream &, const string, const string);

		functionXor(operation *op_=0) : functionInst(op_){};
};

class functionNot : public functionInst{
	public :
		void Eval();
		functionInst *Copy(){return new functionNot(*this);};
		void CPutCommands(ostream &, const string, const string);

		functionNot(operation *op_=0) : functionInst(op_){};
};

class functionEqual : public functionInst{
	public :
		void Eval();
		functionInst *Copy(){return new functionEqual(*this);};
		void CPutCommands(ostream &, const string, const string);

		functionEqual(operation *op_=0) : functionInst(op_){};
};

#endif // FUNCTION_INST_H_INCLUDED
