/*=====================================================================
// Copyright (C) 2000-2012 Instrumental Software Technologies, Inc.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code, or portions of this source code,
//    must retain the above copyright notice, this list of conditions
//    and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materials provided with the
//    distribution.
// 3. All advertising materials mentioning features or use of this
//    software must display the following acknowledgment:
//    "This product includes software developed by Instrumental
//    Software Technologies, Inc. (http://www.isti.com)"
// 4. If the software is provided with, or as part of a commercial
//    product, or is used in other commercial software products the
//    customer must be informed that "This product includes software
//    developed by Instrumental Software Technologies, Inc.
//    (http://www.isti.com)"
// 5. The names "Instrumental Software Technologies, Inc." and "ISTI"
//    must not be used to endorse or promote products derived from
//    this software without prior written permission. For written
//    permission, please contact "info@isti.com".
// 6. Products derived from this software may not be called "ISTI"
//    nor may "ISTI" appear in their names without prior written
//    permission of Instrumental Software Technologies, Inc.
// 7. Redistributions of any form whatsoever must retain the following
//    acknowledgment:
//    "This product includes software developed by Instrumental
//    Software Technologies, Inc. (http://www.isti.com/)."
// THIS SOFTWARE IS PROVIDED BY INSTRUMENTAL SOFTWARE
// TECHNOLOGIES, INC. "AS IS" AND ANY EXPRESSED OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED.  IN NO EVENT SHALL INSTRUMENTAL SOFTWARE TECHNOLOGIES,
// INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//=====================================================================
//  A current version of the software can be found at
//                http://www.isti.com
//  Bug reports and comments should be directed to
//  Instrumental Software Technologies, Inc. at info@isti.com
//=====================================================================
// This work was funded by the IRIS Data Management Center
// http://www.iris.washington.edu
//===================================================================== 
*/

/*
**   THIS FILE IS UNDER RCS - DO NOT MODIFY UNLESS YOU HAVE
**   CHECKED IT OUT USING THE COMMAND CHECKOUT.
**
**    $Id: ws_requests.c 4857 2012-06-19 18:01:15Z ilya $
** 
**	Revision history:
**	$Log$
**	Revision 1.2  2010/04/28 13:48:49  ilya
**	Update to sync with IRIS DMC version
**
**	Revision 1.15  2010/04/22 18:04:00  ilya
**	We now increase the requested interval if fully in gap
**	
**	Revision 1.1  2010/03/10 17:14:58  paulf
**	first check in of ew2mseed to EW proper
**	
**	Revision 1.13  2008/12/30 02:25:27  ilya
**	Modified build process
**	
**	Revision 1.12  2008/12/29 17:49:02  ilya
**	Fixes to suypport long period channels
**	
**	Revision 1.11  2007/09/17 16:29:48  ilya
**	Fixing problems with 78.1 EW integration
**	
**	Revision 1.10  2007/04/12 19:21:04  hal
**	Added ew7.0+ support (-dSUPPORT_SCNL) and linux port (-D_LINUX)
**	
**	-Hal
**	
**	Revision 1.9  2003/03/12 19:09:34  ilya
**	Patched condition generated by buggy waverserver
**	
**	Revision 1.8  2003/01/08 23:40:56  ilya
**	Added printf for datatypes
**	
**	Revision 1.7  2002/05/03 02:35:09  ilya
**	BUG fix: MSEED records -> wrong files
**	
**	Revision 1.6  2002/04/11 20:07:13  ilya
**	Add disabling of catchup mechanism
**	
**	Revision 1.5  2002/04/04 19:26:28  ilya
**	Fixed a bug in processWsGetTraceBin()
**	
**	Revision 1.4  2002/04/02 14:42:01  ilya
**	Version 02-Apr-2002: catchup algorithm
**	
**	Revision 1.3  2002/03/25 20:47:48  ilya
**	Fixed segFaults
**	
**	Revision 1.2  2002/02/21 21:17:19  ilya
**	Bug fixed: use SCN->num instead of SCN->avail in init functions
**	
**	Revision 1.1.1.1  2002/01/24 18:32:05  ilya
**	Exporting only ew2mseed!
**	
**	Revision 1.1.1.1  2001/11/20 21:47:00  ilya
**	First CVS commit
**	
 * Revision 1.11  2001/03/15  16:44:53  comserv
 * Modifications to add configurable SocketReconnect and to
 * reduce a number of menu updates
 * 	processWsAppendMenu() and updateMenu() assign rn->updateMenuTime
 * 	updateSingleSCNtimes() is rewritten
 *
 * Revision 1.10  2001/02/27  22:59:36  comserv
 * Modifications to decrease socket connections:
 * ws_requests.c: updateMenu() is created from strongly modified processWsAppendMenu()
 *
 * Revision 1.9  2001/02/23  21:32:33  comserv
 * 	a call to wsServersReAttach () is removed since it has not been used
 *
 * Revision 1.8  2001/02/13  20:59:50  comserv
 * 	We compute sample rate as
 * 	sampRate = floor(wf->samprate+0.5);
 *
 * Revision 1.7  2001/02/12  18:41:07  comserv
 * In getSampeRate()
 * 	sample rate is computed now as
 * 	sampRate = floor(wf->samprate + smallValue)
 * #include <math.h> is added
 * smallValue is redefined as 0.0001
 *
 * Revision 1.6  2001/02/06  17:19:15  comserv
 * Functions logFailedSCN() resetWsTrace() are moved to ew2mseed_utils.c
 *
 * Revision 1.5  2001/02/06  05:58:16  comserv
 * Multiple changes:
 * 1) logic of getParamsFromWS() is rewritten so it no is able to remove sick SCNs from the trace ring
 * and potocols those SCNs in the log and LOCK files
 * 2)logic of getSampleRate() is rewritten so it returns negative values instead of exiting
 * 3)Modified a check for sample rate validity (sampRate > smallValue) instead of (sampRate > 0)
 * 4) Parameter timeshift in getsampleRate is set to 300 instead of 3000s to sample the tank denser
 * in search of the non-gapped data
 * verbosity for 2 logit calls is increased to 2 and higher to decrease the size of the log file
 * during routine processing
 *
 * Revision 1.4  2001/01/18  23:50:53  comserv
 * removed stderr message on memory buffer size
 *
 * Revision 1.3  2001/01/17  21:58:31  comserv
 * prerelease version; new copyright statement
 *
 * Revision 1.2  2001/01/08  22:55:57  comserv
 * lighten the functions to speed up
 *
 * Revision 1.1  2000/11/17  06:57:10  comserv
 * Initial revision
 *
*/

