#ifndef GRAPH_H_INCLUDED
#define GRAPH_H_INCLUDED

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

class functionInst;
class functionUser;
class operation;

class variable{
	private :
		string name;	// name can be an empty string

		bool value;

		/**
         * Used=true when a variable is directly or inderectly linked with an input
         * That means : variable will be used during simulation
         **/
		bool used;

		friend class registerV;
		friend class operation;
		friend class functionUser;

	public :
		/// Used only fo creating C program
		/// id is the position of the variable in the variable's list
		short id;

        /// operations for which variable is an input
		vector<operation*> ops;

		variable(string="");

		void SetValue(bool value_){value = value_;};
		bool GetValue(){return value;};

		void SetName(string name_){name = name_;};
		string GetName(){return name;};

		/// Is it a temporary variable or a variable with a name ?
		bool IsTemp(){return (name=="");};

		friend bool CompareVariableName(variable *, variable *);
};

bool CompareVariableName(variable *, variable *);

class registerV{
	private :
		variable *input;
		variable *output;

		bool value;

		friend class functionUser;

		// Just for debug ...
		// TODO : remove this friend class !
		friend class functionUserInst;

	public :
		registerV(variable *input_, variable *output_);

		void SaveRegister();	// Save registers
		void NextClockEdge();	// Copy current value of registers into outputs
};

class operation{
	private :
		functionInst *fun;

		vector<variable*> inputs;
		vector<variable*> outputs;

		short indegree;	// Used by sortListOps of functionUser

		friend class functionUser;

		friend class functionInst;
		friend class functionUserInst;
		friend class functionMem;
		friend class functionAnd;
		friend class functionOr;
		friend class functionXor;
		friend class functionNot;
		friend class functionEqual;

	public :
		unsigned int line;	// used for error reporting

		void AddInput(variable *);
		void AddOutput(variable *);

		short GetNumberOfInputs(){return inputs.size();};
		short GetNumberOfOutputs(){return outputs.size();};

		functionInst *GetFun(){return fun;};

		operation(unsigned int=0);
		operation(operation *op, map<variable *, variable *> &newVar, unsigned int line_=0);
		~operation();
};

#endif // GRAPH_H_INCLUDED
