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

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


//
// $Log: reduce_fn_nz,v $
// Revision 1.4.1.2  1995/01/13  19:37:42  thoth
// CoreImage has been re-merged with Image.  All special stuff should be
// friends of FBI now.
//
// Revision 1.4.1.1  1994/12/28  18:19:22  thoth
// Image operations are now friendly with FBI
//
// Revision 1.4  1994/07/25  17:26:39  thoth
// Name sanitization
//
// Revision 1.3  1994/01/07  15:12:35  thoth
// Image class is now CoreImage and named image types are
// Image<P,T>.
//
// Revision 1.2  1993/12/29  17:33:18  thoth
// New operator scheme that prevents the need for trivial Image conversions.
//
// Revision 1.1  1993/09/15  13:04:51  thoth
// Initial revision
//
// Revision 1.2  93/05/27  11:49:03  thoth
// Copyright Notices
// 
// Revision 1.1  93/03/10  13:49:13  thoth
// Initial revision
// 

#ifndef REDUCE_ATYPE_LTYPE_OPNAME
#define REDUCE_ATYPE_LTYPE_OPNAME
IA_UnaryOperationsTable<ATYPE,
	IA_BaseImage<IA_Point<int>, LTYPE> >
	*IA_Image_IP_ATYPE_LTYPE_OPNAME_tbl;

void IA_fill_Image_IP_ATYPE_LTYPE_OPNAME_tbl();
#endif // REDUCE_ATYPE_LTYPE_OPNAME


ATYPE OP ( const IA_Image<IA_Point<int>, LTYPE> &arg)
{
    if (!IA_Image_IP_ATYPE_LTYPE_OPNAME_tbl)
	IA_fill_Image_IP_ATYPE_LTYPE_OPNAME_tbl();

    ATYPE(*f)
	(IA_BaseImage<IA_Point<int>, LTYPE> &);
    f = IA_Image_IP_ATYPE_LTYPE_OPNAME_tbl->lookup_operation (arg.type());

    
    IA_BaseImage<IA_Point<int>, LTYPE>	&bip =
	*IA_FBI<IA_Point<int>,IA_Point<int>,LTYPE,LTYPE,LTYPE>
	    ::extract_baseptr(arg);

    return f(bip);
}

#ifndef vec_reduce_ATYPE_LTYPE_OPNAME
#define vec_reduce_ATYPE_LTYPE_OPNAME
static ATYPE
vec_reduce_OPNAME(IA_BaseImage<IA_Point<int>, LTYPE> &lhs_)
{
    const IA_VectorI<IA_Point<int>, LTYPE> *lhs =
	(IA_VectorI<IA_Point<int>, LTYPE> *) &lhs_;

    const LTYPE *ls = lhs->vec;

    ATYPE	rval=*(ls++);

    const unsigned sz = lhs->domain().card();
    for (unsigned i=1; i<sz; i++) {
	rval = SUBOP( rval, (*(ls++)));
    }

    return rval;
}
#endif // vec_reduce_ATYPE_LTYPE_OPNAME

#ifndef scalar_reduce_ATYPE_LTYPE_OPNAME
#define scalar_reduce_ATYPE_LTYPE_OPNAME
static ATYPE
scalar_reduce_OPNAME(IA_BaseImage<IA_Point<int>, LTYPE> &lhs_)
{
    const IA_ConstI<IA_Point<int>, LTYPE> *lhs =
	(IA_ConstI<IA_Point<int>, LTYPE> *) &lhs_;

    ATYPE	rval = lhs->value;
    const unsigned sz = lhs->domain().card();

    for (unsigned i=1; i<sz; i++)
	rval = SUBOP( rval, lhs->value );

    return rval;
}
#endif // scalar_reduce_ATYPE_LTYPE_OPNAME

// scalar-scalar operation is trivial