/* Standard includes */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <math.h>  /* IGD 02/12/01 Add */

/* Includes from Earthworm distribution */
#include "earthworm.h"
#include "trace_buf.h"

/* Local includes */
#include "ew2mseed.h"


 /**************************************************************/


   
  int updateSingleSCNtimes (RINGS *rn, WS_MENU_QUEUE_REC *menu_queue)
  {
	char message[200];
	
	long secondsAfterMenuUpdate;   /* IGD 03/15/01 */
	int retVal;
#ifdef SUPPORT_SCNL
	WS_PSCNL pscn;
#else
	WS_PSCN pscn;
#endif
	WS_MENU menu;
#ifdef SUPPORT_SCNL
	retVal = WS_ERR_SCNL_NOT_IN_MENU;
#else
	retVal = WS_ERR_SCN_NOT_IN_MENU;
#endif
       	menu = menu_queue->head;
	rn->scnRing->tankStarttime = -1;
	rn->scnRing->tankEndtime = -1;
	while (menu)
	{
#ifdef SUPPORT_SCNL
		pscn = menu->pscnl;
#else
		pscn = menu->pscn;
#endif	  
		while (pscn)
		{
			if ( strcmp( rn->scnRing->traceRec.sta, pscn->sta ) == 0 &&
			     strcmp( rn->scnRing->traceRec.chan, pscn->chan ) == 0 &&
			     strcmp( rn->scnRing->traceRec.net, pscn->net ) == 0 )
			{
#ifdef SUPPORT_SCNL
				if ( strcmp( rn->scnRing->traceRec.loc, pscn->loc ) != 0)
				{
				     pscn = pscn->next;
					continue;
				}
#endif
				retVal = WS_ERR_NONE;
				rn->scnRing->traceRec.pinno = pscn->pinno;
	
				if (rn->scnRing->tankStarttime < 0) /*not initialized */
					rn->scnRing->tankStarttime = pscn->tankStarttime;
				/* If it is not the first tank */
				if (rn->scnRing->tankStarttime > pscn->tankStarttime)
					rn->scnRing->tankStarttime = pscn->tankStarttime;

				if (rn->scnRing->tankEndtime < 0) /*not initialized */
					rn->scnRing->tankEndtime = pscn->tankEndtime;
				/* If it is not the first tank */
				if (rn->scnRing->tankEndtime < pscn->tankEndtime)
					rn->scnRing->tankEndtime = pscn->tankEndtime;

         		} 						 /* endof if (strcmp) */
			     pscn = pscn->next;
		 }  							/* End of while (pscn) */
  	         menu = menu->next;	
	} 				

	sprintf(message, "updateSingleSCNtimes %s %s %s %s ", 
		rn->scnRing->traceRec.sta, rn->scnRing->traceRec.chan, 
		rn->scnRing->traceRec.net, rn->scnRing->locId);	
	if ((rn->verbosity > 3 && retVal == WS_ERR_NONE) || retVal != WS_ERR_NONE) LogWsErr(message, retVal);	

	if (retVal == WS_ERR_NONE && rn->verbosity > 2)	
		logit ("pt", "%s: pinno = %d tankStarttime = %s; tankEndtime = %s\n", 
			message, rn->scnRing->traceRec.pinno, 
			strDate(rn->scnRing->tankStarttime, d20), strDate(rn->scnRing->tankEndtime, d20a) );
	
	if (rn->scnRing->traceRec.reqStarttime < rn->scnRing->tankStarttime)
	{
		rn->scnRing->traceRec.reqStarttime = rn->scnRing->tankStarttime + rn->TravelTimeout;
		rn->scnRing->traceRec.reqEndtime = getReqEndTime (
			rn->scnRing->traceRec.reqStarttime, 
			rn->scnRing->samprate, 
			(int) rn->reqBufLen/sizeof(int));
			logit ("pt", "updateSingleSCNtimes: requested start time shifted to %s\n",
			strDate(rn->scnRing->traceRec.reqStarttime, d20));	
	}

	if (rn->scnRing->traceRec.reqEndtime > rn->scnRing->tankEndtime)	
	{	
		if (rn->verbosity > 2)  /* IGD 02/06/01 stronger reqirement */
			logit ("pt", "updateSingleSCNtimes: requested end time %s (%f); endTanktime = %s (%f)\n",
			       strDate(rn->scnRing->traceRec.reqEndtime, d20),
			       rn->scnRing->traceRec.reqEndtime,
			       strDate(rn->scnRing->tankEndtime, d20a),
			       rn->scnRing->tankEndtime);

		/* How many seconds after we updated menu last time? */
		secondsAfterMenuUpdate = (long) (time (NULL) - rn->updateMenuTime);
		if (rn->scnRing->traceRec.reqEndtime > rn->scnRing->tankEndtime + secondsAfterMenuUpdate)
			retVal = EW2MSEED_TOO_EARLY;  /* Thre is no way we have enough data in the menu */
		else
			retVal = EW2MSEED_TIME2_UPDATE_MENU;  /* Time to update menu */
	}
	return retVal;
  }


