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

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


// $Log:	DiscreteImage.h,v $
// Revision 1.14  93/06/10  17:24:02  thoth
// Workaround for 3.0.1 bug.
// 
// Revision 1.13  93/05/27  11:19:40  thoth
// Copyright Notices
// 
// Revision 1.12  93/05/26  17:00:18  thoth
// Read and write of IAA image files.
// 
// Revision 1.11  93/05/18  21:39:51  thoth
// New Point-Point composition closure object.
// New value_array method gives an Array of image values.
// New value-value composition functions.
// 
// Revision 1.10  93/04/29  11:19:18  thoth
// Support for point-point-function and image composition.
// Support for fast vector boxy extension in convolution.
// 
// Revision 1.9  93/04/08  13:11:46  thoth
// restriction is now a virtual method of the BaseDI.
// image translation is now available.
// 
// Revision 1.8  93/03/10  13:34:38  thoth
// range method no longer returns valueset due to
// difficulties with template implementation.
// FunctionDI constructor was not truly generic.
// 
// Revision 1.7  93/02/23  14:17:20  thoth
// set_and_reference_image method encodes common initialization semantics.
// User-defined OtherDIs are now supported.
// FunctionRef images are now supported for quick-hacks.
// 
// Revision 1.6  93/02/20  15:10:06  thoth
// errorDI is used differently now.
// The pointset should go first in an image constructor.
// Function images are no longer supported.
// Image restriction and extension have been revamped.
// 
// Revision 1.5  93/02/17  11:00:48  thoth
// We now have the ability to give away the value vector.
// restriction and extension are no longer operators.  They are methods.
// 
// Revision 1.4  93/02/08  12:58:19  thoth
// The user does not need to know about ErrorDI.
// 
// Revision 1.3  93/01/19  14:56:05  jnw
// Modified to support IA_ naming convention
// 
// Revision 1.2  92/11/13  13:50:02  jnw
// Updated to include all sorts of new goodies
// 
// Revision 1.1  92/10/05  11:42:52  jnw
// Initial revision
// 

#ifndef DiscreteImage_h_
#define DiscreteImage_h_

#include <stream.h>
#include "ia.h"
#include "IntPoint.h"
#include "IntPointSet.h"

#include "BaseDI.h"

template <class T> class IA_ValueSet;

template <class T> class IA_DIVIter;
template <class T> class IA_DIPIter;

#if 0
template <class T> class IA_OtherDI;
#else
#include "OtherDI.h"
#endif

template <class T>
friend ostream& operator <<(ostream&, const IA_DiscreteImage<T>&);


template <class T>
class IA_DiscreteImage {
protected:

    // INVARIANT:  bdip has a value in every image.  The uninitialized
    //		   value is errorDI.
    IA_BaseDI<T> *bdip;

    // Places a valid value in bdip and refcounts appropriately.
    void set_and_reference_image(IA_BaseDI<T> *i);

    // Decrement the BaseDI\'s refcount and delete if necessary.
    void disassociate_image();

    // no one else should be tossing BaseDIs around
    IA_DiscreteImage(IA_BaseDI<T> *base) {
	set_and_reference_image(base);
    }

public:
    IA_DiscreteImage();

    // copy constructor
    IA_DiscreteImage(const IA_DiscreteImage&);

    // const image constructor
    IA_DiscreteImage(const IA_IntPointSet&, const T&);

    // vector image constructor
    IA_DiscreteImage(const IA_IntPointSet&, T *, unsigned, int giveaway);
    IA_DiscreteImage(const IA_IntPointSet&, const T *, unsigned);
    IA_DiscreteImage(const IA_OtherDI<T>& i);
    IA_DiscreteImage(const IA_IntPointSet&, T (*)(const IA_IntPoint&));

    virtual ~IA_DiscreteImage();

    IA_DiscreteImage& operator =(const IA_DiscreteImage &);

    // keep the domain, but make all values the same
    IA_DiscreteImage& operator =(const T&);

