 
/*=====================================================================
// Copyright (C) 2000-2010 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: ew2mseed.c 3839 2010-03-10 17:14:58Z paulf $
** 
**	Revision history:
**	$Log$
**	Revision 1.1  2010/03/10 17:14:58  paulf
**	first check in of ew2mseed to EW proper
**
**	Revision 1.16  2010/01/21 23:30:36  ilya
**	Service
**	
**	Revision 1.15  2008/12/30 02:25:27  ilya
**	Modified build process
**	
**	Revision 1.14  2007/09/17 17:31:33  ilya
**	Tested SNCL fixes on Solaris
**	
**	Revision 1.13  2007/04/12 19:21:04  hal
**	Added ew7.0+ support (-dSUPPORT_SCNL) and linux port (-D_LINUX)
**	
**	-Hal
**	
**	Revision 1.12  2006/09/20 21:53:58  ilya
**	Apperantly fixed the lepseconds bug
**	
**	Revision 1.11  2006/07/17 17:26:02  ilya
**	7/17/06
**	
**	Revision 1.10  2005/03/23 03:24:25  ilya
**	Fixed alighnment of data in BUD volumes
**	
**	Revision 1.9  2005/03/22 22:24:42  ilya
**	Bug fixed: writng in the wrong file
**	
**	Revision 1.8  2003/05/16 01:04:18  ilya
**	Added StartLatency
**	
**	Revision 1.7  2003/03/12 19:09:34  ilya
**	Patched condition generated by buggy waverserver
**	
**	Revision 1.6  2002/11/22 16:39:26  ilya
**	Moved file name update down to processing routines from main()
**	
**	Revision 1.5  2002/05/03 02:35:09  ilya
**	BUG fix: MSEED records -> wrong files
**	
**	Revision 1.4  2002/04/11 20:07:13  ilya
**	Add disabling of catchup mechanism
**	
**	Revision 1.3  2002/04/02 14:42:01  ilya
**	Version 02-Apr-2002: catchup algorithm
**	
**	Revision 1.2  2002/03/25 20:47:48  ilya
**	Fixed segFaults
**	
**	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.13  2001/03/15  16:46:23  comserv
 *  Modifications to add configurable SocketReconnect and to
 *  reduce a number of menu updates
 * main lopp is strongly modified
 *
 * Revision 1.12  2001/02/27  22:58:18  comserv
 * Modifications to decrease socket connections:
 *  updateMenu()	replaces processWsAppendMenu() in main
 * 	if (retVal == EW2MSEED_TOO_EARLY)
 * main()" postprocessing after processSingleSCN() is modified.
 *  int processSingleSCN (RINGS *rn, WS_MENU_QUEUE_REC *mq)
 * is modified to return WS_ERR... values not EW_SUCCESS or EW_FAILURE.
 *
 * Revision 1.11  2001/02/23  21:34:29  comserv
 * service version
 *
 * Revision 1.10  2001/02/23  21:32:47  comserv
 *  added the level 5 of verosity w_clientsII.c debug....
 * in main()
 * 		if (j==30*rn.SCN_avail)   IGD 02/23/01 increased from 30 
 *
 * Revision 1.9  2001/02/13  21:00:48  comserv
 * Changes in ws_requests.c
 *
 * Revision 1.8  2001/02/12  18:42:01  comserv
 * Modifications in ws_requests.c
 *
 * Revision 1.7  2001/02/12  17:48:35  comserv
 * Modifications of sample rate in ew2mseed.h
 *
 * Revision 1.6  2001/02/06  05:54:50  comserv
 * 	code is added to prevent writing MSEED records (calling processSingleSCN) if
 * 	the endTime on tank is before requested endTime. This prevents ew2mseed from creating
 * 	MSEED records with too few data points in cases ew2mseed preformance is faster
 * 	 than real-time
 *
 * Revision 1.5  2001/01/17  21:47:35  comserv
 * Copyright is changed, version is inserted
 *
 * Revision 1.4  2001/01/08  22:53:54  comserv
 * Modifications to reduce the latency time
 *
 * Revision 1.3  2001/01/04  13:36:09  comserv
 * Fixed the bug preventing writing data to the new file if the
 * old file is empty
 *
 * Revision 1.2  2000/11/17  20:30:55  comserv
 * processWsGetTraceBin is fixed and then moved to ws_requests.c
 *
 * Revision 1.1  2000/11/17  06:55:44  comserv
 * Initial revision
 *
*/

