#ifndef FUNCTIONUSER_H_INCLUDED
#define FUNCTIONUSER_H_INCLUDED

#include "graph.h"

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

class operation;
class registerV;
class variable;
class functionUserInst;

/**
 * Class for function created by user
 **/
class functionUser{
	private :
		string name;

		// Registers -> WARNING, these registers must not be used to eval function
		// We copy these registers to functionUserInst when needed
		// And only functionUserInst's registers are really used
		vector<registerV *> registers;

		// WARNING : inputs and outputs are NOT sorted (because otherwise we can't instantiate a function !!!)
		// But listVars is sorted

		// In addition, please notice that inputs and outputs are also in listVars !

		// Inputs of graph's function
		vector<variable *> inputs;
		// Outputs of graph's function
		vector<variable *> outputs;

		// List of operations
		vector<operation *> listOps;

		// Sorted version of this list
		vector<operation *> sortedListOps;

		// List of internal varibales (not inputs nor outputs)
		vector<variable *> listVars;

		// Variable 0 and 1
		variable var0, var1;

		friend class functionUserInst;
		friend class FunctionUserSameName;

	public :
        /**
         * when =-1, you can create any number of instances of this class
         * when >=0, decrement this number at each instanciation, when =0, no instanciation is authorized
         *
         * it's used for preventing instanciating twice a RAM whith --nogc flag
         **/
        short numInst;

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

		void AddOperation(operation *);
		void AddInstFunctionUser(functionUser *, operation *);
		void AddRegister(registerV *);

		void DeleteVariable(variable *);

		variable *GetVariable(string="", bool=true);

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

		short GetNumberOfInputs();
		short GetNumberOfOutputs();

		bool IsInput(variable *);

        bool DecreaseOpsIndegree(variable *, unsigned short &, string &);
		bool SortListOps(string &error);

		// WARNING -> these functions have only to be used when you need to modify value of Inputs or see value of Outputs
		// In any other case (add variable, ..., you have to use other functions !!!!!
		vector<variable *> &GetInputs(){return inputs;};
		vector<variable *> &GetOutputs(){return outputs;};

		// Just evaluate combinatorial graph
		void Eval();

		// Go next clock edge
		// USE this function only when
		void MainNextClockEdge();

		// Functions for creating a C program
		void CPutDeclarations(ostream &, const string);
		void CPutCommands(ostream &, const string);
		void CPutRegistersSave(ostream &, const string);	// only for main program
		void CPutRegistersNext(ostream &, const string);	// only for main program

		functionUser(string="");

		void DestroyGraph();	// destroy the graph associated with function
};

#include <iostream>

/**
 * Enable us to find a functionUser by its name in a list of functionUsers.
 **/
class FunctionUserSameName{
    private :
        string name;
    public :
        FunctionUserSameName(string name_){name=name_;}
        bool operator () (functionUser *f) { return (f->name==name); }
};

#endif // FUNCTIONUSER_H_INCLUDED
