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

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

static char copyright[] = "Copyright 1993, Center for Computer Vision and Visualization,\nUniversity of Florida.  All rights reserved.\n";

static char BitDI_rcsid[] = "$Id: BitDI.c,v 1.4 1994/01/31 15:38:40 thoth Exp $";

//
// $Log: BitDI.c,v $
// Revision 1.4  1994/01/31  15:38:40  thoth
// read and write PBM is now available.
//
// Revision 1.3  1994/01/07  15:15:14  thoth
// Image class is now CoreImage and named image types are
// Image<P,T>.
//
// Revision 1.2  1993/12/29  16:53:13  thoth
// Bit Discrete Image now uses separate Bit type.
//
// Revision 1.1  1993/11/29  22:20:39  thoth
// Initial revision
//
//

#include	"BitDI.h"
#include	"VectorI.h"
#include	"ConstI.h"
#include	"ClosureI.h"
#include	"ErrorI.h"
#include	"ImageIter.h"
#include	"PSIter.h"

#include	<math.h>
#include	<fstream.h>

//
//
//

#include "restrict.h"

IA_BaseImage<IA_Point<int>,IA_Bit> *restrict_toD(const IA_BaseImage<IA_Point<int>, IA_Bit> *im, const IA_Set<IA_Point<int> > &ips) {
    return restrictD_toD(im, ips);
}


//
// below are included the implementations of every image-image
// and image-scalar operation we could think of for binary images.
//

template <class T>
inline T max(T a, T b)
{
    return (a<b)?b:a;
}

template <class T>
inline T min(T a, T b)
{
    return (a<b)?a:b;
}

#include "BitImageOps.c"

//
//
//

istream &wsc(istream &);	// from UcharDI.c

IA_Image<IA_IntPoint,IA_Bit> IA_Image<IA_IntPoint,IA_Bit>::read_PBM(istream &i)
{
    int	width, height,maxval;
    int	code;
    if (i.get()=='P' && ((code=i.get())=='4' || code == '1')
	&& i>>wsc>>width>>wsc>>height) {
	{
	    int	ch = i.get();
	    if (ch!='\n')
		i.putback(ch);
	}

	const unsigned	size=width*height;
	IA_Bit	*data = new IA_Bit[size];

	if (code=='4') {
	    unsigned char	ch;
	    int	idx=0;
	    for (int y=0; y<height; y++) {
		for (int x=0; x<width; x+=8) {
		    ch = i.get();
		    for (int b=0; b<8 && b+x<width; b++, ch <<=1) 
			data[idx++] = (ch&0x80);
		}
	    }
	} else {
	    int	val;
	    int	idx=0;
	    for (int y=0; y<height; y++) {
		for (int x=0; x<width; x+=8) {
		    i >> val;
		    data[idx++] = val;
		}
	    }
	}
	if (i)		// no errors during reading
	    return IA_Image<IA_IntPoint,IA_Bit>
		(IA_IntPointSet(IA_IntPoint(0,0),
				IA_IntPoint(height-1,width-1)),
		 data, size, 1);
    }

    ia_throw(IA::PNM_IO_ERROR, __FILE__, __LINE__);
    return IA_Image<IA_IntPoint,IA_Bit>();
}

IA_Image<IA_IntPoint,IA_Bit> IA_Image<IA_IntPoint,IA_Bit>::read_PBM(const char *fname)
{
    ifstream	in(fname);
    return read_PBM(in);
}

ostream & IA_Image<IA_IntPoint,IA_Bit>::write_PBM(ostream & o) const
{
    // what if image dimension is not 2?

    IA_IntPoint	inf_(domain().inf());
    IA_IntPoint	extent(domain().sup()-domain().inf()+1);
    int	width = extent[1], height=extent[0];

    o << "P4\n";
    o << width << " " << height << "\n";

    for (int y=0; y<height; y++) {
	for (int x=0; x<width; x+=8) {
	    char	val=0;
	    int mask = 0x80;
	    for (int b=0; b<8 && b+x<width; b++, mask >>=1) {
		IA_IntPoint	p(y+inf_[0],x+b+inf_[1]);
		if (this->domain().contains(p) &&
		    (*this)(p))
		    val |= mask;
	    }
	    o.put(val);
	}
    }
    return o;
}

void IA_Image<IA_IntPoint,IA_Bit>::write_PBM(const char *fname) const
{
    ofstream out(fname);
    write_PBM(out);
}

//
//
//


class blah : public IA_ClosureI<IA_IntPoint, IA_Bit> {
  public:
    blah() 
    :IA_ClosureI<IA_IntPoint, IA_Bit>(IA_IntPointSet()) {}
    ostream &print_this(ostream &o) const { return o;}
    IA_Bit operator()(const IA_IntPoint &) const { return 0; }
    IA_ClosureI<IA_IntPoint, IA_Bit>* clone_self() const { return 0; }
};
static void dummy001()
{
    IA_IntPoint		ip;
    IA_IntPointSet	ps;
    IA_Image<IA_IntPoint,IA_Bit>	i1;
    IA_Image<IA_IntPoint,IA_Bit>
	i2(i1),
	i3(ps,0),
	i4(ps, (IA_Bit*)0, 0, 1),
	i5(ps, (IA_Bit*)0, 0),
	i6(blah()),
	i7(ps, (IA_Bit(*)(const IA_IntPoint&))0),
	i10(IA_CoreImage<IA_IntPoint,IA_Bit>());
    IA_Bit sc;

    i1 = i1.restrict(i2.range());
    i1 = i1.translate(ip);
    (IA_CoreImage<IA_IntPoint,IA_Bit>&)i1 = 2;
    (void)i1.type();
    i1[ip] = i1(ip);
    i1 = i1.restrict(i2.domain());
    (void)i1.extend(i2);
    (void)i1.reduce((IA_Bit (*)(const IA_Bit&,const IA_Bit&)) 0, 0);
    (void)i1.reduce((IA_Bit (*)( IA_Bit, IA_Bit)) 0, 0);
    cout << (IA_CoreImage<IA_IntPoint,IA_Bit>&)i1;

#if 0
    IA_Image<IA_IntPoint,IA_Bit>::read_IAA("");
    IA_Image<IA_IntPoint,IA_Bit>::read_IAA("","");

    i1.write_IAA("");
    i1.write_IAA("","");
#endif

    IA_IVIter<IA_IntPoint,IA_Bit>	iter1(i1), iter2;
    IA_IPIter<IA_IntPoint,IA_Bit>	iter3(i2), iter4;
    iter1 = iter2;
    iter3 = iter4;
#if 1
    iter1.reset();
    iter1(sc);
    iter3.reset();
    iter3(ip, sc);
#endif
    compose(i1, (IA_IntPoint(*)(const IA_IntPoint&))0);
    compose(i1, *(IA_Closure<IA_IntPoint, IA_IntPoint>*)0);
    compose((IA_Bit(*)(IA_Bit))0, i1);
    compose((IA_Bit(*)(IA_Bit))0, i1, (IA_Bit*)0);

    IA_ValueSet<IA_Bit>	vs(i1.range());
    // I shouldn\'t have to do the following two lines
    // vs.value_type_compare(0,0);
}