/* Standard includes */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>

/* Includes from Earthworm distribution */
#include "earthworm.h"
#include <qlib2.h>



/* Local includes */
#include "ew2mseed.h"
#define VERSION "$Id: ew2mseed.c 3839 2010-03-10 17:14:58Z paulf $"


  int main(int argc, char **argv)
  {
	int loopCount;	/* IGD 02/29/02 Counter of loops over all available SCNs */
	int i;
  	int retVal, retVal1;
  	RINGS rn;
  	WS_MENU_QUEUE_REC menu_queue;
	menu_queue.head = NULL;
	menu_queue.tail = NULL;
 
	fprintf(stdout, "%s\n", VERSION);

  	/* Check command line arguments 
 	******************************/
   	if (argc != 2)
   	{
                fprintf (stderr, "Usage: ew2mseed <configfile>\n");
                exit (EW_FAILURE);
   	}


	/* Check for the compilation flags
	 * Program should be compiled with either _SPARC or _INTEL flag
	 * Only _SPARC is supported
	**************************************/
	if (checkCompilationFlags(argv[0]) < 0)
		exit(EW_FAILURE); 
	

  	/* Put the configuration file name in the rn structure
  	***************************************/ 
  	rn.configFile = calloc(1, strlen(*(argv+1))+1);

 	strncpy (rn.configFile, *(argv+1), strlen(*(argv+1))+1);

 	/*  Read configuration
 	 ***************************************/ 
  	retVal = ew2mseed_config (&rn);
 	if (retVal != EW_SUCCESS)
  	{
		fprintf(stderr, "ew2mseed: Error reading config file\n");
		exit (EW_FAILURE);
  	}
	
	/* IGD 03/14/01 Set timeout values in each traceRec
	 ****************************************/	
	ew2mseedUpdateTimeout (&rn);

	/* Start logging mechanism if required 
 	 ***************************************/ 
 	logit_init (argv[1], (short) 0, 1024, rn.logSwitch);
 	logit ("pt" , "ew2mseed: Read command file <%s>\n", argv[1]);
	d20 = (char *) calloc(1, 21); /* alloc global char date line */
	d20a = (char *) calloc (1, 21); 
	/* Log the configuration  
 	 ***************************************/ 
 	 ew2mseed_logconfig(&rn);
	
	/* If rn.verbosity == 5,
	 * we log the ws_client.c debug messages 
	 * IGD 04/01/02 Tests with this version shows that
	 * the program crashes if it logs WS_ERR_TIMEOUT in
	 * wsGetTraceBin, so we disable logging of clients
	 * at least for a while
	 ***********************************************/
	/* if (rn.verbosity == 5)
		setWsClient_ewDebug (1);
	 */
	/* Check if we set a lock and if the lock is set exist 
	 ****************************************************/
	if (checkLock(rn.LockFile) < 0)
	{
  		logit ("pt", "ew2mseed: lock % is set by the other instance of ew2mseed\n", 
			rn.LockFile);
		exit(-15);
	}
	/* Set rn.bufLen to zero : rn.bufLen is a length of our single data buffer 
	 ********************************/
	rn.bufLen = 0;

	/* Initialize waveserver wave server menu linked list  
 	 ***************************************/ 
  	rn.WS_avail =  processWsAppendMenu (&rn, &menu_queue);

  	logit ("pt", "ew2mseed: got menu from %d WaveServers (out of %d)\n", 
		rn.WS_avail, rn.WS_num);

	/* Fill PSCN strucuture 
	  **************************************/ 
 	 rn.SCN_avail = fillPSCN (&rn, &menu_queue);

  	if (rn.SCN_avail == 0)
	{  /* IGD : is this a right solution? */
		logit ("pt", "no valid SCN are found in waveservers, program exits NOW!!!\n");
		wsKillMenu (&menu_queue);
		exit(-1);
  	} 
	/* Init and Handle the MSEED file structure 
 	 **************************************/ 
  	retVal = filesHandler (&rn);

	/* Get the requested block reading size and the 
	** sample rate for each SNC from the Wave Servers 
 	 **************************************/ 
  	retVal = getParamsFromWS (&rn, &menu_queue);

	/* Initialize qlib2 in NO_EXIT mode
	 *************************************/
	init_qlib2(1);

	/*	Create SCN infinite Ring loop
 	 **************************************/
 	makeSNCLoop (&rn);	
	
 
	logit ("", "-------------------------------------\n");
 	logit ("pt", "ew2mseed: entering the Main Loop\n"); 	

	/* IGD 02/29/02 Set accounting stuff */
	i = 0;
	loopCount = 0;

	/* Set signals
	**********************************/
	signal (SIGALRM, signal_handler);	/*03/14/01 IGD */
	signal (SIGINT, signal_handler);
	signal (SIGTERM, signal_handler);
	signal (SIGUSR1, signal_handler);
	sigignore(SIGPIPE);
	ew_signal_flag = EW2MSEED_OK; /*global variable ! */
	alarm((unsigned int) rn.TimeoutSeconds);

	/* Main loop
	 **************/
	while (1)
	{	

		sighold(SIGALRM); 	/* 03/14/01 IGD */
		sighold(SIGINT);
		sighold(SIGTERM);
		sighold(SIGUSR1);

		/* IGD 03/29/02 Count loops to rearrange priorities */
		if (i >= rn.SCN_avail)
		{
			loopCount++;
			i = 0;
			if (loopCount >= rn.LoopsBeforeService)
			{
				loopCount = 0;
				if (rn.usePriority == 1) /* IGD 04/11/02 */
					(void) updatePriorityValues(&rn);
			}
		}	

/*            IGD 11/21/02 This code is moved to processSingleSCN() to prevent empty files creation
 *
 *		if (rn.scnRing->newFileJulTime <= rn.scnRing->traceRec.reqStarttime )
 *		{
 *			free(rn.scnRing->curMseedFile);
 *			rn.scnRing->curMseedFile = ew2mseedUpdateFileName
 *			(&(rn.scnRing->traceRec), rn.scnRing->dir, 
 *				rn.scnRing->locId);
 *			rn.scnRing->newFileJulTime = findNewFileJulTime (rn.scnRing->traceRec.reqStarttime);
 *			rn.scnRing->mseedSeqNo = 1;
 *			logit ("pt", "New file is avaialble for writing: %s\n",
 *				rn.scnRing->curMseedFile);
 *		}
 */
			/* IGD 03/14/01 If there is no WS available
			 * we sleep for 20 seconds and try to get menu again
			 *****************************************/	
			if (rn.WS_avail == 0)
			{	sleep(20);
				ew_signal_flag = EW2MSEED_ALARM; /* This will force the program to request a menu */	
				continue;
			}

		retVal = updateSingleSCNtimes (&rn, &menu_queue);

		/* IGD 02/06/01 
		 * Obvious fix: if the endTime of request is after the endTime in tank
		 * we update the tank times, but do not attempt to create MSEED
		 ****************************************************/
		if (retVal == EW2MSEED_TOO_EARLY)
		{	
			sleep(2);	/* IGD 01/24/02 Sandy requested */
			if (rn.verbosity > 3)	/* IGD 03/15/01 Do nothing*/
				logit("pt", "updateMenu skipped\n");			
		}
		else if (retVal == EW2MSEED_TIME2_UPDATE_MENU)
			rn.WS_avail = updateMenu(&rn, &menu_queue); /* IGD 03/15/01 */
		else  /* here we try to actually create MSEED records */
		{	
			retVal1 = processSingleSCN (&rn, &menu_queue);
			if (retVal1 != WS_ERR_NONE) /* IGD changed 02/27/01 */	
			{
				if (retVal1 == WS_ERR_NO_CONNECTION ||		/* Cases when socket is closed */
				    retVal1 == WS_ERR_BUFFER_OVERFLOW ||
				    retVal1 == WS_ERR_TIMEOUT || 
                         	    retVal1 == WS_ERR_BROKEN_CONNECTION  || 
                                    retVal1 == WS_ERR_SOCKET) 
				{
					wsKillMenu(&menu_queue);
					rn.WS_avail = processWsAppendMenu(&rn, &menu_queue);
					alarm((unsigned int) rn.TimeoutSeconds);
				}
				else						/* Socket is not required an update */
					rn.WS_avail = updateMenu(&rn, &menu_queue); /* IGD new 02/26/01 */
				if (rn.WS_avail == 0)
					continue; 		
				retVal = updateSingleSCNtimes (&rn, &menu_queue);
			}
		}

		rn.scnRing = rn.scnRing->next;
		i++; 
		sigrelse(SIGINT);
		sigrelse(SIGTERM);
		sigrelse(SIGUSR1);
		sigrelse(SIGALRM);
		if (ew_signal_flag != EW2MSEED_OK)
		{
			if (ew_signal_flag == EW2MSEED_ALARM)
			{
				/* Kill the old menu and get the new one 
				 ***************************************/
				wsKillMenu(&menu_queue);
				rn.WS_avail = processWsAppendMenu(&rn, &menu_queue);
				/* Rest the alarm 
				 ***************/
				alarm((unsigned int) rn.TimeoutSeconds);
				/* reset the flag 
				 ******************/
				ew_signal_flag = EW2MSEED_OK; /*global variable ! */
			}
			if (ew_signal_flag == EW2MSEED_TERMINATE)
 
			/* Gracefullly finish the program
			 **********************************/
				finish_handler(&rn);
			else if (ew_signal_flag == EW2MSEED_MAKE_REPORT)
				ew2mseedGenReport(&rn);
			else
				continue;				
		}
		
	}

/* We should never get here 
********************************************/
  logit ("pt", "closing WS connections and exiting\n");
  wsKillMenu (&menu_queue);	
  exit(0);  
 } 

 /****************************************************************/
  int processSingleSCN (RINGS *rn, WS_MENU_QUEUE_REC *mq)
  {
	char message[200];
	int retVal;	

	if (rn->verbosity > 2) logit ("", "--------------------------------------\n");

	if (rn->verbosity > 2) logit ("pt",  "Begin processing  %s %s %s\n",
			rn->scnRing->traceRec.sta, rn->scnRing->traceRec.net,
			rn->scnRing->traceRec.chan);
 

  
	/* Get the buffer from the waveserver; process the response
	*********************************************/
	rn->scnRing->traceRec.pBuf = rn->pBuf;
	rn->scnRing->traceRec.bufLen = rn->bufLen;

	/*IGD 03/29/02 We increase the timeout for those snippets which are large */
	retVal = processWsGetTraceBin (&(rn->scnRing->traceRec), 
				mq, rn->TravelTimeout*1000 * 
					rn->scnRing->priority);
	/* If the below statement is true, we have to increase the buffer accordingly
         * IGD 03/18/02 checking for err condition is added
	 **********************************************************/
	if (retVal == WS_ERR_BUFFER_OVERFLOW && rn->scnRing->traceRec.bufLen > rn->bufLen)	{
		rn->bufLen = rn->scnRing->traceRec.bufLen;
		free (rn->pBuf);
		rn->pBuf = (char *) calloc(1, rn->bufLen);
		if (rn->pBuf == NULL)
		{
			fprintf(stderr, "Attempt to re-allocate %ld bytes for rn->pBuf failed\n", 
				rn->bufLen);
			logit("pt", "Attempt to re-allocate %ld bytes for rn->pBuf failed\n",
				 rn->bufLen);
			perror("The reason:");
			exit(-13);
		}
	}

	
	if (rn->scnRing->traceRec.reqEndtime <= rn->scnRing->traceRec.reqStarttime)
	{				
		logit ("pt", "WARNING: <%s %s %s> requested end time %s <= requested starttime time %s\n",
				rn->scnRing->traceRec.sta,
				rn->scnRing->traceRec.net,
				rn->scnRing->traceRec.chan,
				strDate(rn->scnRing->traceRec.reqEndtime, d20),
			 	strDate(rn->scnRing->traceRec.reqStarttime, d20a));
#ifdef SUPPORT_SCNL
		retVal = WS_ERR_SCNL_NOT_IN_MENU;		
#else
		retVal = WS_ERR_SCN_NOT_IN_MENU;		
#endif
		rn->scnRing->traceRec.reqStarttime += 2.; /* add two  second; one is not right */
		rn->scnRing->traceRec.reqEndtime = rn->scnRing->traceRec.reqStarttime + rn->scnRing->timeInterval;	
		logit ("pt", "WARNING: <%s %s %s> requested interval is reset to <%s - %s>\n",
				rn->scnRing->traceRec.sta,
				rn->scnRing->traceRec.net,
				rn->scnRing->traceRec.chan,
				strDate(rn->scnRing->traceRec.reqStarttime, d20), 
				strDate(rn->scnRing->traceRec.reqEndtime, d20a));			 	
	}

	/* 
	 * IGD 08/11/03 Checking the sanity of the output of wsGetTraceBin 
	 */
	if (rn->scnRing->traceRec.actEndtime > (rn->scnRing->tankEndtime + 100))
	{
		logit ("pt", "WARNING: <%s %s %s> end time from WaveServer  %s > requested tank end time %s\n",
				rn->scnRing->traceRec.sta,
				rn->scnRing->traceRec.net,
				rn->scnRing->traceRec.chan,
				strDate(rn->scnRing->traceRec.actEndtime, d20), 
				strDate(rn->scnRing->tankEndtime, d20a));
#ifdef SUPPORT_SCNL
		retVal = WS_ERR_SCNL_NOT_IN_MENU;		
#else
		retVal = WS_ERR_SCN_NOT_IN_MENU;		
#endif
		rn->scnRing->traceRec.reqStarttime += 100.; /* add two  second; one is not right */
		rn->scnRing->traceRec.reqEndtime = rn->scnRing->traceRec.reqStarttime + rn->scnRing->timeInterval;	
		logit ("pt", "WARNING: <%s %s %s> requested interval is reset to <%s - %s>\n",
				rn->scnRing->traceRec.sta,
				rn->scnRing->traceRec.net,
				rn->scnRing->traceRec.chan,
				strDate(rn->scnRing->traceRec.reqStarttime, d20), 
				strDate(rn->scnRing->traceRec.reqEndtime, d20a));	
	}

	if (retVal != WS_ERR_NONE)  /* IGD 02/27/01 changed */
	{	
		return retVal;
	}


	/* IGD 11/21/02 Here we gonna change the date of the file is required 
	 * We moved the snippet here from the main function to prevent a creation
	 * of empty files: i.e., we only bother to create a new file is processWsGetTraceBin
	 * returned real data. 
	 */
	if (rn->scnRing->newFileJulTime <= rn->scnRing->traceRec.reqStarttime )
	{
		free(rn->scnRing->curMseedFile);
		rn->scnRing->curMseedFile = ew2mseedUpdateFileName
			(&(rn->scnRing->traceRec), rn->scnRing->dir, 
			rn->scnRing->locId);
		rn->scnRing->newFileJulTime = findNewFileJulTime (rn->scnRing->traceRec.reqStarttime);
		rn->scnRing->mseedSeqNo = 1;
		logit ("pt", "New file is avaialble for writing: %s\n",
			rn->scnRing->curMseedFile);
	}

 	retVal =createMseed (rn->scnRing,
		                rn->verbosity);

 	sprintf(message, "createMseed %s %s %s %s ", 
		rn->scnRing->traceRec.sta, rn->scnRing->traceRec.chan, 
		rn->scnRing->traceRec.net, rn->scnRing->locId);	
	if (rn->verbosity > 3) LogWsErr(message, retVal);


	return retVal;
  }
