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

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


//
// $Log: Nbh.h,v $
// Revision 1.6  1994/08/22  15:20:29  thoth
// DOS-inspired name rework.
//
// Revision 1.5  1994/07/25  17:26:39  thoth
// Name sanitization
//
// Revision 1.4  1994/05/08  19:40:25  thoth
// New automatic neighborhood decomposition capability.
//
// Revision 1.3  1994/04/15  13:17:48  thoth
// Finish up the list of generic reductions.
//
// Revision 1.2  1994/03/30  13:57:51  thoth
// generic neighborhood reductions are now available.
//
// Revision 1.1  1994/01/31  16:50:30  thoth
// Initial revision
//

#ifndef Neighborhood_h_
#define Neighborhood_h_

#include "BaseNbh.h"
#include "Image.h"

template <class P, class Q, class R, class S, class T> class IA_FBI;

template <class P, class Q>
class IA_Neighborhood {
    template <class R, class S, class T> friend class IA_FBI<P,Q,R,S,T>;
protected:
    IA_BaseNbh<P,Q>	*bnbh;

    void set_and_reference(IA_BaseNbh<P,Q> *);
    void disassociate();

public:
    IA_Neighborhood(unsigned dim, const IA_Set<P> & ps);
    IA_Neighborhood(const IA_Neighborhood &);

    ~IA_Neighborhood();

    IA_Neighborhood& operator=(const IA_Neighborhood &);

    static int	auto_decomposition;

    IA_Set<P> operator()(const Q &p) const { return (*bnbh)(p); }

    IA_Set<Q> domain() const { return bnbh->domain(); }
    IA::Type type() const { return bnbh->type(); }

#include "NbhOps.h"

};

//
//
//

template <class T>
IA_Image<IA_Point<int>, T> neighborhood_reduction
(const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Neighborhood<IA_Point<int>,IA_Point<int> > &tmpl,
 const IA_Set<IA_Point<int> > &dst,
 T (*gamma)(T,T),
 T gamma_zero);

//

template <class S, class T>
IA_Image<IA_Point<int>, S> neighborhood_reduction
(const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Neighborhood<IA_Point<int>,IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dst,
 T gamma_zero,
 S (*Gamma)(T*, unsigned count),
 const S*);

template <class T> inline 
IA_Image<IA_Point<int>, T> neighborhood_reduction
(const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Neighborhood<IA_Point<int>,IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dst,
 T gamma_zero,
 T (*Gamma)(T*, unsigned count)) {
    return neighborhood_reduction(img, nbh, dst, gamma_zero, Gamma, (T*)0);
}

//

template <class S, class T>
IA_Image<IA_Point<int>, S> neighborhood_reduction
(const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Neighborhood<IA_Point<int>,IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dst,
 S (*Gamma)(T*, unsigned count),
 const S*);

template <class T> inline 
IA_Image<IA_Point<int>, T> neighborhood_reduction
(const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Neighborhood<IA_Point<int>,IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dst,
 T (*Gamma)(T*, unsigned count)) {
    return neighborhood_reduction(img, nbh, dst, Gamma, (T*)0);
}

//

template <class T>
IA_Image<IA_Point<int>, T> neighborhood_reduction
(const IA_Neighborhood<IA_Point<int>,IA_Point<int> > &tmpl,
 const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Set<IA_Point<int> > &dst,
 T (*gamma)(T,T),
 T gamma_zero);

//

template <class S, class T>
IA_Image<IA_Point<int>, S> neighborhood_reduction
(const IA_Neighborhood<IA_Point<int>,IA_Point<int> > &nbh,
 const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Set<IA_Point<int> > &dst,
 T gamma_zero,
 S (*Gamma)(T*, unsigned count),
 const S*);

template <class T> inline 
IA_Image<IA_Point<int>, T> neighborhood_reduction
(const IA_Neighborhood<IA_Point<int>,IA_Point<int> > &nbh,
 const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Set<IA_Point<int> > &dst,
 T gamma_zero,
 T (*Gamma)(T*, unsigned count)) {
    return neighborhood_reduction(nbh, img, dst, gamma_zero, Gamma, (T*)0);
}

