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

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


//
// $Log: IAAIO.h,v $
// Revision 1.2  1994/01/07  15:19:42  thoth
// Image class is now CoreImage and named image types are
// Image<P,T>.
//
// Revision 1.1  1993/09/15  12:53:36  thoth
// Initial revision
//

#include	<iostream.h>
#include	<sys/types.h>
#include	<netinet/in.h>	// for ntohl

//
//
//

inline int slurpint(istream &is) {
    int	k;
    is.read((char*)&k, 4);
    return ntohl(k);
}

template <class T>
IA_CoreImage<P,T> IA_CoreImage<P,T>::read_IAA(istream &header,
						      istream &values)
{
    // start parsing the header

    if ( ! ( header.get() == 0x61 &&
	     header.get() == 0x69 &&
	     header.get() == 0x41 &&
	     header.get() == 0x49) ) {
	// format error;
	ia_throw(IA::IAAIO_FORMAT_ERROR, __FILE__, __LINE__);
	return IA_CoreImage<T>();
    }

    // this is all ugly.  The IAA image file spec is not specced.
    //  We should probably talk about network byte order and specify the
    // sizes of the fields.

    int	k;
    k = slurpint(header);
    switch (k) {
    case 1:
	break;
    default:
	// wrong version of the file format
	ia_throw(IA::IAAIO_FORMAT_ERROR, __FILE__, __LINE__);
	return IA_CoreImage<T>();
    }

    k = slurpint(header);	// bits per value
    if (k!=8*sizeof(T)) {
	// wrong sort.
	ia_throw(IA::TYPE_MISMATCH, __FILE__, __LINE__);
	return IA_CoreImage<T>();
    }

    header.seekg(5*4, ios::cur); // skip reserved bytes

    const int nheadelem = slurpint(header);
    const unsigned valsoffset = slurpint(header);
    const int dim = slurpint(header);
    const int code = slurpint(header);
    IA_IntPointSet	domain;
    switch (code) {
    case 0:
	domain = IA_BlackHole(dim);
	// how do we handle the rest of the header?
	return IA_CoreImage<T>(domain, (T)0);
	break;
    case 1:
	{
	    int	*inf = new int[dim];
	    int	*sup = new int[dim];
	    for (k=0; k<dim; k++)
		inf[k] = slurpint(header);
	    for (k=0; k<dim; k++)
		sup[k] = slurpint(header);
	    domain = IA_IntPointSet(IA_IntPoint(inf, dim, 1),
				    IA_IntPoint(sup, dim, 1));
	}
	break;
    default:
	// pure or impure interval?
	// abort(); // throw
	ia_throw(IA::IAAIO_FORMAT_ERROR, __FILE__, __LINE__);
	return IA_CoreImage<T>();
    }

    const int card = slurpint(header);

    if (card != domain.card()) {
	// file consistency error
	// abort(); throw
	ia_throw(IA::IAAIO_FORMAT_ERROR, __FILE__, __LINE__);
	return IA_CoreImage<T>();
    }

    if (!header) {
	// error somewhere in the reading process
	ia_throw(IA::IAAIO_FORMAT_ERROR, __FILE__, __LINE__);
	return IA_CoreImage<T>();
    }

    T	*valvec = new T[card];
    values.read((char*)valvec, card * sizeof(T));

    return IA_CoreImage<T>(domain, valvec, card, 1);
}

template <class T>
IA_CoreImage<T> IA_CoreImage<T>::read_IAA(const char *fname1,
						      const char *fname2)
{
    ifstream header(fname1), values(fname2);
    return read_IAA(header, values);
}

template <class T>
IA_CoreImage<T> IA_CoreImage<T>::read_IAA(const char *fname)
{
    // create some istreams
    char	*temp = new char[strlen(fname)+5];
    strcpy(temp, fname);
    strcat(temp, ".iaa1");
    ifstream	header(temp);
    strcpy(temp, fname);
    strcat(temp, ".iaa2");
    ifstream	values(temp);
    delete [] temp;

    return read_IAA(header, values);
}

//
//
//


inline void spewint(ostream &is, int i) {
    int	k = htonl(i);
    is.write((char*)&k, 4);
}

template <class T>
void IA_CoreImage<T>::write_IAA(ostream &header, ostream &values) const
{
    header.put(0x61);		// magic number
    header.put(0x69);
    header.put(0x41);
    header.put(0x49);

    spewint(header, 1);		// version
    spewint(header, 8*sizeof(T)); // bits per value

    spewint(header, 0);		// reserved
    spewint(header, 0);
    spewint(header, 0);
    spewint(header, 0);
    spewint(header, 0);

    spewint(header, 18);	// how do we compute this?

    spewint(header, 1);		// data offset

    const int dim = domain().dim();
    spewint(header, dim);
    if (domain().empty()) {
	// this stuff is probably wrong
	spewint(header, 0);
	spewint(header, 0); // cardinality
	// we\'re done
    } else if (domain().boxy()) {
	spewint(header, 1);
	int	k;
	IA_IntPoint	p;

	p=domain().inf();
	for (k=0; k<dim; k++)
	    spewint(header, p[k]);

	p=domain().sup();
	for (k=0; k<dim; k++)
	    spewint(header, p[k]);

	const int card=domain().card();
	spewint(header, card);

	values.write((const char*)value_array().data_start(), card*sizeof(T));

    } else {
	ia_throw(IA::IAAIO_FORMAT_ERROR, __FILE__, __LINE__);
	abort(); // unhandled domain type
    }

}

template <class T>
void IA_CoreImage<T>::write_IAA(const char *fname1, const char *fname2)
    const
{
    ofstream header(fname1), values(fname2);
    write_IAA(header, values);
}

template <class T>
void IA_CoreImage<T>::write_IAA(const char *fname) const
{
    // create some ostreams
    char	*temp = new char[strlen(fname)+6];
    strcpy(temp, fname);
    strcat(temp, ".iaa1");
    ofstream	header(temp);
    strcpy(temp, fname);
    strcat(temp, ".iaa2");
    ofstream	values(temp);
    delete [] temp;

    write_IAA(header, values);
}
