/*
 *   DIS/x : An implementation of the IEEE 1278.1 protocol
 *
 *   Copyright (C) 1996, Riley Rainey (rainey@netcom.com)
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of either:
 *
 *   a) the GNU Library General Public License as published by the Free
 *   Software Foundation; either version 2 of the License, or (at your
 *   option) any later version.  A description of the terms and conditions
 *   of the GLPL may be found in the "COPYING.LIB" file.
 *
 *   b) the "Artistic License" which comes with this Kit.  Information
 *   about this license may be found in the "Artistic" file.
 *
 *   This library 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
 *   Library General Public License or the Artistic License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this library; if not, write to the Free
 *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *   Information describing how to contact the author can be found in the
 *   README file.
 */

/**
 * Test program that continously displays all the incoming DIS packets.
 * Currently operates only in broadcast mode on the UDP port 3000.
 * 
 * @file
 */

#include "../dis/dis.h"
#ifdef _DEBUG
#include <crtdbg.h>
#endif
#ifndef WINNT
#include <sys/time.h>
#endif
#include <stdio.h>


static void
PrintEntityID (dis_entity_id *p)
{
	printf ("%d.%d.%d", p->sim_id.site_id,
		p->sim_id.application_id,
		p->entity_id);
}


static void
PrintEmitterSystem (dis_em_system_info *p)
{
	dis_emitter_system *p1 = &p->emitter_system;
	char *s;
	int	i;

	switch (p1->function) {
	case DISEmitterFuncUnknown:
		s = "Unknown";
		break;
	case DISEmitterFuncLandBasedAirDefense:
		s = "Land Based Air Defense";
		break;
	case DISEmitterFuncBattlefieldAndGroundSurveillance:
		s = "Battlefield And Ground Surveillance";
		break;
	case DISEmitterFuncNavalSurveillanceAndNavigation:
		s = "Naval Surveillance And Navigation";
		break;
	case DISEmitterFuncNavalFireControl:
		s = "Naval Fire Control";
		break;
	case DISEmitterFuncAirborneSurveillance:
		s = "Airborne Surveillance";
		break;
	case DISEmitterFuncAirborneFireControl:
		s = "Airborne Fire Control";
		break;
	case DISEmitterFuncSpaceborne:
		s = "Spaceborne";
		break;
	case DISEmitterFuncATCInstrumentationAndRanging:
		s = "ATC Instrumentation And Ranging";
		break;
	case DISEmitterFuncWeather:
		s = "Weather";
		break;
	case DISEmitterFuncMissileGuidance:
		s = "Missile Guidance";
		break;
	case DISEmitterFuncJamming:
		s = "Jamming";
		break;
	default:
		s = "Unknown*";
		break;
	}
	printf ("        %s (%d, %d) (system data length = %d)\n", s, p1->name, p1->id,
		p->sys_data_length);
	for (i=0; i<p->num_beams; ++i) {
	    printf ("            beam %d: length %d; targets %d\n", p->beam[i].beam_id,
		p->beam[i].beam_data_length, p->beam[i].num_targets);
	}
}

static char *
PDUName (dis_pdu *pdu)
{
	char *s = "*Unknown*";
	switch (pdu->hdr.pdu_type) {
	case PDUTypeOther:
		s = "Other";
		break;
	case PDUTypeEntityState:
		s = "Entity State";
		break;
	case PDUTypeFire:
		s = "Fire";
		break;
	case PDUTypeDetonation:
		s = "Detonation";
		break;
	case PDUTypeCollision:
		s = "Collision";
		break;
	case PDUTypeServiceRequest:
		s = "Service Request";
		break;
	case PDUTypeResupplyOffer:
		s = "Resupply Offer";
		break;
	case PDUTypeResupplyReceived:
		s = "Resupply Received";
		break;
	case PDUTypeResupplyCancel:
		s = "Resupply Cancel";
		break;
	case PDUTypeRepairComplete:
		s = "Repair Complete";
		break;
	case PDUTypeRepairResponse:
		s = "Repair Response";
		break;
	case PDUTypeCreateEntity:
		s = "Create Entity";
		break;
	case PDUTypeRemoveEntity:
		s = "Remove Entity";
		break;
	case PDUTypeStartResume:
		s = "Start/Resume";
		break;
	case PDUTypeStopFreeze:
		s = "Stop/Freeze";
		break;
	case PDUTypeAcknowledge:
		s = "Acknowledge";
		break;
	case PDUTypeActionRequest:
		s = "Action Request";
		break;
	case PDUTypeActionResponse:
		s = "Action Response";
		break;
	case PDUTypeDataQuery:
		s = "Data Query";
		break;
	case PDUTypeSetData:
		s = "Set Data";
		break;
	case PDUTypeData:
		s = "Data";
		break;
	case PDUTypeEventReport:
		s = "Event Report";
		break;
	case PDUTypeComment:
		s = "Message";
		break;
	case PDUTypeEmission:
		s = "EM Emission";
		break;
	case PDUTypeDesignator:
		s = "Designator";
		break;
	case PDUTypeTransmitter:
		s = "Transmitter";
		break;
	case PDUTypeSignal:
		s = "Signal";
		break;
	case PDUTypeReceiver:
		s = "Receiver";
		break; 
	case PDUTypeTransferControl:
		s = "Transfer Control";
		break;
	}
	return s;
}