#ifndef iter_reduce_ATYPE_LTYPE_OPNAME
#define iter_reduce_ATYPE_LTYPE_OPNAME
static ATYPE
iter_reduce_OPNAME(IA_BaseImage<IA_Point<int>, LTYPE> &lhs)
{
    const unsigned sz = lhs.domain().card();

    LTYPE ltmp;
    IA_BaseIVIter<IA_Point<int>, LTYPE>	*liter = lhs.value_iterator();

    liter->next(ltmp);
    ATYPE	rval=ltmp;
    

    for (unsigned i=1; i<sz; i++) {
	liter->next(ltmp);
	rval = SUBOP(rval, ltmp);
    }
    delete liter;

    return rval;
}
#endif // iter_reduce_ATYPE_LTYPE_OPNAME

#ifndef FILL_REDUCE_ATYPE_LTYPE_OPNAME
#define FILL_REDUCE_ATYPE_LTYPE_OPNAME
void IA_fill_Image_IP_ATYPE_LTYPE_OPNAME_tbl()
{
    if (IA_Image_IP_ATYPE_LTYPE_OPNAME_tbl)
	return;

    IA_UnaryOperationsTable<ATYPE,
	IA_BaseImage<IA_Point<int>, LTYPE> >::function f;
    f = iter_reduce_OPNAME;

    IA_Image_IP_ATYPE_LTYPE_OPNAME_tbl = new IA_UnaryOperationsTable<ATYPE,
	IA_BaseImage<IA_Point<int>, LTYPE> >(iter_reduce_OPNAME);
    IA_Image_IP_ATYPE_LTYPE_OPNAME_tbl->add_operation
	(IA_VectorI<IA_Point<int>, LTYPE>::s_type(),
	 vec_reduce_OPNAME);
    IA_Image_IP_ATYPE_LTYPE_OPNAME_tbl->add_operation
	(IA_ConstI<IA_Point<int>, LTYPE>::s_type(),
	 scalar_reduce_OPNAME);

}
#endif // REDUCE_ATYPE_LTYPE_OPNAME

#if 0

static ATYPE vec_reduce_OPNAME(const IA_VectorI<IA_Point<int>, LTYPE> *arg)
{
    const LTYPE *ls = arg->vec;

    ATYPE	rval=*(ls++);

    const unsigned sz = arg->domain().card();
    for (unsigned i=1; i<sz; i++) {
	rval = SUBOP( rval, (*(ls++)));
    }

    return rval;
}

#ifndef const_reduce_ATYPE_LTYPE_OPNAME
#define const_reduce_ATYPE_LTYPE_OPNAME
static ATYPE const_reduce_OPNAME(unsigned sz, LTYPE arg)
{
    ATYPE	rval=arg;
    for (unsigned i=1; i<sz; i++) {
	rval = SUBOP(rval, arg);
    }
    return rval;
}
#endif

static ATYPE iter_reduce_OPNAME(const IA_Image<IA_Point<int>, LTYPE> &arg)
{
    IA_IVIter<IA_Point<int>, LTYPE>	iter(arg);

    LTYPE	temp;
    iter(temp);

    ATYPE	rval=temp;

    while(iter(temp)) {
	rval = SUBOP(rval, temp);
    }

    return rval;
}

ATYPE OP ( const IA_Image<IA_Point<int>, LTYPE> &arg_)
{
    if (arg_.domain().card()==0)
	return ( ZERO );
    IA_Image<IA_Point<int>, LTYPE>	arg(arg_);

    IA_BaseImage<IA_Point<int>, LTYPE>	*bip =
	IA_FBI<IA_Point<int>,IA_Point<int>,LTYPE,LTYPE,LTYPE>
	    ::extract_baseptr(arg);
    if (arg.type() == IA_VectorI<IA_Point<int>, LTYPE>::s_type()) {
	return vec_reduce_OPNAME((IA_VectorI<IA_Point<int>, LTYPE> *)bip);
    } else if (arg.type() == IA_ConstI<IA_Point<int>, LTYPE>::s_type()) {
	return const_reduce_OPNAME
	    (arg.domain().card(),
	     ((IA_ConstI<IA_Point<int>, LTYPE> *)bip)->value);
    } else {
	return iter_reduce_OPNAME(arg);
    }
}
#endif