/**************************************************************************/


int fillPSCN (RINGS *rn, WS_MENU_QUEUE_REC *menu_queue)
{
  char message[200]; 
  int i;
  int availablePSCNs =0;
  int retVal;
  struct SCN_ring *scn_head;
#ifdef SUPPORT_SCNL
  WS_PSCNL pscn;
#else
  WS_PSCN pscn;
#endif
  WS_MENU  menu;
 
  scn_head = rn->scnRing;
  
  for (i=0; i<rn->SCN_num; i++)  /* For each SCN of interest */	
  {
#ifdef SUPPORT_SCNL
	retVal = WS_ERR_SCNL_NOT_IN_MENU;
#else
	retVal = WS_ERR_SCN_NOT_IN_MENU;
#endif
       	menu = menu_queue->head;
	while (menu)
	{
#ifdef SUPPORT_SCNL
		pscn = menu->pscnl;
#else
		pscn = menu->pscn;
#endif
		while (pscn)
		{
			if ( strcmp( rn->scnRing->traceRec.sta, pscn->sta ) == 0 &&
	     		     strcmp( rn->scnRing->traceRec.chan, pscn->chan ) == 0 &&
	      		     strcmp( rn->scnRing->traceRec.net, pscn->net ) == 0)
	   		     {  
	      		     	retVal = WS_ERR_NONE;
				rn->scnRing->traceRec.pinno = pscn->pinno;
	
				if (rn->scnRing->tankStarttime < 0) /*not initialized */
					rn->scnRing->tankStarttime = pscn->tankStarttime;
				/* If it is not the first tank */
				if (rn->scnRing->tankStarttime > pscn->tankStarttime)
					rn->scnRing->tankStarttime = pscn->tankStarttime;

				if (rn->scnRing->tankEndtime < 0) /*not initialized */
					rn->scnRing->tankEndtime = pscn->tankEndtime;
				/* If it is not the first tank */
				if (rn->scnRing->tankEndtime < pscn->tankEndtime)
					rn->scnRing->tankEndtime = pscn->tankEndtime;

         		     } 						 /* endof if (strcmp) */
			     pscn = pscn->next;
		 }  							/* End of while (pscn) */
  	         menu = menu->next;	
	} 					 			/* End while (menu) */
		
 	sprintf(message, "fillPSCN %s %s %s %s ", 
		rn->scnRing->traceRec.sta, rn->scnRing->traceRec.chan, 
		rn->scnRing->traceRec.net, rn->scnRing->locId);	
	LogWsErr(message, retVal);	

	if (retVal == WS_ERR_NONE)	{
		availablePSCNs++;
	logit ("pt", "%s: pinno = %d tankStarttime = %s; tankEndtime = %s\n", 
			message, rn->scnRing->traceRec.pinno, 
			strDate(rn->scnRing->tankStarttime, d20), strDate(rn->scnRing->tankEndtime, d20a) );
	}
	rn->scnRing = rn->scnRing->next;

  } /* end of loop for SCNs */

  rn->scnRing = scn_head;  
  return availablePSCNs;
}

