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

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


static char BaseDIrcsid[] = "$Id: BaseDI.c,v 1.10 93/05/27 11:27:46 thoth Exp $";

// $Log:	BaseDI.c,v $
// Revision 1.10  93/05/27  11:27:46  thoth
// Copyright Notices
// 
// Revision 1.9  93/05/26  16:58:38  thoth
// Performance enhancement.
// 
// Revision 1.8  93/05/18  21:38:08  thoth
// range method returns ValueSet again.
// new value_array method gives an Array of image values.
// 
// 
// Revision 1.7  93/04/17  18:44:27  thoth
// Iterator support is no longer based on a switch statement.  We now
// use a virtual method.  The user can now provide faster iterators.
// 
// Revision 1.6  93/04/08  13:04:29  thoth
// Default restriction and translation methods.
// 
// Revision 1.5  93/03/10  13:30:52  thoth
// range method no longer returns valueset due to
// difficulties with template implementation.
// 
// Revision 1.4  93/02/23  14:04:03  thoth
// clone_self_extensively and range now have default versions.
// DI implementations that can do these operations faster can
// provide their own version that overrides the inherited default.
// 
// Revision 1.3  93/02/20  12:26:41  thoth
// operator[] is no longer inline.  Being virtual and moderately complicated,
// inlineness was not justified.
// 
// Revision 1.2  93/01/19  14:55:32  jnw
// Modified to support IA_ naming convention
// 
// Revision 1.1  92/10/05  11:43:04  jnw
// Initial revision
// 

#include "IPSIter.h"
#include "BaseDI.h"
#include "OtherDIIter.h"
#include "VectorDI.h"


template <class T>
T& IA_BaseDI<T>::operator[](const IA_IntPoint&)
{
    ia_throw( IA::IMAGE_REQUIRE_EXTENSIVE, __FILE__, __LINE__);
    abort(); // internal error
    T	lie;
    return lie;
}

template <class T>
IA_BaseDI<T>* IA_BaseDI<T>::clone_self_extensively() const
{
    // This will throw if the pointset is comprehensive, but
    // we can\'t clone extensively if our domain is comprehensive.
    const unsigned sz = ps.card();

    // We will build a VectorDI
    T *const dest = new T[sz];

    {
	// Iterate over the domain.
	IA_IPSIter	iter(ps);
	// For each point
	IA_IntPoint	ip;
	T *scan = dest;

	while (iter(ip))
	    // evaluate the image at that point and place it in the
	    // proper slot of the vector.
	    *(scan++) = (*this)(ip);
    }

    // Build a VectorDI and give away the value vector.
    return new IA_VectorDI<T>(ps, dest, sz, 1);
}

#if 1
template <class T>
IA_ValueSet<T> IA_BaseDI<T>::range() const
{
    // This will throw if the pointset is comprehensive, but
    // we can\'t compute the range if our domain is comprehensive.
    const unsigned sz = ps.card();

    // We will build a vector of values
    T *const dest = new T[sz];

    {
	// Iterate over the domain.
	IA_IPSIter	iter(ps);
	// For each point
	IA_IntPoint	ip;
	T *scan = dest;

	while (iter(ip))
	    // evaluate the image at that point and place it in the vector.
	    *(scan++) = (*this)(ip);
    }

    IA_ValueSet<T>	rval(dest, sz);
    delete[] dest;

    return rval;
}
#else
template <class T>
T* IA_BaseDI<T>::range(unsigned *sz) const
{
    // This will throw if the pointset is comprehensive, but
    // we can\'t compute the range if our domain is comprehensive.
    *sz = ps.card();

    // We will build a vector of values
    T *const dest = new T[*sz];

    {
	// Iterate over the domain.
	IA_IPSIter	iter(ps);
	// For each point
	IA_IntPoint	ip;
	T *scan = dest;

	while (iter(ip))
	    // evaluate the image at that point and place it in the vector.
	    *(scan++) = (*this)(ip);
    }

    return dest;
}
#endif

template <class T>
IA_Array<T> IA_BaseDI<T>::value_array() const
{
    // This will throw if the pointset is comprehensive, but
    // we can\'t compute the value_array if our domain is comprehensive.
    const unsigned sz = ps.card();

    // We will build a vector of values
    T *const dest = new T[sz];

    {
	// Iterate over the domain.
	IA_IPSIter	iter(ps);
	// For each point
	IA_IntPoint	ip;
	T *scan = dest;

	while (iter(ip))
	    // evaluate the image at that point and place it in the vector.
	    *(scan++) = (*this)(ip);
    }

    return IA_Array<T>(dest, sz, 1);
}

template <class T>
IA_BaseDI<T> *IA_BaseDI<T>::restricted_to(const IA_IntPointSet &ips) const
{
    IA_SetStructure	ss;
    IA_IntPointSet	result_domain =
	intersect_with_structure(this->domain(), ips, &ss);
    if (result_domain == this->domain())
	// clue to reuse this object
	return 0;

    const unsigned	sz = result_domain.card();
    T * const	dest = new T[sz];
    {
	T	*scan = dest;
	IA_IPSIter	iter(result_domain);
	IA_IntPoint	ip;
	while (iter(ip))
	    *(scan++) = (*this)(ip);
    }

    return new IA_VectorDI<T>(result_domain, dest, sz, 1);
}

//
//
//

template <class T>
class IA_LazyXlationDI: public IA_BaseDI<T> {
  private:
    static char	dummy;

    const IA_IntPoint	offset;
    IA_BaseDI<T>	* base;
  public:
    IA_LazyXlationDI(const IA_BaseDI<T> *base_, IA_IntPoint offset_)
    :IA_BaseDI<T>(base_->domain() + offset_), offset(offset_),
     base((IA_BaseDI<T>*)base_) {
	base->incr_ref();
    }
    ~IA_LazyXlationDI() {
	if (base->decr_ref()<=0)
	    delete base;
    }
    int extensivep() const { return 0; }
    T operator() (const IA_IntPoint &p) const {
	return (*base)(p-offset);
    }
    IA_DiscreteImageType type() const { return &dummy; }
    IA_BaseDI<T> * xlated_by(const IA_IntPoint &p) const {
	return new IA_LazyXlationDI<T>(base, p+offset);
    }
    ostream& print_this(ostream&o) const {
	o<< "translation by " << offset << " of \n";
	return base->print_this(o);
    }
};

template <class T>
char IA_LazyXlationDI<T>::dummy;

template <class T>
IA_BaseDI<T> *IA_BaseDI<T>::xlated_by(const IA_IntPoint &p) const
{
    return new IA_LazyXlationDI<T>(this, p);
}

//
// Value iterator support below
//

template <class T>
IA_BaseDIVIter<T> *IA_BaseDI<T>::value_iterator() const
{
    return new IA_OtherDIVIter<T>(this);
}

template <class T>
IA_BaseDIPIter<T> *IA_BaseDI<T>::pixel_iterator() const
{
    return new IA_OtherDIPIter<T>(this);
}

//
//
//

template <class T>
ostream& operator<<(ostream& o, const IA_BaseDI<T>& bdi)
{
    o << "**Discrete Image**\n";
    bdi.print_this(o);
    return o << "\n******************\n" ;
}

