#if ! defined(lint) && ! defined(LINT)
static char rcs_id[] = "$Id: grdtm.c,v 1.7 1994/01/05 21:06:27 gbourhis Exp $";
#endif
/* contains dtm stuff- for receiving palettes from ximage */
/* $Log: grdtm.c,v $
 * Revision 1.7  1994/01/05  21:06:27  gbourhis
 * little fix
 *
 * Revision 1.6  1993/12/13  22:11:47  gbourhis
 * Add support for -DTMIN option from command-line., send back connect
 * SRV message when receiving an RSV connect message.
 *
 * Revision 1.5  1993/10/27  18:05:01  gbourhis
 * Use gr_StoreColors() instead of gr_ImageSetCMap().
 * test the data type of SDS. Add support for INT SDS.
 *
 * Revision 1.4  1993/10/25  21:53:07  gbourhis
 * Add support of -DTMOUT option, enabling XDataSlice to
 * be used in a collaborative session with collage.
 *
 * Revision 1.3  1993/10/25  16:11:00  gbourhis
 * add some DTMendRead(), use gr_ImageInitCMapHDF() to load palettes.
 *
 */
#include "gr_com.h"
#include <stdio.h>

#ifdef DTMOK
#include "dtm.h"
#include "sds.h"
#include "ris.h"
#include "srv.h"


#define TIME_INTERVAL 2000  /* check dtm port every 2 sec */

static void DTM_checkPortForData();

/* --- DTM related variables --- */
static char IN_HOST_NAME[120];
int  IN_PORT_NUMBER = -1;

static int inPort = -55;
static char inPortAddr[256];
static int outPort;
char *outPortName = NULL;
static char userID[256];
static int DTM_state = 0; 
static char header[DTM_MAX_HEADER];
static unsigned char palette[256*3];
static int ignoreDTMflag = 0;

/* ------------------------------------------------------- */
setignoreDTM (s) int s; { ignoreDTMflag = s; }

/* ------------------------------------------------------- */
/* return 0 if O.K. 1 otherwise */
int DTM_setInPort(ss)
char *ss;
{
	if (ss[0] == ':')	/* test if host field is empty */
	  {			/* gbourhis Feb 93 */
	    sprintf(IN_HOST_NAME,"");
	    sscanf(ss+1, "%d", &IN_PORT_NUMBER);
	  }
	else
	  {
	    int i;
	    for(i=0;i<strlen(ss);i++) if ( ss[i]==':') { ss[i] = ' '; break; }
	    sscanf(ss,"%s %d", IN_HOST_NAME, &IN_PORT_NUMBER);
	  }

	return IN_PORT_NUMBER < 1;
}
  
