/*
 * E.S.O. - VLT project / ESO Archive
 *
 * "@(#) $Id: ImageIO.C,v 1.1.1.1 2009/03/31 14:11:53 cguirao Exp $" 
 *
 * ImageIO.C - method definitions for class ImageIO, for managing image
 *             I/O and storage
 * 
 * who             when      what
 * --------------  --------  ----------------------------------------
 * Allan Brighton  07/03/96  Created
 *
 *                 12/03/98  Remove dependency on FitsIO (delegated to
 *                           class FitsIO or other class derived from
 *                           ImageIORep.
 * pbiereic        12/08/07  added support for data types double and long long int
 */
static const char* const rcsId="@(#) $Id: ImageIO.C,v 1.1.1.1 2009/03/31 14:11:53 cguirao Exp $";


#include <netinet/in.h>
#include <cmath>
#include <cstdlib>
#include "define.h"
#include "error.h"
#include "ImageIO.h"

/*
 * copy constructor - increment the reference count...
 */
ImageIO::ImageIO(const ImageIO& im) 
    : rep_(im.rep_)
{
    if (rep_) 
	rep_->refcnt_++;
}


/*
 * destructor - delete if there are no more references.
 */
ImageIO::~ImageIO() 
{
    if (rep_ && --rep_->refcnt_ <= 0) 
	delete rep_;
}


/*
 * assignment operator
 */
ImageIO& ImageIO::operator=(const ImageIO& im)
{
    if (im.rep_)
	im.rep_->refcnt_++;		// protect against "im = im"
    if (rep_ && --rep_->refcnt_ <= 0) 
	delete rep_;
    rep_ = im.rep_;
    return *this;
}


// -----------------------------------------------------------------------
// ImageIORep: base class of internal representation
// -----------------------------------------------------------------------

/*
 * replace header
 */
int ImageIORep::header(const Mem& m)
{
    header_ = m;
    return 0;
}

    
/*
 * replace data with data of same size
 */
int ImageIORep::data(const Mem& m)
{
    if (m.length() < width_* height_ * (abs(bitpix_)/8))
	return error("image memory area is too small");
    data_ = m;
    return 0;
}


/*
 * If byte swapping is needed for this machine and image, make a byte
 * swapped copy of the image data, otherwise, do nothing.
 * Returns 0 if all is OK.
 */
int ImageIORep::byteSwapData() 
{
    int dsize = abs(bitpix_)/8;
    long l = 1;
    if (ntohl(l) == l || dsize == 1) {
	// no byte swapping needed
	return 0;
    }
    
    // make a byte-swapped copy of the image in memory. 
    // Note: if this causes problems with huge images, maybe we should
    // make a byte swapped file copy and mmap it.
    int n = width_ * height_;
    int datalen = n * dsize;
    Mem data(datalen, 0);
    if (data.status() != 0)
	return 1;

    // copy the data and swap bytes
    if (dsize == 2) {
	// copy shorts (could be an odd number of them...)
	unsigned short* from = (unsigned short*)data_.ptr();
	unsigned short* to = (unsigned short*)data.ptr(); 
	while(n--) {
	    *to++ = ntohs(*from);
	    // note: ntohs could be a macro that references its arg more than once...
	    from++; 
	}
    }
    else if (dsize == 4) {
	// copy longs
	unsigned long* from = (unsigned long*)data_.ptr();
	unsigned long* to = (unsigned long*)data.ptr(); 
 	while(n--) {
	    *to++ = ntohl(*from);
	    from++;
	}
    }
    else if (dsize == 8) {
        // copy long longs (doubles)
        unsigned long long* from = (unsigned long long*)data_.ptr();
        unsigned long long* to = (unsigned long long*)data.ptr(); 
        while(n--) {
            *to++ = SWAP64(*from);
            from++;
        }
    }
    else {
	return fmt_error("ImageIO: unexpected value for bitpix: %d", bitpix_);
    }
    
    // replace the image data with the byte swapped data
    // (This deletes the old data Mem object and replaces it with the new one)
    data_ = data;
    return 0;
}