/********************************************************************/

int processWsAppendMenu (RINGS *rn, WS_MENU_QUEUE_REC *menu)
  {
  char message[200]; 
  int i;
  int retVal;	
  int availableServers=0; 
  struct WS_ring *ws_head;
  ws_head = rn->wsRing;
  while (1)
  { 
  	for (i=0; i < rn->WS_num; i++)	
  	{
	  	retVal = wsAppendMenu (rn->wsRing->wsIP, rn->wsRing->wsPort, 
			menu, rn->TravelTimeout * 1000 );

		sprintf(message, "wsAppendMenu %s:%s ", 
					rn->wsRing->wsIP, rn->wsRing->wsPort);
		if (rn->verbosity > 2 || retVal != WS_ERR_NONE) /* IGD 02/06/01 new requirement */
 	 		LogWsErr(message, retVal);
		
		if (retVal == WS_ERR_NONE)
			availableServers++;

	  	rn->wsRing = rn->wsRing->next;
  	}

	rn->wsRing = ws_head;

 	 if (menu->head == NULL)
  	{
		logit ("pt", "processWsAppendMenu: menu is empty, retrying to connect to servers...");
  		sleep (20);
  	}
  	else	
	{	
		rn->updateMenuTime = time(NULL); /* IGD 03/15/01 */
   	 	return availableServers;	
  	}	
  }  /* End of infinite while */
}

/**************************************************************************
 *      updateMenu: updates a linked-list of menus .                      *
 *	Calls wsAppendMenuNoSocketReconnect() for each WS_MENU *	  *
 *	which attempts to update th PSCNs without reconnection to the     *
 *	socket.								  *
 *	If the return value of the call is negative WS_MENU *		  *
 *	current_menu is not updated. Otherwise, it is updated.		  *
 * 	If any of WS_MENU is not updated, the menu linked-list is killed  *
 *	and the control is passed to processWsAppendMenu		  *
 *	Returns the number of active waveservers.			  *
 *	Ilya Dricker ISTI 02/27/01					  *	
 *************************************************************************/

int updateMenu (RINGS *rn, WS_MENU_QUEUE_REC *menu_queue)
  {

  WS_MENU_REC * current_menu;
  int retVal;	

  current_menu = menu_queue->head;
  retVal = wsAppendMenuNoSocketReconnect (current_menu, rn->verbosity, rn->TravelTimeout * 1000);
  if (retVal != WS_ERR_NONE)
 	 goto RecreateSocket;
  else 
	menu_queue->head = current_menu;
 	
  while (1)
  {
	if(current_menu->next == NULL)
	{
		if (rn->verbosity > 2)
			logit("pt", "updateMenu: %d WaveServers updated successfully\n", rn->WS_avail);	
		rn->updateMenuTime = time (NULL); /* IGD 03/15/01 */
		return (rn->WS_avail);
	}
	else
	{
		current_menu = current_menu->next;
		retVal = wsAppendMenuNoSocketReconnect (current_menu, rn->verbosity, rn->TravelTimeout * 1000);
		if (retVal != WS_ERR_NONE)
			 goto RecreateSocket;
	}

  }

RecreateSocket :
	if (rn->verbosity > 2)
			LogWsErr("updateMenu failed:", retVal);

	wsKillMenu(menu_queue);
	rn->WS_avail =  processWsAppendMenu (rn, menu_queue);
	return (rn->WS_avail); 
}

