/*
    mtr  --  a network diagnostic tool
    Copyright (C) 1997,1998  Matt Kimball

    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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <config.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <math.h>

#include "display.h"
#include "dns.h"
#include "net.h"

extern int Interactive;
extern int MaxPing;
extern float WaitTime;
double dnsinterval;

static struct timeval intervaltime;


void select_loop() {
  fd_set readfd;
  int anyset;
  int action, maxfd;
  int dnsfd, netfd;
  int NumPing;
  int paused;
  struct timeval lasttime, thistime, selecttime;
  float wt;
  int dt;

  NumPing = 0; 
  anyset = 0;
  gettimeofday(&lasttime, NULL);
  paused=0;

  while(1) {
    dt = calc_deltatime (WaitTime);
    intervaltime.tv_sec  = dt / 1000000;
    intervaltime.tv_usec = dt % 1000000;

    FD_ZERO(&readfd);

    maxfd = 0;

    if(Interactive) {
      FD_SET(0, &readfd);
      maxfd = 1;
    }

    dnsfd = dns_waitfd();
    FD_SET(dnsfd, &readfd);
    if(dnsfd >= maxfd)
      maxfd = dnsfd + 1;

    netfd = net_waitfd();
    FD_SET(netfd, &readfd);
    if(netfd >= maxfd)
      maxfd = netfd + 1;

    if(anyset || paused) {
      selecttime.tv_sec = 0;
      selecttime.tv_usec = 0;
      
      select(maxfd, (void *)&readfd, NULL, NULL, &selecttime);
    } else {
      if(Interactive) 
	display_redraw();

      gettimeofday(&thistime, NULL);

      if(thistime.tv_sec > lasttime.tv_sec + intervaltime.tv_sec ||
         (thistime.tv_sec == lasttime.tv_sec + intervaltime.tv_sec &&
          thistime.tv_usec >= lasttime.tv_usec + intervaltime.tv_usec)) {
        lasttime = thistime;
        if(NumPing >= MaxPing && !Interactive)
          break;
        if (net_send_batch())
	  NumPing++;
      }

      selecttime.tv_usec = (thistime.tv_usec - lasttime.tv_usec);
      selecttime.tv_sec = (thistime.tv_sec - lasttime.tv_sec);
      if (selecttime.tv_usec < 0) {
	--selecttime.tv_sec;
	selecttime.tv_usec += 1000000;
      }
      selecttime.tv_usec = intervaltime.tv_usec - selecttime.tv_usec;
      selecttime.tv_sec = intervaltime.tv_sec - selecttime.tv_sec;
      if (selecttime.tv_usec < 0) {
	--selecttime.tv_sec;
	selecttime.tv_usec += 1000000;
      }

      if ((selecttime.tv_sec > (time_t)dnsinterval) ||
          ((selecttime.tv_sec == (time_t)dnsinterval) &&
           (selecttime.tv_usec > ((time_t)(dnsinterval * 1000000) % 1000000)))) {
        selecttime.tv_sec = (time_t)dnsinterval;
        selecttime.tv_usec = (time_t)(dnsinterval * 1000000) % 1000000;
      }

      select(maxfd, (void *)&readfd, NULL, NULL, &selecttime);
    }

    anyset = 0;

    /* Handle any pending resolver events */
    dnsinterval = WaitTime;
    dns_events(&dnsinterval);

    /*  Has a key been pressed?  */
    if(FD_ISSET(0, &readfd)) {
      action = display_keyaction();

      if(action == ActionQuit)
	break;

      if(action == ActionReset) 
	net_reset();

      if (action == ActionDisplay) 
        display_mode = (display_mode+1) % 3;

      if (action == ActionClear) 
	display_clear();

      if (action == ActionPause) 
	paused=1;

      if (action == ActionResume) 
	paused=0;

      anyset = 1;
    }

    /*  Have we finished a nameservice lookup?  */
    if(FD_ISSET(dnsfd, &readfd)) {
      dns_ack();
      anyset = 1;
    }

    /*  Have we got new packets back?  */
    if(FD_ISSET(netfd, &readfd)) {
      net_process_return();
      anyset = 1;
    }
  }
}

