#ifndef __COMPLEMENT__
#define __COMPLEMENT__

#include "kernelincludes.h"

class Complement
{
	private:
		class MultiResult												// this class is used as a return typ of CheckSpecialCases function
		{
			public:
				MultiResult( Cube * c, const unsigned int s, const bool all2s);				// constructor
				~MultiResult();											// destructor
				Cube * mapa;											// indicates columns of all 1s (by '1' value in the j-th position) and columns of all 0s (by '0' value in the j-th position)
				int split_var;											// says which variable should be chosen as a splitting variable
				bool all2s;												// indicates that a row of all 2s (or '-') was found - in other words it's a tautology
		};

		int BinateSelect(const SoPLA * pla) const;									// says which variable should be chosen as splitting variable - but CheckSpecialCases is used instead
		SoPLA * MergeWithContainment(SoPLA* pla0, SoPLA* pla1, const unsigned int ind) const;// merges two parts of splitted function with respect to the i-th variable
		void PrintPersonalityMatrix(SoPLA * pers_m);					// prints the personality matrix to the output - used only for testing
		void PrintTranslationMatrix(const Cube * V);					// prints the translation matrix to the output - used only for testing
		unsigned int UnateComplement_SplitSelect(const SoPLA * pers_mat) const;				// complutes the splitting variable for splitting the personality matrix of a unate function - this splitting variable is only used while computing unate (while computing unate complement)
		SoPLA * PersCofactors(const SoPLA * pers_mat, const unsigned int j, const bool sign) const;		// computes the cofactors of persoality matrix (!! not PLA !!) with respect to j-th variable
		SoPLA * DemorganForUC(const CubeList::const_iterator ti, const SoPLA *pla) const;		// Demorgan's Law - but only for personality matrix (unate complementation)
		SoPLA * Pers_Unate_Complement(const SoPLA * pers_mat) const;				
		SoPLA * GeneratePersonalMatrix(const SoPLA * pla) const;					// computes the personality matrix of SoPLA
		Cube * Monotone(const SoPLA * pla) const;									// says in which variables is given function monotone (increasing or decreasing)
		SoPLA * Translate(const SoPLA * pers_mat, const Cube * V) const;					// translation from personality matrix back to SoPLA
		SoPLA * UnateComplement(const SoPLA * pla) const;							// computes the comlement of a unate function
		Complement::MultiResult * CheckSpecialCases(const SoPLA * pla) const;		// checks the three special cases in SingleOutputComplement - is used instead of (IsUnate + searching for a column of all 1s or 0s + BinateSelect)
		SoPLA * SingleOutputComplement(SoPLA * fd) const;						// complutes the comlement of a Single-output function. Modifies the source function!
		bool IsUnate(const SoPLA * pla) const;										// says whether given SoPLA is unate or not
		bool containment;												// settings for MergeWithContainment function
		bool merge_shared;												// says whether equal terms contained in several output functions should be merged

		bool  GetContainment() const { return containment; };			// getter for 'containment' settings
		void  SetContainment(const bool c) { containment = c; };		// setter for 'containment' settings 
		bool  GetMergeShared() const { return merge_shared; };			// getter for 'merge_shared' settings 
		void  SetMergeShared(const bool ms) { merge_shared = ms; };		// setter for 'merge_shared' settings 


	public:
		Complement();													// constructor
		//~Complement();

		PLA *PLAComplement( const PLA * pla ) const;						// function for compuping complement of PLA
		SoPLA *PLAComplement( const SoPLA * pla ) const;						// function for compuping complement of PLA

};

#endif













