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

template <class P, class T>
void IA_Image<P,T>::vec_restrict_assign
(const IA_SetStructure &ss, T ** dst,
#ifdef FUNKY_ERROR
 void *src_
#else
 IA_IVIter<P,T> *src
#endif
 )
{
#ifdef FUNKY_ERROR
    IA_IVIter<P,T> *src = (IA_IVIter<P,T> *)src_;
#endif
    T	temp;
    for(int i = 0; i < ss.nintervals(); i++) {
	IA_ss_interval ssi = ss.retrieve_interval(i);
	if (ssi.substructure == IA_SetStructure::BOTH) {
	    for (int j=0; j<ssi.count; j++) {
		if (!(*src)(temp))
		    IA::internal_error(__FILE__,__LINE__);
		*((*dst)++) = temp;
	    }
	} else if (ssi.substructure == IA_SetStructure::FIRST_ONLY) {
	    (*dst) += ssi.count;
	} else if (ssi.substructure == IA_SetStructure::SECOND_ONLY) {
	    for (int j=0; j<ssi.count; j++)
		if (!(*src)(temp))
		    IA::internal_error(__FILE__,__LINE__);
	} else {
	    for (int j=0; j<ssi.count; j++) {
		vec_restrict_assign(ssi.substructure, dst, src);
	    }
	}
    }
}


template <class P, class T>
void IA_Image<P,T>::const_restrict_assign
(const IA_SetStructure &ss, T ** dst,
 T src1,
#ifdef FUNKY_ERROR
 void *src2_
#else
 IA_IVIter<P,T> *src2
#endif
)
{
#ifdef FUNKY_ERROR
    IA_IVIter<P,T> *src2 = (IA_IVIter<P,T> *)src2_;
#endif
    T	temp;
    for(int i = 0; i < ss.nintervals(); i++) {
	IA_ss_interval ssi = ss.retrieve_interval(i);
	if (ssi.substructure == IA_SetStructure::BOTH) {
	    for (int j=0; j<ssi.count; j++) {
		if (!(*src2)(temp))
		    IA::internal_error(__FILE__,__LINE__);
		*((*dst)++) = temp;
	    }
	} else if (ssi.substructure == IA_SetStructure::FIRST_ONLY) {
	    for (int j=0; j<ssi.count; j++)
		*((*dst)++) = src1;
	} else if (ssi.substructure == IA_SetStructure::SECOND_ONLY) {
	    for (int j=0; j<ssi.count; j++)
		if (!(*src2)(temp))
		    IA::internal_error(__FILE__,__LINE__);
	} else {
	    for (int j=0; j<ssi.count; j++) {
		const_restrict_assign(ssi.substructure, dst, src1, src2);
	    }
	}
    }
}


template <class P, class T>
void IA_Image<P,T>::iter_restrict_assign
(const IA_SetStructure &ss, T ** dst,
#ifdef FUNKY_ERROR
 void *src1_, void *src2_
#else
 IA_IVIter<P,T> *src1, IA_IVIter<P,T> *src2
#endif
)
{
#ifdef FUNKY_ERROR
    IA_IVIter<P,T> *src1 = (IA_IVIter<P,T> *)src1_;
    IA_IVIter<P,T> *src2 = (IA_IVIter<P,T> *)src2_;
#endif
    T	temp;
    for(int i = 0; i < ss.nintervals(); i++) {
	IA_ss_interval ssi = ss.retrieve_interval(i);
	if (ssi.substructure == IA_SetStructure::BOTH) {
	    for (int j=0; j<ssi.count; j++) {
		if (!(*src1)(temp))
		    IA::internal_error(__FILE__,__LINE__);
		if (!(*src2)(temp))
		    IA::internal_error(__FILE__,__LINE__);
		*((*dst)++) = temp;
	    }
	} else if (ssi.substructure == IA_SetStructure::FIRST_ONLY) {
	    for (int j=0; j<ssi.count; j++) {
		if (!(*src1)(temp))
		    IA::internal_error(__FILE__,__LINE__);
		*((*dst)++) = temp;
	    }
	} else if (ssi.substructure == IA_SetStructure::SECOND_ONLY) {
	    for (int j=0; j<ssi.count; j++)
		if (!(*src2)(temp))
		    IA::internal_error(__FILE__,__LINE__);
	} else {
	    for (int j=0; j<ssi.count; j++) {
		iter_restrict_assign(ssi.substructure, dst, src1, src2);
	    }
	}
    }
}

template <class P, class T>
IA_Image<P,T> & IA_Image<P,T>::restrict_assign(const IA_Image<P,T>& rhs)
{
    IA_SetStructure ss;
    union_with_structure(this->domain(), rhs.domain(), &ss);
    IA_Set<P>	ps = domain();

    IA_IVIter<P,T> rhs_iter(rhs);

    if (rhs.type() == IA_VectorI<P,T>::s_type()) {
	IA_VectorI<P,T>	*dst;

	if (bip->get_ref() >1) {
	    dst = (IA_VectorI<P,T>*)bip->clone_self_extensively();
	    disassociate_image();
	    set_and_reference_image(dst);
	} else
	    dst = (IA_VectorI<P,T>*)bip;

	T	*dp = dst->vec;

	vec_restrict_assign(ss, &dp, &rhs_iter);

    } else {
	const	int sz = ps.card();
	T	*dp = new T[sz];

	if (rhs.type() == IA_ConstI<P,T>::s_type()) {
	    const IA_ConstI<P,T>	*lhs = (const IA_ConstI<P,T>*)bip;
	    const_restrict_assign(ss, &dp, lhs->value, &rhs_iter);
	} else {
	    IA_IVIter<P,T>	lhs_iter(*this);
	    iter_restrict_assign(ss, &dp, &lhs_iter, &rhs_iter);
	}

	disassociate_image();

	set_and_reference_image(new IA_VectorI<P,T>(ps, dp, sz, 1));
    }

    return *this;
}