    // what sort of image is this?
    IA_DiscreteImageType type() const { return bdip->type(); }

    // retrieve a value from the image
    T operator ()(const IA_IntPoint& p) const {
	if (!domain().contains(p)) {
	    abort();		// throw
	}
	return (*this->bdip)(p);
    }

    // retrieve a reference to a value in the image
    T& operator [](const IA_IntPoint&);

    IA_DiscreteImage restrict( const IA_IntPointSet&) const;
    IA_DiscreteImage restrict( const IA_ValueSet<T>&) const;
    // the next one looks gratuitous --thoth
    //IA_DiscreteImage restrict( int (*)(const IA_IntPoint&)) const;

    // Image Extension -- NOT ASSOCIATIVE!!!
  private:
#define FUNKY_ERROR
    static void vec_vec_2_vec_structcopy (const T **lhs_data,
					  const T **rhs_data,
					  T **dest, const IA_SetStructure &ss);
    static void vec_iter_2_vec_structcopy(const T **lhs_data,
#ifdef FUNKY_ERROR
					  void *rhs_iter,
#else
					  IA_DIVIter<T> *rhs_iter,
#endif
					  T **dest,
					  const IA_SetStructure &ss);
    static void iter_vec_2_vec_structcopy( //
#ifdef FUNKY_ERROR
					   void *lhs_iter,
#else
					   IA_DIVIter<T> *lhs_iter,
#endif
					   const T **rhs_data,
					   T **dest,
					   const IA_SetStructure &ss);
    static void iter_iter_2_vec_structcopy( //
#ifdef FUNKY_ERROR
					    void *lhs_iter,
					    void *rhs_iter,
#else
					    IA_DIVIter<T> *lhs_iter,
					    IA_DIVIter<T> *rhs_iter,
#endif
					    T **dest,
					    const IA_SetStructure &ss);
  public:
    IA_DiscreteImage extend( const IA_DiscreteImage&) const;

    IA_DiscreteImage xlated( const IA_IntPoint &) const;

    IA_IntPointSet domain() const { return this->bdip->domain(); }
    
    IA_ValueSet<T> range() const;
    IA_Array<T> value_array() const { return this->bdip->value_array(); }

    int card() const { return this->domain().card(); }

    int extensivep() const { return this->bdip->extensivep(); }

    T reduce(T (*)(const T&, const T&),T) const;

    T reduce(T (*) (T, T), T) const;

    friend ostream& operator <<(ostream&, const IA_DiscreteImage<T>&);

    static IA_DiscreteImage read_IAA(istream &header, istream &values);
    static IA_DiscreteImage read_IAA(const char *fname1,
				     const char *fname2);
    static IA_DiscreteImage read_IAA(const char *fname);

    void write_IAA(ostream &header, ostream &values) const;

    void write_IAA(const char *fname1, const char *fname2) const;
    void write_IAA(const char *fname) const;

    friend class IA_DIVIter<T>;
    friend class IA_DIPIter<T>;

    friend zero_extend(const IA_DiscreteImage<T> &, const IA_IntPointSet&,
		       T*, T);
};

#include "PPComp.h"

template <class T>
IA_DiscreteImage<T> compose
(const IA_DiscreteImage<T>&,
 const IA_PPCompClosure<IA_IntPoint, IA_IntPoint> &);

template <class T>
IA_DiscreteImage<T> compose(const IA_DiscreteImage<T>&,
			    IA_IntPoint (*)(const IA_IntPoint&));

template <class T>
IA_DiscreteImage<T> compose(T (*)(T), const IA_DiscreteImage<T> &);

template <class S, class T>
IA_DiscreteImage<S> compose(S (*)(T), const IA_DiscreteImage<T> &, const S*);

template <class R, class S, class T>
IA_DiscreteImage<R> compose(R (*)(S), const IA_DiscreteImage<T> &, const R*, const S*);

template <class Q, class R, class S, class T>
IA_DiscreteImage<Q> compose(R (*)(S), const IA_DiscreteImage<T> &, const Q*, const R*, const S*);

#endif