/******************************************************************************/

  double getSampleRate (TRACE_REQ *trace, WS_MENU_QUEUE_REC *menu_queue, int timeout)
  {
	char message[200];
	double endTime;
	double startTime;
	double sampRate = 0;
	int retVal;
	double seconds = 5;
	double time_shift = 300; /* decreased IGD 02/05/01 */
/*	double verySmall = 0.0001; */  /* IGD 02/12/01 redefined */
	TRACE_HEADER *wf;

	if ('V' == trace->chan[0] || 'U' == trace->chan[0])
		seconds = 500;
	if ('R' == trace->chan[0])
		seconds = 5000;

	
	startTime = trace->reqStarttime;
	endTime = trace->reqEndtime;
	
	trace->reqEndtime = trace->reqStarttime + seconds;  /*get five seconds of data */

	/* Without knowing the actual sample rate we can only assume the real buffer size
        ** so let's make it large;
	******************************************************/
	
	trace->bufLen = 8 * 100000 * 5; /* in bytes : assuming 100000 samples per seconds 
				      **  and 8 bytes in a sample
                                      ***************************/  
					
	trace->pBuf = (char *) calloc(1, trace -> bufLen);
	if (trace->pBuf == 0)
	{

		fprintf(stderr, "Attempt to allocate %ld bytes for trace->pBuf %s %s %s failed\n", 
			trace->bufLen, trace->sta, trace->net, trace->chan);
		logit("pt", "Attempt to allocate %ld bytes for trace->pBuf %s %s %s failed\n",
			 trace->bufLen, trace->sta, trace->net, trace->chan);
		perror("The reason:");
		exit(-13);

	}
#ifdef SUPPORT_SCNL
	retVal = wsGetTraceBinL (trace, menu_queue, timeout);
#else
	retVal = wsGetTraceBin (trace, menu_queue, timeout);
#endif

	//if (trace->retFlag != 0) { 	/* IGD this and next line are added on 02/05/01 */
	//  retVal = WS_WRN_FLAGGED;
	//}


	
	/* IGD 03/11/03 Fixing a condition when waveserver returns bogus endtime */	
	if (trace->actEndtime - trace->reqEndtime > 10000)
	{
		logit ("pt", "WARNING: <%s %s %s> WaveServer returned bogus endtime <%s> requested endtime: <%s>\n",
				trace->sta,
				trace->net,
				trace->chan,
				strDate(trace->actEndtime, d20), 
				strDate(trace->reqEndtime, d20a));
#ifdef SUPPORT_SCNL	      
		retVal = WS_ERR_SCNL_NOT_IN_MENU;		
#else
		retVal = WS_ERR_SCN_NOT_IN_MENU;		
#endif

	
	}	

	sprintf(message, "getSampleRate %s %s %s ", 
				trace->sta, trace->chan, trace->net);
	



	LogWsErr(message, retVal);

	/* If the buffer is overflown, we still can get a sample rate
	 ******************************************/
	if (retVal == WS_ERR_BUFFER_OVERFLOW) {
		retVal = WS_ERR_NONE;

	}



	/* See if we got a gap 
	 * If we are inside the gap, or before the tank, we loop around the tank
	 * until we find the data or until we are outside the tank
	 ***********************************/
	while (1)	
	{
		if (retVal == WS_WRN_FLAGGED)

		{


			/* Let us see what we've got
			****************************/
			if (trace->retFlag == '\000')
			{
				if (trace->reqStarttime < trace->actStarttime)
				{	
					trace->reqStarttime = trace->actStarttime;
					logit ("pt", "actual start time %s; requested start time %s\n",
						strDate(trace->actStarttime, d20), strDate(trace->reqStarttime, d20a));
				}
				if (trace->reqEndtime > trace->actEndtime)
				{
					trace->reqEndtime = trace->actEndtime;
					logit ("pt", "actual end time %s; requested end time %s\n",
						strDate(trace->actEndtime, d20), strDate(trace->reqEndtime, d20a));		 
				}
			retVal = WS_ERR_NONE;
			break;
			}
			else /* retFlag is not null */
			{
				if (trace->retFlag == 'R')
				{
					logit ("pt", "<%s %s %s>: requested time interval <%s - %s> is younger than anything in the tank\n",
							trace->sta, trace->net, trace->chan, strDate(trace->reqStarttime, d20), strDate(trace->reqEndtime, d20a));
					break;
				}

				else if (trace->retFlag == 'L' )
	 				{
						logit ("pt", "<%s %s %s>: requested time interval <%s - %s> is older than anything in the tank\n",
							trace->sta, trace->net, trace->chan, strDate(trace->reqStarttime, d20), strDate(trace->reqEndtime, d20a));
						trace->reqStarttime += time_shift;
						trace->reqEndtime += time_shift;
					}
				else if (trace->retFlag == 'G')
					{

						logit ("pt", "<%s %s %s>: requested time interval <%s - %s> is fully within a gap in the tank\n",
								trace->sta, trace->net, trace->chan, strDate(trace->reqStarttime, d20), strDate(trace->reqEndtime, d20a));

						trace->reqStarttime += time_shift;
						trace->reqEndtime += time_shift;
						if (trace->reqStarttime - time(NULL) > 12 * 3600)
						{
							logit ("pt", "<%s %s %s>: requested time interval <%s - %s> is before the real time: bogus tank time\n",
                                                                trace->sta, trace->net, trace->chan, strDate(trace->reqStarttime, d20), strDate(trace->reqEndtime, d20a));
							break;
						}

					}
				else 
				{
					logit ("pt", "unknown retFlag %c", trace->retFlag);
					break;
				}
			}
		}
		else   /* This is not a flagged nessage */
			break;
#ifdef SUPPORT_SCNL
		retVal = wsGetTraceBinL (trace, menu_queue, timeout);
#else
		retVal = wsGetTraceBin (trace, menu_queue, timeout);
#endif

	}

	if (retVal != WS_ERR_NONE)
	{
 		logit("pt", "Cannot determine sample rate %s %s %s (%d)\n",
		      trace->sta, trace->chan, trace->net, retVal);
			/* Clean the stuff */
		resetWsTrace (trace, startTime, endTime);  /* IGD 02/05/01 replaced exit(-) */
		return (-1);

	}

	wf = (TRACE_HEADER *) trace->pBuf;

	/* IGD 01/08/03: Let's use our chance to log the datatype for our channel */
	logit("pt", "Datatype for %s %s %s is %s\n", 
			trace->sta, trace->chan, trace->net, wf->datatype);
	/* Let's check if the sample rate is intended to be an integer 
	** If if it is so, let's round it to an integer
	** IGD 02/12/01
	******************************************************/
	
	ew2mseed_SwapDouble(&(wf->samprate), wf->datatype[0]);
	if ((wf->samprate+0.5) >= 1)
		sampRate = floor(wf->samprate+0.5); /* IGD 02/13/01 insead of verySmall */	
	else
		sampRate = wf->samprate; 
	
	
	/*Does this sample rate make sense */
	if (sampRate <= 0.01 || sampRate > 10000000)
	{
		logit("pt", "Fatal: Sample rate %f seems to be bogus: out of bounds for %s %s %s\n",
			sampRate, trace->sta, trace->chan, trace->net);
		resetWsTrace (trace, startTime, endTime);  /* IGD 02/05/01 replaced exit(-) */
		return(-3);
	}	
		
	logit("pt", "Sample rate for %s %s %s is %f\n", 
			trace->sta, trace->chan, trace->net, sampRate);
		
	/* Clean the stuff */
	resetWsTrace(trace, startTime, endTime);   /* IGD 02/05/01 replaced exit(-) */
	return sampRate;
  }