//

template <class S, class T>
IA_Image<IA_Point<int>, S> neighborhood_reduction
(const IA_Neighborhood<IA_Point<int>,IA_Point<int> > &nbh,
 const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Set<IA_Point<int> > &dst,
 S (*Gamma)(T*, unsigned count),
 const S*);

template <class T> inline 
IA_Image<IA_Point<int>, T> neighborhood_reduction
(const IA_Neighborhood<IA_Point<int>,IA_Point<int> > &nbh,
 const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Set<IA_Point<int> > &dst,
 T (*Gamma)(T*, unsigned count)) {
    return neighborhood_reduction(nbh, img, dst, Gamma, (T*)0);
}

//
// support procedures.
//

template <class T>
IA_Image<IA_Point<int>, T> backw_nbh_inv_core1
(IA_Point<int> src_infimum,
 IA_Point<int> src_width,
 const T* src_data,
 const IA_Set<IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dest_ps,
 T (*gamma)(T, T),
 T gamma_zero);

template <class T>
IA_Image<IA_Point<int>, T> backw_nbh_inv1
(const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Set<IA_Point<int> > &invnbh,
 const IA_Set<IA_Point<int> > &dest_ps,
 T (*gamma)(T, T),
 T gamma_zero);

//

template <class S, class T>
IA_Image<IA_Point<int>, S> backw_nbh_inv_core
(IA_Point<int> src_infimum,
 IA_Point<int> src_width,
 const T* src_data,
 const IA_Set<IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dst,
 S (*Gamma)(T*, unsigned count),
 const S*);

template <class S, class T>
IA_Image<IA_Point<int>, S> backw_nbh_inv
(const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Set<IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dst,
 S (*Gamma)(T*, unsigned count),
 T gamma_zero,
 const S*);

//

template <class S, class T>
IA_Image<IA_Point<int>, S> backw_nbh_inv_core3
(IA_Point<int> src_infimum,
 IA_Point<int> src_width,
 const T* src_data,
 const IA_Set<IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dst,
 S (*Gamma)(T*, unsigned count),
 const S*);

template <class S, class T>
IA_Image<IA_Point<int>, S> backw_nbh_inv3
(const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Set<IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dst,
 S (*Gamma)(T*, unsigned count),
 const S*);

//

template <class T>
IA_Image<IA_Point<int>, T> forw_nbh_inv_core1
(IA_Point<int> src_infimum,
 IA_Point<int> src_width,
 const T* src_data,
 const IA_Set<IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dest_ps,
 T (*gamma)(T, T),
 T gamma_zero);

template <class T>
IA_Image<IA_Point<int>, T> forw_nbh_inv1
(const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Set<IA_Point<int> > &invnbh,
 const IA_Set<IA_Point<int> > &dest_ps,
 T (*gamma)(T, T),
 T gamma_zero);

//

template <class S, class T>
IA_Image<IA_Point<int>, S> forw_nbh_inv_core
(IA_Point<int> src_infimum,
 IA_Point<int> src_width,
 const T* src_data,
 const IA_Set<IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dst,
 S (*Gamma)(T*, unsigned count),
 const S*);

template <class S, class T>
IA_Image<IA_Point<int>, S> forw_nbh_inv
(const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Set<IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dst,
 S (*Gamma)(T*, unsigned count),
 T gamma_zero,
 const S*);

//

template <class S, class T>
IA_Image<IA_Point<int>, S> forw_nbh_inv_core3
(IA_Point<int> src_infimum,
 IA_Point<int> src_width,
 const T* src_data,
 const IA_Set<IA_Point<int> > &src_ps,
 const IA_Set<IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dst,
 S (*Gamma)(T*, unsigned count),
 const S*);

template <class S, class T>
IA_Image<IA_Point<int>, S> forw_nbh_inv3
(const IA_CoreImage<IA_Point<int>, T> &img,
 const IA_Set<IA_Point<int> > &nbh,
 const IA_Set<IA_Point<int> > &dst,
 S (*Gamma)(T*, unsigned count),
 const S*);

#endif // Neighborhood_h_
