// Emacs -*- C++ -*-

//
//	Copyright 1994, Center for Computer Vision and Visualization,
//	University of Florida.  All rights reserved.
//

//
// $Log: metacode,v $
// Revision 1.2.1.1  1994/12/08  14:52:40  thoth
// Intersection between comprehensive and extensive can yield
// extensive result.
//
// Revision 1.2  1994/10/19  15:20:00  thoth
// Seems we need to declare a couple of the classes we use.
//
// Revision 1.1  1994/10/06  19:28:08  thoth
// Initial revision
//

#include "OpTable.h"
#include "Set.h"
#include "BaseSet.h"
#include "LazySet.h"
#include "ValueSet.h"
#include "BSetIter.h"

#include "RGB.h"
#include "Bit.h"
#include <complex.h>

IA_HomogenousBinaryOperationsTable<IA_BaseSet<TYPE> > * IA_Set_TYPENAME_OPNAME_tbl;

static IA_HomogenousBinaryOperationsTable<IA_BaseSet<TYPE> > *&curr_tbl = IA_Set_TYPENAME_OPNAME_tbl;

void IA_fill_Set_TYPENAME_OPNAME_table();

IA_Set<TYPE> OPERATOR(const IA_Set<TYPE> &lhs, const IA_Set<TYPE> &rhs)
{
    if (! curr_tbl) {
	IA_fill_Set_TYPENAME_OPNAME_table();
    }

    IA_BaseSet<TYPE> *(*f)(IA_BaseSet<TYPE> &, IA_BaseSet<TYPE>&);
    f = curr_tbl
	->lookup_operation(lhs.bsp->type(), rhs.bsp->type());

    return f(*lhs.bsp, *rhs.bsp);
}

//
//
//


template <class T>
inline IA_BaseSet<T>*
intersect_valueset(IA_BaseSet<T>&a_, IA_BaseSet<T>&b_) {
    return new IA_ValueSet<T>(*(IA_ValueSet<T> *)&a_
			      &
			      *(IA_ValueSet<T> *)&b_);
}

#if (OPNUM==1)

// #define FRIENDLY

static IA_BaseSet<TYPE>*
intersect_valueset_w_generic(IA_BaseSet<TYPE>&a_, IA_BaseSet<TYPE>&b_) {
    TYPE	*vals = new TYPE[a_.card()];
    int	count=0;
#ifdef FRIENDLY
    IA_ValueSet<TYPE> *a = (IA_ValueSet<TYPE> *)&a_;
    for (int i=0; i<a->size; i++) {
	if (b_->contains(a->value_array[i]))
	    vals[count++] = a->value_array[i];
    }
#else
    {
	IA_BaseSetIter<TYPE>	*iter = a_.iterator();
	TYPE	val;
	while (iter->next(val)) {
	    if (b_.contains(val))
		vals[count++] = val;
	}
	delete iter;
    }
#endif
    IA_BaseSet<TYPE> *rval = new IA_ValueSet<TYPE>(vals, count);
    delete[] vals;
    return rval;
}

static IA_BaseSet<TYPE>*
intersect_generic_w_valueset(IA_BaseSet<TYPE>&b_, IA_BaseSet<TYPE>&a_) {
    TYPE	*vals = new TYPE[a_.card()];
    int	count=0;
#ifdef FRIENDLY
    IA_ValueSet<TYPE> *a = (IA_ValueSet<TYPE> *)&a_;
    for (int i=0; i<a->size; i++) {
	if (b_->contains(a->value_array[i]))
	    vals[count++] = a->value_array[i];
    }
#else
    {
	IA_BaseSetIter<TYPE>	*iter = a_.iterator();
	TYPE	val;
	while (iter->next(val)) {
	    if (b_.contains(val))
		vals[count++] = val;
	}
	delete iter;
    }
#endif
    IA_BaseSet<TYPE> *rval = new IA_ValueSet<TYPE>(vals, count);
    delete[] vals;
    return rval;
}