/*****************************************************************************/

  int getParamsFromWS (RINGS *rn, WS_MENU_QUEUE_REC *menu_queue)
  {	
	int i;
	struct SCN_ring *scn_head;
	struct SCN_ring *failedSCNring;
	struct SCN_ring *previousSCNring;
	int validSCNcount;
	scn_head = rn->scnRing;	

	validSCNcount = rn->SCN_num; /* IGD 02/21/02 All are valid: we gonna remove bads later */

        logit("pt", "Starting with %d SCN_Locs\n", validSCNcount);
	/* IGD  02/21/02 : bug fixed was rn->SCN_avail */
	for (i=0; i < rn->SCN_num; i++)
	{   
		/* Get sample rate for this SCN 
		 ***********************************/
		rn->scnRing->samprate = getSampleRate
		      (&(rn->scnRing->traceRec), menu_queue, rn->TravelTimeout * 1000);

		/* Assume the required buffer size 
		 **************************************/
		rn->scnRing->traceRec.bufLen = assumeSnippetSize
			(rn->scnRing->logRec, rn->scnRing->CompAlg,
			 rn->RecNum, rn->PriorityHighWater); 
		
		/* If the assertion below is true, we are removing the trace
		 * from the ring and record this in the log and lock(!) file
		 *   IGD 02/05/01
		 ****************************************************/	
		if (rn->scnRing->samprate < 0 || rn->scnRing->traceRec.bufLen < 0)	
		{
			validSCNcount--; /* one actual SCN less to process */
			if (scn_head == rn->scnRing)	/* this scnRing is the first one */
				scn_head = rn->scnRing->next; /* remove this scnRing element from the ring  */ 			
			else  /* This scnRing is not the first one */
				previousSCNring->next = rn->scnRing->next; /* remove this scnRing element from the Ring */
			failedSCNring = rn->scnRing;
			rn->scnRing = rn->scnRing->next;
			logFailedSCN (failedSCNring, rn->LockFile);
			free(failedSCNring->dir);
			free(failedSCNring->curMseedFile);
			free(failedSCNring);
		}	
		else  /* scn_ring is fine */  
		{
			/* Allocate memory for the data buffer if first time
			 * Reallocate the memory in case the buffer length for this SCN
			 * is larger than the global one
			 ***************************************/
	
			if (rn->bufLen < rn->scnRing->traceRec.bufLen ) 			

			{	
			if (rn->bufLen < 0)
				{
					fprintf(stderr, "Memory allocation problems in ew2mseed\n");
					exit(-16);
				}		
				if (rn->bufLen > 0)  /* Buffer has already been calloced */
					free(rn->pBuf); 
			
				if ((rn->pBuf = (char *)
					 calloc(1, rn->scnRing->traceRec.bufLen)) == NULL)
				{
					logit("pt", "Fatal error: %s %s %s: cannot calloc %d bytes\n",
						rn->scnRing->traceRec.sta, rn->scnRing->traceRec.net,
						rn->scnRing->traceRec.chan,
			 		       (int)rn->scnRing->traceRec.bufLen);	
			
					fprintf(stderr, "Fatal error: %s %s %s: cannot calloc %d bytes\n",
						rn->scnRing->traceRec.sta, rn->scnRing->traceRec.net,
						rn->scnRing->traceRec.chan,
			  	 	     (int)rn->scnRing->traceRec.bufLen);	
					exit(-10);
				}
				/* Now assign value values to rn->bufLen and rn->reqBufLen
				 ******************************************/
				rn->bufLen = rn->scnRing->traceRec.bufLen;
				rn->reqBufLen = rn->scnRing->traceRec.bufLen;
				logit("pt", "%s %s %s: buffer size set to %d bytes\n",
					rn->scnRing->traceRec.sta, rn->scnRing->traceRec.net,
					rn->scnRing->traceRec.chan,
				 	(int)rn->bufLen);			
			}


			/* Compute the end time for the request 
		 	*************************************/
			/* IGD 03/29/02 We divide by HighWater
			 * Because we multiplied when we computed
			 * Buffer Size: catchup algorithm 
			 */
			rn->scnRing->traceRec.reqEndtime = getReqEndTime (
				rn->scnRing->traceRec.reqStarttime, 
				rn->scnRing->samprate, 
				(int)rn->reqBufLen/
					(sizeof(int) * rn->PriorityHighWater) );
		
			/* Set time interval for a single wsRequest 
			*******************************************/
			rn->scnRing->timeInterval = rn->scnRing->traceRec.reqEndtime - rn->scnRing->traceRec.reqStarttime;
			if (rn->verbosity > 3) logit ("pt", "time interval for requests is set to %f s\n", 
					rn->scnRing->timeInterval);	

			if (rn->verbosity > 2) logit("pt", "%s %s %s: requested start time set to %s s\n",
				rn->scnRing->traceRec.sta, rn->scnRing->traceRec.net,
				rn->scnRing->traceRec.chan,
				 strDate(rn->scnRing->traceRec.reqStarttime, d20));

 			if (rn->verbosity > 1) logit("pt", "%s %s %s: requested end time set to %s s\n",
				rn->scnRing->traceRec.sta, rn->scnRing->traceRec.net,
				rn->scnRing->traceRec.chan,
				 strDate(rn->scnRing->traceRec.reqEndtime, d20));

			previousSCNring	= rn->scnRing; /* IGD 02/05/01 here we protocol the las successful scnRing */
			rn->scnRing = rn->scnRing->next;
		}   /* end of else : the current scnRing is OK */
	}

	rn->scnRing = scn_head;
	rn->SCN_avail = validSCNcount; /* IGD 02/05/01 added */
	if (rn->SCN_avail > 0)
		logit("pt", "%d (out of %d requested) SCN-Locs are available for furher processing\n",
			rn->SCN_avail, rn->SCN_num);
	else	
	{
		logit("pt", "No SCN_Locs are avaialble for further processing (out of %d requested)",
		rn->SCN_num);
		fprintf(stderr, "No SCN_Locs are avaialble for further processing (out of %d requested)\n",
		rn->SCN_num);
		exit(-21);
	}
		 
	return 0;
  }

 
