/*
Copyright (c) 2000,2001                      RIPE NCC


All Rights Reserved

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of the author not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.

THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/*
-------------------------------------------------------------------------------
Module Header
Filename          : Delay.cxx
Author            : Rene Wilhelm
Date              : 07-JUL-2000
Revised		  : 02-JUL-2001 extended check on NTP status word 
Revised		  : 12-JUL-2001 define DelaySummary class methods
Description       : Implementation of TTM Delay and DelaySummary classes
Language Version  : C++
OSs Tested        : Solaris 2.6, Solaris8, Debian Linux 2.2
Comments	  : macros used in checking ntp status word are
		    defined in Delay.h
$Id: Delay.cxx,v 1.8 2003/06/19 13:58:56 ttraffic Exp $
-------------------------------------------------------------------------------
*/


#include "Delay.h"

ClassImp(Delay)

Delay::Delay() {
   // cout << "Contructor for Delay\n";
}

Delay::~Delay() {
   // cout << "Destructor for Delay\n";
}
 
Delay::Delay (struct packet *mypacket) {
   // Create Delay object from packet structure

   PacketId    = mypacket->packet_id;
   SourceId    = mypacket->source_id;
   SourcePort  = mypacket->source_port;
   TargetId    = mypacket->target_id;
   TargetPort  = mypacket->target_port;
   PacketSize  = mypacket->packet_size;
   ArrivalTime = mypacket->arrival_time;
   PacketDelay = mypacket->delay;
   SourceClock = mypacket->source_clock;
   TargetClock = mypacket->target_clock;
   Nhops       = mypacket->nhops;
   RouteId     = mypacket->routeid;
   SourceNtp   = mypacket->source_ntp;
   TargetNtp   = mypacket->target_ntp;

}

Int_t Delay::ClocksOK() {
	// report if both clocks are valid or not

	short SourceOK, TargetOK;

	SourceOK = ((SourceClock & LEAPBITMASK) == GPSGOODCLOCK1) ||
                   ((SourceClock & LEAPBITMASK) == GPSGOODCLOCK2) ||
                   ((SourceClock & LEAPBITMASK) == CDMAGOODCLOCK1) ||
                   ((SourceClock & LEAPBITMASK) == CDMAGOODCLOCK2) ;

	TargetOK = ((TargetClock & LEAPBITMASK) == GPSGOODCLOCK1) ||
                   ((TargetClock & LEAPBITMASK) == GPSGOODCLOCK2) ||
                   ((TargetClock & LEAPBITMASK) == CDMAGOODCLOCK1) ||
                   ((TargetClock & LEAPBITMASK) == CDMAGOODCLOCK2) ;

	return(SourceOK && TargetOK);
}

Double_t Delay::GetPacketTime(time_t starttime) {

	// Return the time the packet was scheduled to send
	// This is by convention coded into the PacketId
	// to ease timestamping the lost packets (no ArrivalTime available)
	//
	// Upto 27 June 2002 packet id equaled Unix time stamp of scheduled 
	// delay measurement. After that, to support higher frequencies
	// than 1 per second, packet id counts ticks of a 100 Hz clock,
	// starting at 0 on 1/1/2002 and cycles after 2000000000 ticks
	// (almost eight months)
	//
	// startime is the timestamp at the start of the time period
	// being analysed by the caller; it is needed to find which
	// cycle we are in. 


#define LASTUNIXTIME 1025189400    // Thu Jun 27 14:50:00 2002 GMT
#define TIMEZERO     1009843200    // Tue Jan  1 00:00:00 2002 GMT
#define CYCLEPERIOD  20000000      // cycle period in seconds
#define FREQUENCY    100.0         // force floating point calculation

        Double_t packettime;
        int nCycles;
        UInt_t starttimeId;     // packetid at starttime

        if (starttime <= LASTUNIXTIME) {
                // no two cycles in delay plot
                if (PacketId > LASTUNIXTIME) {
                        packettime = PacketId / FREQUENCY + TIMEZERO;
                }
                else {
                        packettime = (Double_t) PacketId;
                }
        }
        else {
                // all ids in new packetid schema
                nCycles = (starttime - TIMEZERO) / CYCLEPERIOD;
                starttimeId = (starttime - TIMEZERO - nCycles * CYCLEPERIOD) * FREQUENCY ;
                if (PacketId < starttimeId) {
                        // must have completed a cycle 
                        nCycles++;
                }
                packettime = PacketId / FREQUENCY + nCycles * CYCLEPERIOD + TIMEZERO;
        }
        return(packettime);
}

PacketStatus Delay::Status () {

	// report status of packet, i.e. one of: 
	//	Both clocks valid
	//	only source clock valid
	//	only target clock valid
	//	invalid clocks
	//      packet lost


	short SourceOK, TargetOK;

	// Clock is OK if status word ok AND estimated error < 0.75 ms
	// NOTE: due to NTP peer setup check only possible after 1/Mar/2001

	SourceOK = ((SourceClock & LEAPBITMASK) == GPSGOODCLOCK1) ||
                   ((SourceClock & LEAPBITMASK) == GPSGOODCLOCK2) ||
                   ((SourceClock & LEAPBITMASK) == CDMAGOODCLOCK1) ||
                   ((SourceClock & LEAPBITMASK) == CDMAGOODCLOCK2) ;

	TargetOK = ((TargetClock & LEAPBITMASK) == GPSGOODCLOCK1) ||
                   ((TargetClock & LEAPBITMASK) == GPSGOODCLOCK2) ||
                   ((TargetClock & LEAPBITMASK) == CDMAGOODCLOCK1) ||
                   ((TargetClock & LEAPBITMASK) == CDMAGOODCLOCK2) ;


	if (int(ArrivalTime) > 983404800 ) {
		// NTP error estimates only usefull after 1 Mar 2001
		// The 0.5ms limit is liberal enough to not unjustly
		// invalidate too many packets
		SourceOK = SourceOK && (SourceNtp < 0.5);
		TargetOK = TargetOK && (TargetNtp < 0.5);
	}

	if  (SourceOK  && TargetOK) {
		return(ClockValid);
	}
	else if (! SourceOK && TargetOK) { 
		return(ClockTrgValid);
	}
	else if  (SourceOK && ! TargetOK) { 
		return(ClockSrcValid);
	}
	else if ( ArrivalTime > 0.0 ) {
		return(ClockInvalid);
	}
	return(PacketLost);
}


// Implementation of Delay Summary class 
// See Delay.h for details

ClassImp(DelaySummary)

DelaySummary::DelaySummary() {

   // Default Creator: fill object with values which are clearly out of range

    TargetId    = -1;
    SourceId    = -1;
    BinNo       = -1;
    NumDays     = -1;
    NumEntries  = -1;
    TimeLow     =  0.0;
    BinSize     =  0.0;
    Level025    = -10000.0;
    Median      = -10000.0;
    Level975    = -10000.0;
}

DelaySummary::~DelaySummary() {
	// Object destructor, nothing to do
}
