/*
 * $Id: readsocket.cxx,v 4.0 2003/04/28 14:44:36 hut66au Exp $
 *
 * Imview, the portable image analysis application
 * http://www.cmis.csiro.au/Hugues.Talbot/imview
 * ----------------------------------------------------------
 *
 *  Imview is an attempt to provide an image display application
 *  suitable for professional image analysis. It was started in
 *  1997 and is mostly the result of the efforts of Hugues Talbot,
 *  Image Analysis Project, CSIRO Mathematical and Information
 *  Sciences, with help from others (see the CREDITS files for
 *  more information)
 *
 *  Imview is Copyrighted (C) 1997-2001 by Hugues Talbot and was
 *  supported in parts by the Australian Commonwealth Science and 
 *  Industry Research Organisation. Please see the COPYRIGHT file 
 *  for full details. Imview also includes the contributions of 
 *  many others. Please see the CREDITS file for full details.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 * */

/*------------------------------------------------------------------------
 *
 * Read raw buffers, for example coming from a socket or a pipe...
 *
 * Hugues Talbot	 6 Mar 2000
 *
 *      
 *-----------------------------------------------------------------------*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <vector> // STL
#include "imview.hxx"
#include "../imageIO.hxx"

extern imageIO *IOBlackBox;

static inline short swap2(short u);
static inline int swap4(int i);
static inline double swap8(double d);

int socketnbcomp(const char *ident)
{
    IMAGE_HEADER     *myheader;
    int               retval = 0;

    // find the corresponding data received through the socket
    myheader = IOBlackBox->findHeader(ident);
    if (myheader != 0) {
	retval = myheader->nbc;
    }

    return retval;
}

static inline short swap2(short u)
{
    char *in, *out;
    short ret;
    
    in = (char *)&u;
    out = (char *)&ret;

    out[1] = in[0];
    out[0] = in[1];
    
    return ret;
}

static inline int swap4(int i)
{
    char *in, *out;
    int   ret;
    
    in = (char *)&i;
    out = (char *)&ret;

    out[3] = in[0];
    out[2] = in[1];
    out[1] = in[2];
    out[0] = in[3];
    
    return ret;
}

static inline double swap8(double d)
{
    char    *in, *out;
    double   ret;
    
    in = (char *)&d;
    out = (char *)&ret;

    out[7] = in[0];
    out[6] = in[1];
    out[5] = in[2];
    out[4] = in[3];
    out[3] = in[4];
    out[2] = in[5];
    out[1] = in[6];
    out[0] = in[7];
    
    return ret;
} 

static void byteSwap(IMAGE_HEADER     *myheader)
{
    // does the data need swapping?
    if (myheader->needswap) {
	int               i, j;
	IMAGECOMP_HEADER *cmp;

	dbgprintf("Pixels have the wrong byte order, they need to be swapped\n");
	for (i = 0 ; i <myheader->nbc ; i++) {
	    cmp = &(myheader->comp[i]);
	    switch(cmp->pixt) {
	      case IM_BINARY:
	      case IM_CHAR:
	      case IM_UINT1:
		break; // no need to do anything

	      case IM_INT2:
	      case IM_UINT2:
		for (j = 0 ; j < cmp->spp ; j++) {
		    short *p = (short *)(cmp->buffp[j]);
		    short *end = p + cmp->nx * cmp->ny * cmp->nz;
		    while (p < end) {
			*p = swap2(*p);
			p++;
		    }
		}
		break;

	      case IM_INT4:
	      case IM_UINT4:
	      case IM_FLOAT:
		for (j = 0 ; j < cmp->spp ; j++) {
		    int *p = (int *)(cmp->buffp[j]);
		    int *end = p + cmp->nx * cmp->ny * cmp->nz;
		    while (p < end) {
			*p = swap4(*p);
			p++;
		    }
		}
		break;

	      case IM_INT8:
	      case IM_UINT8:
	      case IM_DOUBLE:
		for (j = 0 ; j < cmp->spp ; j++) {
		    double *p = (double *)(cmp->buffp[j]);
		    double *end = p + cmp->nx * cmp->ny * cmp->nz;
		    while (p < end) {
			*p = swap8(*p);
			p++;
		    }
		}
		break;

	      default:
		errprintf("Image received from socket with invalid pixel type");
		break;
	    }
	}
	myheader->needswap = false; // we only need to do this once
    }
}

int readSocket(const char *ident, int index)
{
    int              res = 0;
    IMAGE_HEADER     *myheader;

    dbgprintf("Read socket called\n");
    // find the corresponding data received through the socket
    myheader = IOBlackBox->findHeader(ident);
    if (myheader == 0) {
	errprintf("Header not found\n");
	res = 2;
    } else if (myheader->rawdata == 0) {
	errprintf("No data attached to header\n");
	res = 3;
    } else if ((index < 0) || (index >= myheader->nbc)) {
	errprintf("Component number out of range\n");
	res = 4;
    } else {
	dbgprintf("Header id: %d\n", myheader->unique_id);
	// set the current buffer as untouchable
	IOBlackBox->setCurrBuffp((myheader->comp[index]).buffp, true);
	IOBlackBox->setCurrImgWidth((myheader->comp[index]).nx);
	IOBlackBox->setCurrImgHeight((myheader->comp[index]).ny);
	IOBlackBox->setCurrImgThickness((myheader->comp[index]).nz);
	IOBlackBox->setXOffset((myheader->comp[index]).ox);
	IOBlackBox->setYOffset((myheader->comp[index]).oy);
	IOBlackBox->setZOffset((myheader->comp[index]).oz);
	IOBlackBox->setCurrZPos(0); // first plane
	IOBlackBox->setCurrImgType((myheader->comp[index]).imgt);
	IOBlackBox->setCurrPixType((myheader->comp[index]).pixt);
	IOBlackBox->setCurrImgNbComps(myheader->nbc);
	IOBlackBox->setCurrImgNbSamples((myheader->comp[index]).spp);
	IOBlackBox->setImgDesc("SOCKET");
	// swap byte ordering if needed
	byteSwap(myheader);
    }

        
    return res;
}


int readSocketOverlay(const char *name)
{
    int              res = 0;
    IMAGE_HEADER     *myheader;

    dbgprintf("Read overlay from socket called\n");
    // find the corresponding data received through the socket
    myheader = IOBlackBox->findHeader(name);
    if (myheader == 0) {
	errprintf("Header not found\n");
	res = 2;
    } else if (myheader->rawdata == 0) {
	errprintf("No data attached to header\n");
	res = 3;
    } else {
	dbgprintf("Header id: %d\n", myheader->unique_id);
// 	// set the current buffer as untouchable
// 	IOBlackBox->setCurrBuffp((myheader->comp[index]).buffp, true);
// 	IOBlackBox->setCurrImgWidth((myheader->comp[index]).nx);
// 	IOBlackBox->setCurrImgHeight((myheader->comp[index]).ny);
// 	IOBlackBox->setCurrImgThickness((myheader->comp[index]).nz);
// 	IOBlackBox->setXOffset((myheader->comp[index]).ox);
// 	IOBlackBox->setYOffset((myheader->comp[index]).oy);
// 	IOBlackBox->setZOffset((myheader->comp[index]).oz);
// 	IOBlackBox->setCurrZPos(0); // first plane
// 	IOBlackBox->setCurrImgType((myheader->comp[index]).imgt);
// 	IOBlackBox->setCurrPixType((myheader->comp[index]).pixt);
// 	IOBlackBox->setCurrImgNbComps(myheader->nbc);
// 	IOBlackBox->setCurrImgNbSamples((myheader->comp[index]).spp);
// 	IOBlackBox->setImgDesc("SOCKET");
	
	
	void *p = (myheader->comp[0]).buffp;
	int   start[3], end[3];

	// swap byte ordering if needed
	byteSwap(myheader);
	
	start[0] = (myheader->comp[0]).ox;
	end[0] = start[0] + (myheader->comp[0]).nx - 1;
	start[1] = (myheader->comp[0]).oy;
	end[1] = start[1] + (myheader->comp[0]).ny - 1;
	start[2] = (myheader->comp[0]).oz;
	end[2] = start[2] + (myheader->comp[0]).nz - 1;

	res = IOBlackBox->renderOverlay(name,
					p,
					myheader->nbc,
					start,
					end,
					(myheader->comp[0]).pixt);
	// DONT free these buffers. Only when the overlay
	// is closed or when another image by the same name is uploaded.
    }

    return res;
}