/************************************************************************/
  int processWsGetTraceBin (TRACE_REQ *p_trace, WS_MENU_QUEUE_REC *p_mq, int timeout)
{
	int retVal = -999;
	char message[1000];
	double timeShift;	
	double maxRequestedTime = 3600;
	double requestedTimeStep = 60;
	

	double currentSampleRate = 0;
	TRACE_HEADER *wf;

 	/* Little trick: we are widening the requested time by 1 sec
	 * because WaveServer tends to send the data within a sample
	 * from the requested time and this is not what we are 
	 * looking for: we want requested time to be within actual time!
	 ************************************************************/
	p_trace->reqStarttime -= 1.;
	p_trace->reqEndtime += 1.;
		
	/* Get the buffer from the waveserver; process the response
	*********************************************/
#ifdef SUPPORT_SCNL
	retVal = wsGetTraceBinL (p_trace, p_mq, timeout);
#else
	retVal = wsGetTraceBin (p_trace, p_mq, timeout);
#endif

	if (p_trace->pBuf != NULL)
	{
		wf = (TRACE_HEADER *) p_trace->pBuf;
		currentSampleRate = wf->samprate;
		ew2mseed_SwapDouble (&currentSampleRate, wf->datatype[0]);		
	}
	/* IGD 03/18/02 If the condition below occurs, this is probably due
	 * a bug in wsGetTraceBin()
         */
	if (currentSampleRate == 0 && retVal == WS_ERR_NONE)	/* IGS 04/04/02 */
	{
		logit("pt", 
		 "wsGetTraceBin() returned %d, sample rate = %d; setting retVal to WS_ERR_BROKEN_CONNECTION\n",
			retVal, currentSampleRate);
		p_trace->reqStarttime += 30;	/* IGD 04/04/02 Skip 30 secs from danger */
		p_trace->reqEndtime += 30;
		retVal = WS_ERR_BROKEN_CONNECTION;

	}
 
	if (retVal != WS_ERR_NONE)
	{	/* Protocol the attempt
		 ***********************************************/	
		sprintf(message, "wsGetTraceBin  %s %s %s ", 
		p_trace->sta, p_trace->chan, 
		p_trace->net);
		LogWsErr(message, retVal);
	
		/* if the error is WS_ERR_BUFFER_OVERFLOW : increase the size of buffer 
		 ****************************************************/
		if (retVal == WS_ERR_BUFFER_OVERFLOW)
		{
		
			p_trace->bufLen = p_trace->bufLen + (int) (p_trace->bufLen/10);
					logit("pt", "Warning: trace buffer  is increased to %ld bytes\n",
						p_trace->bufLen);	
		}	
	}


	/*Set the requested time back to desired
	******************************************/
	p_trace->reqStarttime += 1.;
	p_trace->reqEndtime -= 1.;
	
	if (retVal == WS_ERR_NONE || retVal == WS_WRN_FLAGGED)
	{
		/* Let us see what we've got
		****************************/
		if (p_trace->retFlag == '\000')
		{
			if (p_trace->reqStarttime < p_trace->actStarttime)
			{	
				logit ("pt", "actual start time %s; requested start time %s\n",
					strDate(p_trace->actStarttime, d20), strDate(p_trace->reqStarttime, d20a));
				p_trace->reqStarttime = p_trace->actStarttime;

			}
			if (p_trace->reqEndtime > p_trace->actEndtime)
			{
				logit ("pt", "actual end time %s; requested end time %s\n",
					strDate(p_trace->actEndtime, d20), strDate(p_trace->reqEndtime, d20a));	
				p_trace->reqEndtime = p_trace->actEndtime;
	 
			}
		}

		else /* retFlag is not null */
		{
			if (p_trace->retFlag == 'R')
			{
				logit ("pt", "<%s %s %s>: requested time interval <%s - %s> is younger than anything in the tank\n",
						p_trace->sta, p_trace->net, p_trace->chan, strDate(p_trace->reqStarttime, d20), strDate(p_trace->reqEndtime, d20a));			
			}

			else if (p_trace->retFlag == 'L' )
	 		{
				logit ("pt", "<%s %s %s>: requested time interval <%s - %s> is older than anything in the tank\n",
						p_trace->sta, p_trace->net, p_trace->chan, strDate(p_trace->reqStarttime, d20), strDate(p_trace->reqEndtime, d20a));
			
				if(p_trace->reqStarttime - time(NULL) < 24 * 3600)
				{	
					timeShift = p_trace->reqEndtime - p_trace->reqStarttime;
					if (timeShift < maxRequestedTime)
				  		timeShift += requestedTimeStep;
					p_trace->reqStarttime += timeShift;
					p_trace->reqEndtime += timeShift;
					logit ("", "<%s %s %s>: new requested time interval is set to <%s - %s> : %f seconds \n",
						p_trace->sta, p_trace->net, p_trace->chan, strDate(p_trace->reqStarttime, d20), strDate(p_trace->reqEndtime, d20a), timeShift);
				}
			}
			else if (p_trace->retFlag == 'G')
			{
				logit ("pt", "<%s %s %s>: requested time interval <%s - %s> is fully within a gap in the tank\n",
						p_trace->sta, p_trace->net, p_trace->chan, strDate(p_trace->reqStarttime, d20), strDate(p_trace->reqEndtime, d20a));
				timeShift = p_trace->reqEndtime - p_trace->reqStarttime;
				if (timeShift < maxRequestedTime)
				  timeShift += requestedTimeStep;
				p_trace->reqStarttime += timeShift;
				p_trace->reqEndtime += timeShift;
				logit ("", "<%s %s %s>: new requested time interval is set to <%s - %s> : %f seconds \n",
						p_trace->sta, p_trace->net, p_trace->chan, strDate(p_trace->reqStarttime, d20), strDate(p_trace->reqEndtime, d20a), timeShift);

			}
			else 
				logit ("pt", "unknown retFlag %c", p_trace->retFlag);
		}
	}

	return retVal;
}

