//---------------------------------------------------------------------------

#ifndef PLAH
#define PLAH

#include "../Apps/BOOM/parallel.h"

class PLA {
  private:
    unsigned int inps;        // # of PLA inputs
    unsigned int outs;       // # of PLA outputs
    PLA_type type;              // PLA type
    bool indexed;        // are indexes valid?

	bool uniq;            // unique terms are present only. TT is generated
	bool keep_TT;			// keeps the TT, even for deleted terms
    TTree TT;               // TTree for uniqueness check.

    TermList data;          // Here are all the terms
    vector<SoPLA> F;          // on-set of each output
    vector<SoPLA> D;          // DC-set of each output
    vector<SoPLA> R;          // off-set of each output

	vector<TermList::iterator> indexterm;		// vector of terms, if PLA is indexed

    vector<string> inames;          // names of input variables. Needs not be defined
    vector<string> onames;          // names of output variables. Needs not be defined

    void Init(void);                    // initializes all the values
public:
    void GenerateOnSet( const unsigned int output);    // Generates on-set of the given output. The result is stored in F[output]
    void GenerateOffSet( const unsigned int output);    // Generates off-set of the given output. The result is stored in F[output]
    void GenerateDCSet( const unsigned int output);    // Generates DC-set of the given output. The result is stored in F[output]

	void Reindex(void);                  // reindex the terms, if indexes are not valid

	PLA(void);
    PLA( const PLA *_pla );			// This is not a copying constructor! Just creates PLA with the same dimensions and type
    PLA( const unsigned int inp, const unsigned int out );
	PLA( const unsigned int inp, const unsigned int out, const PLA_type _type);
    PLA( const list<Term>& _data, const PLA_type _type );
	PLA ( const SoPLA &sopla );
    //~PLA(void);
    void clear(void);                   // clears all the PLA structures

	// setters & getters
    unsigned int inputs(void) const {return inps;};
    unsigned int outputs(void) const {return outs;};
    PLA_type getType(void) const {return type;};
    void setInputs( unsigned int v );
    void setOutputs( unsigned int v );
    void setType(const PLA_type v);                         // are they needed?
    void setType(const string v);                         // are they needed?
	string getIName(const unsigned int i) const;
	string getOName(const unsigned int i) const;
	void setIName(const unsigned int i, const string name);
	void setOName(const unsigned int i, const string name);
 	vector<string> getINames(void) const { return inames;};
	vector<string> getONames(void) const { return onames;};
	void setINames( const vector<string> n ) { inames = n;};
	void setONames( const vector<string> n ) { onames = n;};
	void setUnique(void);    
    void setNonUnique(void);
	void keepTT(void) { keep_TT = true; };			// Sets keeping the TT. Terms from TT will not be deleted when deleting terms. This prevents repeated insertion of a term that is not wanted

	TermList *getData(void) { return &data; };                      // returns pointer to data
	TermList &getDataRef(void) { return data; };                    // returns reference to data
	const list<Term> &getConstDataRef(void) const { return data; };   // returns reference to data
	list<Term>::iterator getTermByIndex(const unsigned int i);	// returns iterator to a term with a given index
    SoPLA *getOnSet(const unsigned int output);  // returns pointer to on-set. Are they needed?
    SoPLA *getOffSet(const unsigned int output);  // returns pointer to off-set. Are they needed?
    SoPLA *getDCSet(const unsigned int output);  // returns pointer to dc-set. Are they needed?
	SoPLA &getOnSetRef(const unsigned int output) { return *getOnSet(output); } ;  // returns reference to on-set. Are they needed?
    SoPLA &getOffSetRef(const unsigned int output) { return *getOffSet(output); } ;  // returns reference to off-set. Are they needed?
    SoPLA &getDCSetRef(const unsigned int output) { return *getDCSet(output); } ;  // returns reference to dc-set. Are they needed?

	unsigned int getIndex( const list<Term>::iterator ti );	// returns index of a term given by iterator

        // data manipulation
    TermList::iterator AppendTerm( const Term &t );            // Appends a term to the PLA. Returns the iterator pointing to this term.
    TermList::iterator AppendTerm( const string iv, const string ov );  // Appends a term to the PLA. Returns the iterator pointing to this term.
    TermList::iterator DeleteTerm(const TermList::iterator ti);   // Deletes term pointed by iterator. Returns iterator of the next one
	void AppendPLA( const PLA &_pla );	// appends a given PLA. Terms are copied to the end
	void AppendTermList( const TermList &terms );	// appends list of terms. Terms are copied to the end
	void Splice(PLA &_pla);    // appends a given PLA to this, the argument PLA is emptied
	void Splice( TermList &terms );	// appends a given list of terms to this, the argument list is emptied
	void Purge(void);							// delete unwanted terms
	void MergeTerms(void);				// merges all terms having equal IM
	void MergeNeighbors(void);			// Repeatitively joins neighboring terms (terms differing in one variable only and having equal OM)
    void RemoveAbsorbed(void);						// removes absorbed terms
	TermList::iterator FindTerm( const string t );	// finds a term with equal IM. If not found, returns data.end();
	void ClearData();					// deletes all terms, but they remain in the (possible) TT.
	void MergePLAs( const PLA &_pla );		// merges two PLAs, regardless their numbers of inputs, outputs, terms. If possible, inputs are matched by input names.


    void LoadPLA(const char *fn);             // Loads PLA from file
    void SavePLA(const char *fn) const;            // Saves PLA to file
    void SaveVHDL(const char *fn);            // Saves VHDL to file

    void NameVars(void);            // if inames and/or onames are NULL, default names are assigned
	void StripNames(void);			// removes the names
	int FindIName( const string name ) const;	// returns index of the name, or -1, if not found
	int FindOName( const string name ) const;	// returns index of the name, or -1, if not found
	bool emptyNames(void) const;	// are the names empty?

        // info functions
    unsigned int getTerms(void) const { return data.size(); };
    unsigned int getLiterals(void);
    unsigned int getOC(void) const;
	unsigned int getGEs(void);		// Returns GEs*2
	bool empty(void) const;			// returns true if the SoPLA is empty

      // Special functions
    bool isImplicantNoOMCheck( const Term& t, const unsigned int output );	// Checks if t is an implicant of the PLA for output. Its value in OM is ignored
	bool isImplicant( const Term& t, const unsigned int output );				// Checks if t is an implicant of the PLA for output. Its value in OM must be '1'
	bool isImplicant( const Term& t );				// Checks if t is an implicant of the PLA for all outputs set to '1'.
	void RemoveUselessTerms();				// Removes terms having all ~ in the output matrix
	void RemoveAllDCCols(void);		// removes all-DC columns from the PLA
	bool isConsistent(void);		// is the PLA consistent? (doesn't the on-set intersect the off-set?)
	bool isConstant(void);			// is the PLA constant 0 or 1?

	void ToF(void);			// Converts PLA to F-type
	void Sort(void);		// sorts the PLA lexicographically, by input and output names

	SoPLA *ToSoPLA( const unsigned int out, const bool _type ) const;
	SoPLA *ToSoPLA( const unsigned int out ) const;

		// for debug purposes
	void DumpOrigin( const char *fn ) const;

	void RemoveAbsorbed(TermQueue * in, TermQueue * tq_rabc);
};

//---------------------------------------------------------------------------
#endif
