// 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.10.1.2 1995/01/13 19:36:30 thoth Exp thoth $";

//
// $Log: BitDI.c,v $
// Revision 1.10.1.2  1995/01/13  19:36:30  thoth
// CoreImage has been re-merged with Image.  All special stuff should be
// friends of FBI now.
//
// Revision 1.10.1.1  1994/12/28  15:43:15  thoth
// image I/O is now ROF.
//
// Revision 1.10  1994/11/14  15:53:02  thoth
// removed useless local variable.
//
// Revision 1.9  1994/10/10  18:52:20  thoth
// Fixed bug with input of ASCII PBM files.
//
// Revision 1.8  1994/09/15  19:36:37  jnw
// Added display function for IA_Image<IA_Point<int>, IA_Bit>
//
// Revision 1.7  1994/07/25  17:29:33  thoth
// Name sanitization
//
// Revision 1.6  1994/05/17  12:53:27  thoth
// Image Operations now get their own files.
//
// Revision 1.5  1994/03/14  15:48:33  thoth
// ValueSet has been replaced by container class Set.
//
// 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	<string.h>
#include	<unistd.h>

#include        "display.h"
#include "image_errors.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);
}


//
//
//

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

IA_Image<IA_Point<int>,IA_Bit> read_PBM(istream &i)
{
    int	width, height;
    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++) {
		    i >> val;
		    data[idx++] = val;
		}
	    }
	}
	if (i)		// no errors during reading
	    return IA_Image<IA_Point<int>,IA_Bit>
		(IA_boxy_pset(IA_Point<int>(0,0),
				IA_Point<int>(height-1,width-1)),
		 data, size, 1);
    }

    ia_throw(Image_PNMIO_Exception(__FILE__, __LINE__));
    return IA_Image<IA_Point<int>,IA_Bit>();
}

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

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

    IA_Point<int>	inf_(img.domain().inf());
    IA_Point<int>	extent(img.domain().sup()-img.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_Point<int>	p(y+inf_[0],x+b+inf_[1]);
		if (img.domain().contains(p) &&
		    img(p))
		    val |= mask;
	    }
	    o.put(val);
	}
    }
    return o;
}

void write_PBM(const IA_Image<IA_Point<int>, IA_Bit> &img,
	       const char *fname)
{
    ofstream out(fname);
    write_PBM(img, out);
}

// display
//
// Forks a process to display an IA_Image<IA_Point<int>, IA_Bit>.
//
// Returns: the uid of the process      if the fork succeeded
//          -1                          if the fork failed
//
// display writes the image to a temp file in pbm format.
//
// User can set environment variable whose name is given by define constant
//        IMAGE_DISPLAY_ENV_VAR to specify what image display application
//        is to be used to display the pbm image.
//
// Default display application name is given by DEFINE constant
//        DEFAULT_IMAGE_DISPLAY
//

pid_t display(IA_Image<IA_Point<int>,IA_Bit> img)
{
    char *display_program;
    pid_t pid;

    // always use a fresh tmp filename
    strcpy(display_filename + strlen(display_filename) - 6, "XXXXXX");

    // Get the image display program filename
    display_program = getenv(IMAGE_DISPLAY_ENV_VAR);
    if (!display_program) {
	display_program = DEFAULT_IMAGE_DISPLAY;
    }

    // Fork and exec the display program
    if ((pid=fork())==0){
	// pid is zero, so this is the child

	// Write the image to a tmp file with a unique pid
	write_PBM(img,mktemp(display_filename));

	char *buffer;
	buffer = new char [strlen(display_program) + strlen(SEPARATOR_STRING)
			   + strlen(display_filename) + strlen(CLEANUP_STRING)
			   + strlen(display_filename)];
	strcat(strcat(strcat(strcat(strcpy(buffer, display_program),
				    SEPARATOR_STRING),
			     display_filename),
		      CLEANUP_STRING),
	       display_filename);
	// should exec a csh -c
	system(buffer);
	exit(0);
    }
    return pid;
}