/* ------------------------------------------------------- */
int DTM_showInfo () {
  if (IN_PORT_NUMBER < 1) {
	char ss[100], *dsP = (char*) getenv("XDSPORT");
	if (dsP != NULL)
		sprintf(ss,"%s", dsP);

	if (dsP == NULL || !strcmp(ss,"(null)") ) {
		 sprintf(IN_HOST_NAME,"");
		 IN_PORT_NUMBER = 4321;
	       }
	else {
		if(DTM_setInPort(ss)) {
			printf("host = [%s] portnumber= [%d]\n", IN_HOST_NAME, IN_PORT_NUMBER);
			printf("Possibly bad port number specified. DTM may not work.\n");
 			beep();
			return;
 		}
	}
 
	if (outPortName == NULL) {
		beep();
    printf("\n*************************************************************\n");
    printf("This version of xds has DTM linked to it.\n");
    printf("It will receive palettes and sds's over port [%s:%d]\n",
	 IN_HOST_NAME, IN_PORT_NUMBER);
    printf("To use a different port instead, you must define the environment\n");
    printf("variable XDSPORT to \":portnumber\" and restart XDataSlice\n");
    printf("Use the DTM toggle to start\n");
    printf("*************************************************************\n\n");
		beep();
		return;
	}
      }

    DTM_initialize();DTM_state = 1;
#ifdef XtSpecificationRelease	/* gbourhis Feb 1 93: we need an app_context */
    XtAppAddTimeOut(XtWidgetToApplicationContext(gr_topLevel),
#else
    XtAddTimeOut(
#endif
		    TIME_INTERVAL, DTM_checkPortForData, NULL);

}

/* ------------------------------------------------------- */
/* toggle on dtm */
static int DTM_init = 0;
int DTM_setControlOn ( w, client_data, call_data)
Widget   w;
caddr_t  client_data;
caddr_t  call_data;

{
   /* start up a DTM connection if not already started  */
		if (DTM_init == 0) { 
			DTM_initialize();
			DTM_init = 1;
       }
		DTM_state = 1; /* on */

   /* set a timed request to wait for data */
		DTM_checkPortForData();
}
/* ------------------------------------------------------- */
/* toggle off dtm */
int DTM_setControlOff ( w, client_data, call_data)
Widget   w;
caddr_t  client_data;
caddr_t  call_data;

{
	DTM_init = 0;
	DTM_state = 0; /* off */
	DTMdestroyPort (inPort);
	fprintf(stderr,"dtm is now OFF\n"); fflush(stderr);
	gr_TextMsgOut("DTM is now OFF. All sending programs will block.\n");
}

/* ------------------------------------------------------- */
static int DTM_createOutPort()
{
     extern double td_version;
     char header[1024];
     char host[65];

     if (cuserid(userID) != NULL && gethostname(host, 64) >= 0)
       strcat(strcat(userID, "@"), host);
     else
       gethostname(userID, 64);
     strcat(userID, " (XDataSlice)");

     outPort = DTMmakeOutPort(outPortName, DTM_DEFAULT);
     if (outPort == DTMERROR) {
       fprintf(stderr, "Can't make DTM out port %s\n",
	       outPortName);
       return 0;
     }
     SRVsetClass(header);
     SRVsetID(header, userID);
     SRVsetFunction(header, SRV_FUNC_CONNECT);
     SRVsetInPort(header, inPortAddr);
     SRVsetVersionNumber(header, 2);
     sprintf(host, "%3.1f", td_version);
     SRVsetVersionString(header, host);
     DTMwriteMsg(outPort, header, strlen(header)+1, NULL, 0, 0);
}

/* ------------------------------------------------------- */

DTM_readData() {
	int i;
	float * sdsbuf;
	char dtmname[160]; /* name of DTM dataset if any */
	
	if (ignoreDTMflag != 0) return;

	if (DTM_state == 0) return;
	fprintf(stderr,"DTM_readData..\n"); fflush(stderr);

   	if (DTMerrno) {
         printf("DTM status: %s\n", DTMerrmsg(1));
  			exit(0);
         }
	if (DTMbeginRead(inPort,header,DTM_MAX_HEADER) == DTMERROR) {
	  fprintf(stderr, "Error reading DTM header\n");
	  exit(0);
         }

	/* gbourhis Jan 93: update to DTM 2.3			*/
	if (dtm_compare_class(header, SRVclass)) {
	  int func;
	  static char newOutPortName[81];
	  DTMendRead(inPort);
	  SRVgetFunction(header, &func);
	  if (func == SRV_FUNC_CONNECT) {
	    SRVgetInPort(header, newOutPortName, 80);
	    if (outPortName) {
		    DTMdestroyPort(outPort);
		    outPort = DTMmakeOutPort(newOutPortName, DTM_DEFAULT);
		  }
	    else {
		    outPortName = newOutPortName;
		    DTM_createOutPort();
		  }
	  }
	  else if (func == SRV_FUNC_DISCONNECT && outPortName) {
	    char discPortName[81];
	    SRVgetInPort(header, discPortName, 80);
	    if (!strcmp(discPortName, outPortName)) {
		    DTMdestroyPort(outPort);
		    outPortName = NULL;
		  }
	  }    
	}
	else if (dtm_compare_class(header,PALclass)) {
	  DTMreadDataset(inPort,palette,768,DTM_CHAR);
	  DTMendRead(inPort);
	  gr_DTMpalLoad(palette);
	}
	else if (dtm_compare_class(header,SDSclass)) {
	  SDSgetTitle( header,dtmname, 80);
	  myDTMbossInit (dtmname);
      	}
	else			/* discard the message */
	  DTMendRead(inPort);

} /* DTM_readData */

/* ------------------------------------------------------- */

static void DTM_checkPortForData()
{
	static long count = 0;

	if (DTM_state == 0) return; /* dtm is off, don't bother */

	count++;
	if(count%4==0) DBPRINTARG("DTM_checkPort (%ld):\n",count);
	if (DTMavailRead(inPort))
	  if (!DTMerrno) 
	    DTM_readData();
	  else 
	    printf("DTM status: %s\n", DTMerrmsg(1));

	if (DTM_state == 1) /* continue to check DTM if DTM_state is on */
#ifdef XtSpecificationRelease	/* gbourhis Feb 1 93: we need an app_context */
	  XtAppAddTimeOut(XtWidgetToApplicationContext(gr_topLevel),
#else
	  XtAddTimeOut(
#endif
		       TIME_INTERVAL, DTM_checkPortForData, NULL);

} /* DTM_checkPortForData */

/* ------------------------------------------------------- */

int DTM_initialize()
{

   sprintf(inPortAddr,"%s:%d",IN_HOST_NAME,IN_PORT_NUMBER);
	/* gbourhis Jan 93: update to DTM 2.3			*/
   if (-1 == (inPort = DTMmakeInPort(inPortAddr, DTM_DEFAULT))) {
         printf("Couldn't use [%s] for input\n", inPortAddr);
			return 0;
       }
   printf("DTM_initialize: Using port [%s] as DTM input\n", inPortAddr);

   DTMgetPortAddr(inPort, inPortAddr, sizeof(inPortAddr));

   if (outPortName)
	DTM_createOutPort();

   return DTM_init = 1;
}
/* ------------------------------------------------------- */

/*
 *	Load color map with data received from DTM port.
 */

gr_DTMpalLoad (palette)
unsigned char * palette;
{

   A_CubeWind_t   *cubeWin;
   A_DsplWind_t   *dWin;
   A_HistWind_t   *hWin;
   A_AniWind_t    *aWin;
	A_BossWind_t   *bWin;

	gr_TextMsgOut("Hello..a Palette just came across the DTM port!\n");
   gr_ImageInitCMapHDF(palette);

   for (aWin = gr_topWin.aniWin; aWin != NULL; aWin = aWin->next)
	gr_StoreColors(aWin->shell, &gr_color);

   bWin = gr_topWin.bossWin;

   while (bWin != NULL) {
	cubeWin = bWin->cubeWin; 
	if (cubeWin != NULL) {
		for (dWin = cubeWin->dsplWin; 
		     dWin != NULL; dWin = dWin->next)
		{  /* update display windows */
			gr_StoreColors( dWin->shell, &gr_color);

			for (hWin = dWin->histWin;
			     hWin != NULL; hWin = hWin->next)
			{  /* update histogram windows */
   				gr_StoreColors(hWin->shell, &gr_color);
			}
		}
		for (aWin = cubeWin->aniWin;
		     aWin != NULL; aWin = aWin->next)
			gr_StoreColors( aWin->shell, &gr_color);
	}
	bWin = bWin->next;
   }

		gr_TextMsgOut("Loaded new DTM palette\n");

} /* gr_DTMpalLoad */


/* ================================================================== */

/*
* jng jan-08-91
* load SDS data from DTM port.
* patterned after td_HdfLoad().
*/
int
myDTMsdsLoad (sds)
A_Data_t *sds;
{
	int i,ret, dimensions[3];
	long nsdselts;
	DTMTYPE type;

	beep();
	gr_TextMsgOut("\nHello..a SDS just came across the DTM port!\n");

	SDSgetTitle(header, sds->pathName, 80);
	SDSgetDimensions( header, &sds->rank, dimensions, 3);
	if (sds->rank < 1 || sds->rank > 3) {
		fprintf(stderr,"bad sds dims (=%d)  from dtm!!\n",sds->rank); 
		return(-1);
	 }
	if (SDSgetType(header, &type) == -1) {
		fprintf(stderr, "Error getting SDS type\n");
		return -1;
	}
	if (type != DTM_FLOAT && type != DTM_INT) {
		fprintf(stderr, "XDS only support float & int SDS\n");
		return -1;
	}
	for (nsdselts = 1, i=0;i<sds->rank;i++)
	  nsdselts *= sds->dims[i] = dimensions[i]; 
	fprintf (stderr,"nsdselts = %ld rank: %d\n", nsdselts, sds->rank);
	for (i = sds->rank; i<3; i++) sds->dims[i] = 1;

	sds->data = (float32 ***)
         td_Malloc3Dfloat32 (sds->dims[0], sds->dims[1], sds->dims[2]);
	if (NULL == sds->data ) {
		printf("malloc err for dtm data %s\n", sds->pathName);
		return(-1);
	}

	if (type == DTM_INT) {
		int *indata = (int *)malloc(sds->dims[0]*sds->dims[1]*
					    sds->dims[2]*sizeof(int));
		if (indata == NULL) {
			printf("malloc err for dtm data %s\n", sds->pathName);
			return(-1);
		}
		DTMreadDataset (inPort, indata, nsdselts , type);
		for (i=0; i < sds->dims[0]*sds->dims[1]*sds->dims[2]; i++)
			sds->data[0][0][i] = (float)indata[i];
		free(indata);
	}
	/* gbourhis Jan 93: update to DTM 2.3			*/
	else
		DTMreadDataset (inPort, sds->data[0][0], nsdselts , type);
 	DTMendRead(inPort);

  	sds->format = HDF;

	/* compute stats for the dtm sds dataset */

	if ( -1 == SDSgetMinMax (header, &sds->min, &sds->max)) {
		myDTMgetStats (sds);
	}

	/* --- note: GLOBALS used here!! --- */
	sds->range = sds->max - sds->min;
  	sds->rangeFrac = (float32)((float32)gr_color.nColors/sds->range);
  	sds->rangeFracSplit = (float32)((float32)gr_colorSplit.nColors/sds->range);
	return 1;

} /* myDTMsdsLoad */

/* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& */

/*
* jng jan-08-91
* fill out the data structure with relevant stats
* of the received DTM SDS dataset.
* Patterned after td_HdfgetStats().
*/

myDTMgetStats (sds) 
A_Data_t	* sds;
{
	register int i,j,k;


   sds->min = sds->max = sds->data[0][0][0]; 
   for (i=0;i<sds->dims[2];i++) {
      for (j=0;j<sds->dims[1];j++) {
          for (k=0;k<sds->dims[0];k++) {
              if (sds->min > sds->data[k][j][i])
                              sds->min = sds->data[k][j][i];
              if (sds->max < sds->data[k][j][i])
                              sds->max = sds->data[k][j][i];
          }
       }
    }

}


/* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& */
/*
 * jng jan-08-91
 *	Open a Boss Window for a DTM dataset
 * patterned after gr_SDSLoad().
 */

myDTMbossInit (dtmname)
char * dtmname; /* name of dtm dataset */
{
	A_BossWind_t	*tmp;
	int 				i,ret,num;
	A_BossWind_t	*bwin;
	char				tname[160];
	int				match;

	sprintf(tname, "%s,DTM", dtmname);
	bwin = gr_topWin.bossWin;

	match = 0;
	while (bwin != NULL) {
		if (!strcmp(bwin->filename, tname))
		{
			match = 1;
			break;
		}		
		else 
			bwin = bwin->next;
	}

	if (match) {
		if (myDTMsdsLoad(bwin->data) == -1)
			DTMendRead(inPort);
		else
			myDTMupdateBoss(bwin);
		return;	
	}
	
  /*-- a new DTM dataset ---- create a new boss window for it --- */
	num = -('D'+'T'+'M'); /* special value of num signals DTM dataset */

	if (gr_topWin.numBossWins < MAX_BOSLEV_WINDS)
	{
		tmp = gr_InitBossLevel(gr_topWin.bossWin, dtmname ,gr_topLevel,
					num,&gr_topWin,HDF);
		if (tmp != NULL)
			{
				gr_topWin.bossWin = tmp;
				gr_topWin.numBossWins++;
				sprintf(msg,"Loaded 3D SDS %s.\n",dtmname);
				gr_TextMsgOut(msg);
			}
		else
			DTMendRead(inPort);
	}
	else
	{
		DTMendRead(inPort);
		sprintf(msg,"Only %d Attributes window is allowed!\n", MAX_BOSLEV_WINDS);
		gr_TextMsgOut(msg);
	}

}

void gr_Close_DTM()
{
  if (outPortName) {
    char header[1024];
    SRVsetClass(header);
    SRVsetID(header, userID);
    SRVsetFunction(header, SRV_FUNC_DISCONNECT);
    SRVsetInPort(header, inPortAddr);
    DTMwriteMsg(outPort, header, strlen(header)+1, NULL, 0, 0);
  }
}

#endif


