/*
 *   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.
 */
#include <dis/dis.h>
#ifdef _DEBUG
#include <crtdbg.h>
#endif
#ifndef WIN32
#include <sys/time.h>
#endif
#include <stdio.h>

char * PDUName (dis_pdu *pdu);
void PrintEntityType ();
void PrintEntityTypeName ();
void PrintEntityID ();
void PrintEmitterSystem ();

int
main ()
{
	DISTransceiver *xcvr;
	dis_pdu	pdu;
	struct timeval tm;
	char	buf[32];
	int	i, count;
	dis_simulation_addr	my_addr;
	dis_entity_type		type;
	char	site[64];
	int	code;
#ifdef WIN32
	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 = DISOpenTransceiver(-1);

#ifndef WIN32
	code = SIMxRegisterApplication ((char *) NULL,
		SIMxGetSiteName(site, sizeof(site)),
		0, &my_addr);
	if (code != 0) {
		fprintf (stderr, "Error connecting to SIMx server: %d\n", code);
		exit (1);
	}
#endif

	printf ("%d broadcast interface(s) detected\n", xcvr->num_dest);
	
	count = 0;
	while (1) {
		DISReadPDU (xcvr, &pdu);
		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);
		DISTimestampToTimeval (&pdu.hdr.time_stamp, &tm);
		printf ("    Time stamp   %d.%d\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: ");
		    PrintEntityType (&pdu.entity_state.type);
		    printf (" (");
		    PrintEntityTypeName (&pdu.entity_state.type);
		    printf (")\n");
			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 ("%d", 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 ("%d", pdu.transfer_control.request_id);
		    printf ("\n    Transfer Type : ");
		    printf ("%d", pdu.transfer_control.transfer_type);
		    printf ("\n\n");
		    break;
		}

		DISFreePDUComponents(&pdu);

#ifdef _DEBUG
		_CrtDumpMemoryLeaks();
#endif
		++ count;
	}
	return;
}

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 PDUTypeMessage:
		s = "Message";
		break;
	case PDUTypeEmission:
		s = "EM Emission";
		break;
	case PDUTypeLaser:
		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;
}

void
PrintEntityType (dis_entity_type *p)
{
	printf ("%d.%d.%d.%d.%d.%d.%d", p->kind, p->domain,
		p->country, p->category, p->subcategory,
		p->specific, p->extra);
}

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

void
PrintEntityTypeName (dis_entity_type *p)
{
#ifndef WIN32
	char res[8][64];
	char *r[8];
	r[0] = &res[0][0];
	r[1] = &res[1][0];
	r[2] = &res[2][0];
	r[3] = &res[3][0];
	r[4] = &res[4][0];
	r[5] = &res[5][0];
	r[6] = &res[6][0];
	r[7] = &res[7][0];

	SIMxLookupEntityNames(p, r, 64);
	printf ("%s/%s/%s/%s/%s/%s", r[0], r[1], r[2], r[3], r[4], r[5]);
#endif
}

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);
	}
}