int main(int argc, char **argv)
{
	dis_Transceiver *xcvr;
	dis_pdu	pdu;
	struct timeval tm;
	int	i, count;
#ifdef WINNT
	WORD wVersionRequested; 
	WSADATA wsaData; 
	int err; 
	wVersionRequested = MAKEWORD(1, 1); 
 
	err = WSAStartup(wVersionRequested, &wsaData); 
 
	if (err != 0) {
		fprintf (stderr, "Windows Sockets initialization failed.\n");
		exit (2);
	}
#endif

	xcvr = dis_openTransceiver(0, NULL, 3000);

	printf ("%d broadcast interface(s) detected\n", xcvr->num_dest);
	
	count = 0;
	while (1) {
		if( ! dis_readPDU (xcvr, &pdu) )
			continue;
		printf ("\npacket; type %d -- \"%s\" (%d bytes)\n", 
				pdu.hdr.pdu_type, PDUName(&pdu), pdu.hdr.length);
		printf ("    Version      %d\n", pdu.hdr.protocol_version);
		printf ("    Family       %d\n", pdu.hdr.protocol_family);
		printf ("    Exercise id  %d\n", pdu.hdr.exercise_id);
		dis_timestampToTimeval (&pdu.hdr.time_stamp, &tm);
		printf ("    Time stamp   %ld.%ld\n", tm.tv_sec,
			tm.tv_usec / 1000);
		switch (pdu.hdr.pdu_type) {
		case PDUTypeEntityState:
		    printf ("    Entity (sim.app.eid) : %d/%d/%d\n",
			pdu.entity_state.id.sim_id.site_id,
			pdu.entity_state.id.sim_id.application_id, 
			pdu.entity_state.id.entity_id);
		    printf ("    Entity type: %s\n", dis_entityTypeToString(&pdu.entity_state.type));
			printf ("    Geocentric Position (meters) :  %.1f, %.1f, %.1f\n",
					pdu.entity_state.pos.x, 
					pdu.entity_state.pos.y,
					pdu.entity_state.pos.z);
			printf ("    Geocentric Velocity (meters/sec) :  %.1f, %.1f, %.1f\n",
					pdu.entity_state.vel.x, 
					pdu.entity_state.vel.y,
					pdu.entity_state.vel.z);
		    printf ("    Articulation parameters: %d\n",
			pdu.entity_state.art_parm_count);
		    printf ("\n");
		    break;
		case PDUTypeDetonation:
		    printf ("    Firing Entity (sim.app.eid) :   ");
		    PrintEntityID (&pdu.detonation.firing_id);
		    printf ("\n    Target Entity (sim.app.eid) :   ");
		    PrintEntityID (&pdu.detonation.target_id);
		    printf ("\n    Munition Entity (sim.app.eid) : ");
		    PrintEntityID (&pdu.detonation.munition_id);
		    printf ("\n\n");
		    break;
		case PDUTypeEmission:
		    printf ("    Emitting Entity (sim.app.eid) :   ");
		    PrintEntityID (&pdu.em_emission.emitter_id);
		    printf ("\n    State Update Indicator        : %d",
		   	pdu.em_emission.state_update);
		    printf ("\n    Number of Systems             : %d\n",
		    	pdu.em_emission.num_systems);
		    for (i=0; i<pdu.em_emission.num_systems; ++i) {
		    	PrintEmitterSystem
		    		(&pdu.em_emission.system[i]);
		    }
		    printf ("\n\n");
		    break;
		case PDUTypeAcknowledge:
		    printf ("    Originating Entity (sim.app.eid) :   ");
		    PrintEntityID (&pdu.acknowledge.orig_id);
		    printf ("\n    Receiving Entity (sim.app.eid) :   ");
		    PrintEntityID (&pdu.acknowledge.recv_id);
		    printf ("\n    Request ID :      ");
		    printf ("%u", pdu.acknowledge.request_id);
		    printf ("\n    Acknowldge Flag : ");
		    printf ("%d", pdu.acknowledge.acknowledge_flag);
		    printf ("\n    Response Flag :   ");
		    printf ("%d", pdu.acknowledge.resp_flag);
		    printf ("\n\n");
		    break;
		case PDUTypeTransferControl:
		    printf ("    Originating Entity (sim.app.eid) :   ");
		    PrintEntityID (&pdu.transfer_control.orig_id);
		    printf ("\n    Receiving Entity (sim.app.eid) :   ");
		    PrintEntityID (&pdu.transfer_control.recv_id);
		    printf ("\n    Target Entity (sim.app.eid) : ");
		    PrintEntityID (&pdu.transfer_control.target_id);
		    printf ("\n    Request ID :    ");
		    printf ("%u", pdu.transfer_control.request_id);
		    printf ("\n    Transfer Type : ");
		    printf ("%d", pdu.transfer_control.transfer_type);
		    printf ("\n\n");
		    break;
		}

		dis_freePDUComponents(&pdu);

		++ count;
	}
	return 0;
}
