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

#include "stdafx.h"

using namespace std;

#pragma hdrstop

#include "myExcept.h"
#include "bitvector.h"
#include "SoTerm.h"
#include "Term.h"

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


Term::Term(void):
	SoTerm()
{
}

Term::Term( const unsigned int iv, const unsigned int ov ):
	SoTerm(iv)
{
    unsigned int i;
	
	OM.resize( ov );
    for ( i = 0; i < ov; i++ ) OM[i] = '~';
	origin = 0;
}

Term::~Term(void)
{
}

void Term::clear(void)
{
	SoTerm::clear();
	OM.clear();
}

void Term::SetOM( const unsigned int pos, const char val )
{
    if ( pos >= OM.size() ) throw RuntimeException( " Term::SetOM: Index out of range" );
    if ( val != '0' && val != '1' && val != '-' && val != '~' ) throw RuntimeException( "Term::SetOM: Invalid value" );
    OM[pos] = val;
}

void Term::SetOM( const string val )
{
	if ( val.size() != OM.size() && OM.size() != 0 ) throw RuntimeException( " Term::SetOM: Wrong IM size" );
	OM = val;
}

unsigned int Term::GetOC(void) const
// Returns the output cost.

{
    unsigned int j, oc;
    oc = 0;
    for ( j = 0; j < OM.size(); j++ )
        if ( OM[j] == '1' ) oc++;
    return oc;
}

bool Term::Intersects( const Term& t ) const
/*
    Returns: do the terms intersect?
    Checks also outputs
*/
{
    unsigned int i;

    if ( t.IM.size() != this->IM.size() || t.OM.size() != this->OM.size() )
		throw RuntimeException("Term::Intersects:Comparing incompatible terms");
           // do the outputs intersect?
    for ( i = 0; i < OM.size(); i++ )
        if ( this->OM[i] == '1' && t.OM[i] == '1' ) break;
    if ( i == OM.size() ) return false;
           // do the intputs intersect?
	return ( SoTerm::Intersects(t.IM) );
}

int Term::IntersectSize( const Term& t ) const
/*
    Returns: do the terms intersect?
    Checks also outputs
*/
{
    unsigned int i;

    if ( t.IM.size() != this->IM.size() || t.OM.size() != this->OM.size() )
		throw RuntimeException("Term::Intersects: Comparing incompatible terms");
           // do the outputs intersect?
    for ( i = 0; i < OM.size(); i++ )
        if ( this->OM[i] == '1' && t.OM[i] == '1' ) break;
    if ( i == OM.size() ) return -1;
           // do the intputs intersect?
    return ( SoTerm::IntersectSize(t.IM) );
}

unsigned int Term::Relation( const Term& t ) const
/*
    Bit 0: non-empty IM intersection
	Bit 1: t.IM is contained
	Bit 2: IMs are equal
    Bit 3: non-empty OM intersection
	Bit 4: t.OM is contained
	Bit 5: OMs are equal
*/
{
    unsigned int i;
	int res = 63-8;

	if ( t.IM.size() != this->IM.size() || t.OM.size() != this->OM.size() )
     throw RuntimeException("Term:Intersects:Comparing incompatible terms");

	for ( i = 0; i < OM.size(); i++ ) {
        if ( this->OM[i] != '1' && t.OM[i] == '1' ) res &= (63-16);   // t is not contained
		if ( this->OM[i] == '1' && t.OM[i] == '1' ) res |= 8;		// non-empty intersection
		if ( this->OM[i] != t.OM[i] ) res &= (63-32);		// not equal
	}
	for ( i = 0; i < IM.size(); i++ ) {
		if ( abs(this->IM[i] - t.IM[i]) == 1 ) {
			res &= (63-7);   // 0/1 conflict. No intersection
			break;
		}
		if ( this->IM[i] != '-' && t.IM[i] == '-' ) res &= (63-2);		// not contained
		if ( this->IM[i] != t.IM[i] ) res &= (63-4);		// not equal
	}
    return ( res );
}

unsigned int Term::Relation2( const Term& t ) const
/*
    0: non-empty IM intersection, terminates
	Bit 1: t.IM is contained
	Bit 2: IMs are equal
    Bit 3: non-empty OM intersection
	Bit 4: t.OM is contained
	Bit 5: OMs are equal
*/
{
    unsigned int i;
	int res = 63-8;

	if ( t.IM.size() != this->IM.size() || t.OM.size() != this->OM.size() )
		throw RuntimeException("Term::Intersects:Comparing incompatible terms");

	for ( i = 0; i < IM.size(); i++ ) {
		if ( abs(this->IM[i] - t.IM[i]) == 1 ) {
			res = 0;   // 0/1 conflict. No intersection. Terminate
			break;
		}
		if ( this->IM[i] != '-' && t.IM[i] == '-' ) res &= (63-2);		// not contained
		if ( this->IM[i] != t.IM[i] ) res &= (63-4);		// not equal
	}
	if (res != 0) 
	  for ( i = 0; i < OM.size(); i++ ) {
        if ( this->OM[i] != '1' && t.OM[i] == '1' ) res &= (63-16);   // t is not contained
		if ( this->OM[i] == '1' && t.OM[i] == '1' ) res |= 8;		// non-empty intersection
		if ( this->OM[i] != t.OM[i] ) res &= (63-32);		// not equal
	  }
    return res;
}

bool Term::Intersects( const Term& t, const unsigned int _ov ) const
/*
    Returns: do the terms intersect?
    Checks given output only
*/
{
    if ( t.IM.size() != this->IM.size() || t.OM.size() != this->OM.size() )
     throw RuntimeException("Term:Intersects:Comparing incompatible terms");
           // do the outputs intersect?
    if ( this->OM[_ov] == '1' && this->OM[_ov] != t.OM[_ov] ) return false;
           // do the intputs intersect?
	return ( SoTerm::Intersects(t.IM) );
}

bool Term::Contains( const Term& t ) const
/*
    Returns: does it fully contain t?
    Only for f-type PLA
*/
{
    unsigned int i;

    if ( t.OM.size() != this->OM.size() )
		throw RuntimeException("Term::Contains: Comparing incompatible terms");
    for ( i = 0; i < OM.size(); i++ )
        if ( this->OM[i] != '1' && t.OM[i] == '1' ) return false;
	return SoTerm::Contains(t.IM);
}

void Term::Merge( const Term& t )
/*
    Merge the terms by output matrices
    !! the terms are considered to have equal IM
    !! only for fd types
*/
{
    unsigned int i;

    for ( i = 0; i < OM.size(); i++ )
        if ( t.OM[i] == '1' ) this->OM[i] = t.OM[i];
}
