// 
// ======================================================================
// Copyright (C) 2000-2003 Instrumental Software Technologies, Inc. (ISTI)
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. If modifications are performed to this code, please enter your own 
// copyright, name and organization after that of ISTI.
// 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/)."
// 8. Redistributions of source code, or portions of this source code,
// must retain the above copyright notice, this list of conditions
// and the following disclaimer.
// 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.
// 

/*
 * q3302ew
 * 
 * main
 * VERSION number 0.1 - 17-Feb-2004 - first release
 * Version number 0.2 - 26-Jul-2005 - fixed numerous issues and ported to Linux
 */

#include <stdio.h>
#include "main.h"
#include "externs.h"
#include "options.h"
#include "config.h"
#include "heart.h"
#include "global.h"
#include "TxCmd.h"
#include "RxMsg.h"
#include "Cleanup.h"
#include "CheckLCQS.h"
#include "CheckPCQS.h"
#include "qmautils.h"
#include "logo.h"
#include "QmaDiag.h"
#include "Logger.h"
#include <signal.h>

extern "C" {
#  include "transport.h"
#  include "earthworm_simple_funcs.h"
#  include "earthworm.h"
};
void check_state();


int ShutMeDown = 0;
SHM_INFO  Region;  
MSG_LOGO OtherLogo;
MSG_LOGO DataLogo;

/* Globals needed by mountainair */
Q330Version      g_Q330Version;
Verbose          g_verbosity;
StateMachine     g_stateMachine;
ConfigVO         g_cvo;
QMA_Port         g_cmdPort;
QMA_Port         g_dataPort;
ModuloCounter    g_cmdPacketSeq;
CountDownTimer   g_cmdTimer;
CountDownTimer   g_dataPortTimer;
CountDownTimer   g_statusTimer;
bool             g_reset;
bool             g_done;
Verbose*         g_verbList; // Not needed. Just for testing
Packet           g_packet_for_tx;
TimeServer       g_timeServer;
AckCounter       g_ackCounter;
TokenVO          g_tvo;
int              g_nextTokenAddress;
int              g_segmentsReceived;
int              g_bytesInBuffer;
char             g_tokenBuffer[C1_MAXCFG];
int              g_totalSegments;
qma_uint16       g_nextPacketSeqno;
int              g_totalFillPackets;
InputPacket      g_inputQueue[MAX_SLIDING_WINDOW_SIZE];
LCQ*             g_digLCQ_list;
LCQ*             g_mainLCQ_list;
PCQ*             g_digPCQ_list;
PCQ*             g_mainPCQ_list;
LCQVO*           g_digLCQVO_list;
LCQVO*		 g_mainLCQVO_list;
bool             g_outputPacketsQueued;
BTI              g_currentTimeInfo;
bool             g_startingDRSNNeeded;
ModuloCounter    g_dataPacketSeq;
ChanFreqMap      g_digMap_list;
TypeChanFreqMap  g_mainMap_list;
bool             g_lcq_freed;
int              g_number_of_diglcqs;
time_t           g_jan2000;
Logger           g_log;

int             g_currentClockQuality;
int             g_number_of_mainlcqs;

int main(int argc, char **argv) {
  
    fprintf(stderr, "Starting %s, Version %s\n", Q3302EW_NAME, Q3302EW_VERSION);
    


    g_done  = false;
    g_reset = false;
    g_lcq_freed = true;


    

	// we start off with everything being OK
    g_currentClockQuality = 100;
    handle_opts(argc, argv);

    g_verbosity.setVerbosity(gConfig.verbosity);
    g_verbosity.setDiagnostic(gConfig.diagnostic);
    logit_init(argv[1], QModuleId, 1024, gConfig.LogFile);

    logit( "et", "%s: Version %s\n", Q3302EW_NAME, Q3302EW_VERSION );
	

#ifdef Q3302EW

	SocketSysInit();

#endif

    if(gConfig.LogFile == 1 || gConfig.LogFile == 2) {
      fprintf(stderr, "--- Logging to logfile\n");
      g_log.logToFile(true);
    }
    if(gConfig.LogFile == 0 || gConfig.LogFile == 1) {
      fprintf(stderr, "--- Logging to Stdout\n");
      g_log.logToStdout(true);
    }
    
    // set up our local epoch (jan 1, 2000)
    struct tm tmJan2000;
    tmJan2000.tm_sec = 0;
    tmJan2000.tm_min = 0;
    tmJan2000.tm_hour = 0;
    tmJan2000.tm_mday = 1;
    tmJan2000.tm_mon = 0;
    tmJan2000.tm_year = 100;
#ifdef _LINUX
    g_jan2000 = timegm(&tmJan2000);
#else
    g_jan2000 = mktime(&tmJan2000);
#endif

#ifndef _WINNT
    Region.mid = -1;
#endif

    if ( GetType( "TYPE_HEARTBEAT", &TypeHB ) != 0 ) {
      fprintf( stderr,
	       "%s: Invalid message type <TYPE_HEARTBEAT>\n", Q3302EW_NAME);
      return( -1 );
    }
    if ( GetType( "TYPE_TRACEBUF", &TypeTrace ) != 0 ) {
      fprintf( stderr,
	       "%s: Invalid message type <TYPE_TRACEBUF>; exiting!\n", Q3302EW_NAME);
      return(-1);
    }
    if ( GetType( "TYPE_ERROR", &TypeErr ) != 0 ) {
      fprintf( stderr,
	       "%s: Invalid message type <TYPE_ERROR>\n", Q3302EW_NAME);
      return( -1 );
    }
    
    setuplogo(&DataLogo);
    DataLogo.type = TypeTrace;
    setuplogo(&OtherLogo);


    //printConfigStructToStdErr();

    fprintf(stderr, "Starting heartbeat\n");
    tport_attach(&Region, gConfig.RingKey);
    time(&TSLastBeat);
  
    // set up signal handling to clean up properly
    // when killed/exiting
#ifndef _WINNT
    signal (SIGHUP ,CleanQMA) ;
    signal (SIGKILL,CleanQMA) ;
    signal (SIGQUIT,CleanQMA) ;
#endif

    signal (SIGINT ,CleanQMA) ;
  
    StartThread(Heartbeat, 8192, &TidHB);

    while(!ShutMeDown && !g_done) {
      ResetQMA();
      g_reset = false;
      openLocalIPPorts();
      while(!g_reset) {
        /* stop looping if we're being asked to stop */
        if ( tport_getflag( &Region ) == TERMINATE ) {
			fprintf(stderr, "Q3302EW is about to die.\n");
			fflush(stderr);
			CleanQMA(12);
			exit(0);
	  break;
        }
	//std::cout << "About to tx";
	tx_cmd();
	//std::cout << "About to rx";
	rx_msg();
	//std::cout << "About to check_lcq";
	if(g_stateMachine.getState() == AcquiringData) {
	  check_lcqs();
	}
	//std::cout << "About to check_pcq";
	if(g_stateMachine.getState() == AcquiringData) {
	  check_pcqs();
	}
	//scan_comserv_clients();
	check_state();
      }
#ifdef _WINNT
      Sleep(1000);
#else
      sleep(1);
#endif
    }

	return 1;
}
 
void check_state()
{

  MainStates mstate = g_stateMachine.getState();
  if(mstate == Resetting)
  {
    //std::cout << "Resetting" << std::endl;
    ResetQMA();
    //std::cout << "Reset" << std::endl;
  }
  else if(mstate == Exitting)
  {
    //std::cout << "Cleaning" << std::endl;
    CleanQMA(12);
    //std::cout << "Cleaned" << std::endl;
  }
  return;
}