static IA_BaseSet<TYPE>*
 intersect_generic_set(IA_BaseSet<TYPE>&a, IA_BaseSet<TYPE>&b)
{
    if (a.extensive()) {
	if (a.empty())
	    return new IA_ValueSet<TYPE>((TYPE*)0, 0);

	TYPE	*vals = new TYPE[a.card()]; // can\'t really be bigger...
	int	count=0;

	if (b.extensive()) {

	    if (b.empty())
		return new IA_ValueSet<TYPE>((TYPE*)0, 0);

	    IA_BaseSetIter<TYPE>	*a_iter = a.iterator();
	    IA_BaseSetIter<TYPE>	*b_iter = b.iterator();
	    TYPE	a_val, b_val;

	    if (! (a_iter->next(a_val) && b_iter->next(b_val)) )
		IA::internal_error(__FILE__,__LINE__);

	    while (1) {
		int	comp;
		comp = IA_ValueSet<TYPE>::value_type_compare(&a_val, &b_val);
		if (comp<0) {
		    if (!a_iter->next(a_val))	break; // ran out of values
		} else if (comp>0) {
		    if (!b_iter->next(b_val))	break; // ran out of values
		} else /* comp==0 */ {
		    vals[count++] = a_val; // ==b_val
		    if (! (a_iter->next(a_val) && b_iter->next(b_val)) )
			break;	// ran out of values
		}
	    }
	    delete a_iter;
	    delete b_iter;

	    IA_ValueSet<TYPE>	*rval;
	    rval = new IA_ValueSet<TYPE>(vals, count);
	    delete[] vals;

	    return rval;
	} else /* b.!extensive() */ {
	    IA_BaseSetIter<TYPE>	*iter = a.iterator();
	    TYPE	val;
	    while (iter->next(val)) {
		if (b.contains(val))
		    vals[count++] = val;
	    }
	    delete iter;

	    IA_ValueSet<TYPE>	*rval;
	    rval = new IA_ValueSet<TYPE>(vals, count);
	    delete[] vals;

	    return rval;
	}

    } else /* a.!extensive() */ {
	if (b.extensive()) {
	    if (b.empty())
		return new IA_ValueSet<TYPE>((TYPE*)0, 0);

	    TYPE	*vals = new TYPE[b.card()]; // can\'t really be bigger.
	    int	count=0;

	    IA_BaseSetIter<TYPE>	*iter = b.iterator();
	    TYPE	val;
	    while (iter->next(val)) {
		if (a.contains(val))
		    vals[count++] = val;
	    }
	    delete iter;

	    IA_ValueSet<TYPE>	*rval;
	    rval = new IA_ValueSet<TYPE>(vals, count);
	    delete[] vals;

	    return rval;
	} else  /* b.!extensive() */{
	    return new IA_LazyIntersectionSet<TYPE>(&a, &b);
	}
    }
}

#endif // OPNUM==1


//
//
//


template <class T>
inline IA_BaseSet<T>*
 union_generic_set(IA_BaseSet<T>&a, IA_BaseSet<T>&b) {
    return new IA_LazyUnionSet<T>(&a, &b);
}


template <class T>
inline IA_BaseSet<T>*
union_valueset(IA_BaseSet<T>&a_, IA_BaseSet<T>&b_) {
    return new IA_ValueSet<T>(*(IA_ValueSet<T> *)&a_
			      |
			      *(IA_ValueSet<T> *)&b_);
}

//
//
//


template <class T>
inline IA_BaseSet<T>*
 XOR_generic_set(IA_BaseSet<T>&a, IA_BaseSet<T>&b) {
    return new IA_LazyXORSet<T>(&a, &b);
}


template <class T>
inline IA_BaseSet<T>*
XOR_valueset(IA_BaseSet<T>&a_, IA_BaseSet<T>&b_) {
    return new IA_ValueSet<T>(*(IA_ValueSet<T> *)&a_
			      ^
			      *(IA_ValueSet<T> *)&b_);
}

//
//
//


template <class T>
inline IA_BaseSet<T>*
 minus_generic_set(IA_BaseSet<T>&a, IA_BaseSet<T>&b) {
    return new IA_LazyMinusSet<T>(&a, &b);
}


template <class T>
inline IA_BaseSet<T>*
minus_valueset(IA_BaseSet<T>&a_, IA_BaseSet<T>&b_) {
    return new IA_ValueSet<T>(*(IA_ValueSet<T> *)&a_
			      /
			      *(IA_ValueSet<T> *)&b_);
}

#if (OPNUM==2)

static IA_BaseSet<TYPE>*
minus_valueset_w_generic(IA_BaseSet<TYPE>&a_, IA_BaseSet<TYPE>&b_) {
    TYPE	*vals = new TYPE[a_.card()];
    int	count=0;
#ifdef FRIENDLY
    IA_ValueSet<TYPE> *a = (IA_ValueSet<TYPE> *)&a_;
    for (int i=0; i<a->size; i++) {
	if (b_->contains(a->value_array[i]))
	    vals[count++] = a->value_array[i];
    }
#else
    {
	IA_BaseSetIter<TYPE>	*iter = a_.iterator();
	TYPE	val;
	while (iter->next(val)) {
	    if (!b_.contains(val))
		vals[count++] = val;
	}
	delete iter;
    }
#endif
    IA_BaseSet<TYPE> *rval = new IA_ValueSet<TYPE>(vals, count);
    delete[] vals;
    return rval;
}

#endif // OPNUM==2

//
//
//


void IA_fill_Set_TYPENAME_OPNAME_table()
{
    if (curr_tbl)
	return;

    IA_BaseSet<TYPE> *(*f)(IA_BaseSet<TYPE>&, IA_BaseSet<TYPE>&);
    f = OPNAME_generic_set;
    curr_tbl = new IA_HomogenousBinaryOperationsTable
	< IA_BaseSet<TYPE> >
	    ( f );
    curr_tbl->add_operation
	(IA_ValueSet<TYPE>::s_type(),IA_ValueSet<TYPE>::s_type(),
	 OPNAME_valueset);
#if (OPNUM == 1) || (OPNUM==2)
    curr_tbl->add_operation
	(IA_ValueSet<TYPE>::s_type(), 0,
	 OPNAME_valueset_w_generic);
#endif
#if (OPNUM == 1)
    curr_tbl->add_operation
	( 0, IA_ValueSet<TYPE>::s_type(),
	 OPNAME_generic_w_valueset);
#endif
}
