/*----------------------------------------------------------------------------
	NETMAIN.C -- Network Game Support for Max. Road. Kill..................
----------------------------------------------------------------------------*/

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <mem.h>
#include <graph.h>
#include <i86.h>
#include <dos.h>

#include "netnow.h"
#include "..\gendefs.h"
#include "..\multi.h"
#include "jcassert.h"
#include "netdefs.h"

// initalisation stuff

_NETNOW_NODE_ADDR NetworkAddresses[MAX_NETWORK_PLAYERS];
int NodesFound[MAX_NETWORK_PLAYERS];
int MaxNodesFound;
int OldMaxNodesFound;
int MaxNodeChangeCount;
int NodesIFound = 1;
int GameNode = 0;

// queue pointer stuff

ubyte NETqueueindex = 0;
NetworkPacket receivers[MAX_NETWORK_PACKETS];

void RefreshListeners()
{
	while (hmiNETNOWPostListen());
}


/*----------------------------------------------------------------------------
	Given the address of a node work out if it is one we know about
-----------------------------------------------------------------------------*/
int IsNewNode( _NETNOW_NODE_ADDR *addr )
{
	int i;

	assert(addr != NULL);
	assert(NodesIFound > 0);
	assert(NodesIFound <= MAX_NETWORK_PLAYERS);

	for(i=0; i < NodesIFound; i++)
	{
		if (memcmp(addr,&NetworkAddresses[i],sizeof(_NETNOW_NODE_ADDR)) == 0)
			return FALSE;
	}
	return TRUE;
} // IsNewNode()




/*----------------------------------------------------------------------------
	AddNetworkNode
----------------------------------------------------------------------------*/
void AddNetworkNode( _NETNOW_NODE_ADDR  *addr )
{
int i,insertat;

	// find out where in the array to insert
	assert( addr != NULL );

	for( i=0; i < MAX_NETWORK_PLAYERS; i++ )
	{
		if (NodesFound[i] == -1)
		{
			insertat = i;
			break;
		}
	}


	// make space in the array for the entry
	assert(insertat >= 0);
	assert(insertat < MAX_NETWORK_PLAYERS);
	memcpy( &NetworkAddresses[insertat], addr, sizeof( _NETNOW_NODE_ADDR ));
	NodesFound[insertat] = 0;

} // AddNetworkNode()



/*
	UpdateNodeFoundList() -- given a node address and the number of nodes it has
  found .. update that entry in the list	return TRUE if the entry changed,
  FALSE if not............
*/
int UpdateNodeFoundList( _NETNOW_NODE_ADDR *addr, int NodesKnown )
{
	int i;

	assert( addr != NULL );
	assert( NodesKnown >= 0 );
	assert( NodesKnown <= MAX_NETWORK_PLAYERS );

	for(i = 0; i < NodesIFound; i++)
	{
		if (memcmp(&NetworkAddresses[i], addr, sizeof(_NETNOW_NODE_ADDR)) == 0)
		{
			if (NodesFound[i] == NodesKnown)
				return FALSE;
			else
			{
				NodesFound[i] = NodesKnown;
				return TRUE;
			}
		}
	}
	assert(FALSE);	// should never reach here
	return FALSE;
} // UpdateNodeFoundList()



/*----------------------------------------------------------------------------
	Screen Setup Routines
-----------------------------------------------------------------------------*/
void SetUpScreen(int row,int col,int row2,int col2)
{
	int  i;
	unsigned char chs[] = "\0";

	_setvideomode(_TEXTC80);
	_setbkcolor(_BLACK);
	_settextcolor(15);
	_clearscreen(_GWINDOW);
	*chs = 0xCD;
  for(i=col; i <= col2; i++)
	{
    _settextposition(row-1,i);
		_outtext(chs);
    _settextposition(row2+1,i);
		_outtext(chs);
	}
	*chs = 0xBA;
  for(i=row; i <= row2; i++)
	{
    _settextposition(i,col-1);
		_outtext(chs);
    _settextposition(i,col2+1);
		_outtext(chs);
	}
	*chs = 0xC9;
  _settextposition(row-1,col-1);
	_outtext(chs);
	*chs = 0xBB;
  _settextposition(row-1,col2+1);
	_outtext(chs);
	*chs = 0xC8;
  _settextposition(row2+1,col-1);
	_outtext(chs);
	*chs = 0xBC;
  _settextposition(row2+1,col2+1);
	_outtext(chs);
  _setbkcolor(_BLUE);
	_settextcolor(14);
	_settextwindow(row,col,row2,col2);
	_clearscreen(_GWINDOW);

} // SetUpScreen()



/*
	End of game cleanup function
*/
void NetCleanUp()
{
	hmiNETNOWUnInitSystem();
}



/*
	returns (if result <= 0) (labels in "multi.h")
		NO_GAME 				 -- no - one out there or IPX/NETBIOS not around
		GAME_IN_PROGRESS -- there is a netgame going on that we can join
	else
		returns (# of players)
*/
int IsNetGame(int waittime)
{
int	i;
 NetworkPacketHeader InitHeader;
 NetworkInitPacket   InitPacket;
NetworkPacketHeader MyInitHeader;
NetworkInitPacket   MyInitPacket;
_NETNOW_NODE_ADDR   MyAddress;
_NETNOW_NODE_ADDR   OtherAddress;


	memset(NetworkAddresses, 0, sizeof(_NETNOW_NODE_ADDR)*MAX_NETWORK_PLAYERS);
	for(i=0; i < MAX_NETWORK_PLAYERS; i++)
		NodesFound[i] = -1;

	SetUpScreen(3,3,23,78);
	if ((hmiNETNOWInitSystem(MAX_NETWORK_PLAYERS)) != _NETNOW_NO_ERROR)
	{
		_outtext("Failed to detect Network\n");
		return NO_GAME;
	}

	switch( hmiNETNOWGetNetworkType() )
	{
		case  _NETNOW_IPX:
		  _outtext("IPX Network Detected\n");
		  break;
		case  _NETNOW_NETBIOS:
			_outtext("NetBIOS Network Detected\n");
		  break;
	}

 	if (atexit(NetCleanUp))
		assert(FALSE);

	RefreshListeners();
  MaxNodesFound = 1;
  MaxNodeChangeCount = 0;
	if (!hmiNETNOWGetNetworkAddr(&MyAddress))
		assert(FALSE);
	AddNetworkNode(&MyAddress);
	while(MaxNodeChangeCount <= waittime)
	{
		// if key hit, skip
		_outtext("*");
//		if (kbhit())
//			break;

		// broadcast the number of nodes we found
		MyInitHeader.PacketType = NET_INIT_PACKET;
		MyInitHeader.MyNode     = GameNode;
		MyInitPacket.NodesIKnow = NodesIFound;
		memcpy( &MyInitPacket.MyAddress, &MyAddress, sizeof( _NETNOW_NODE_ADDR ));

		if (!hmiNETNOWSendData((PSTR)&MyInitHeader,sizeof(NetworkPacketHeader),
				(PSTR)&MyInitPacket,sizeof(NetworkInitPacket),_NETNOW_BROADCAST))
			assert(FALSE);

		// wait a bit
		mydelay(500/5);
		//delay(500);
		// check the queue for repiles
		memset(&InitPacket, 0xcf, sizeof(NetworkInitPacket));
		while( hmiNETNOWGetData( (PSTR) &InitHeader, sizeof(NetworkPacketHeader), (PSTR) &InitPacket, sizeof(NetworkInitPacket) ) != _FALSE)
		{
			// for each reply
			_outtext("#");
	      if (InitHeader.PacketType == NET_INIT_PACKET)
	      {
				// if its a new node add it to list, resort list, get new node #
				memcpy(&OtherAddress, &InitPacket.MyAddress, sizeof( _NETNOW_NODE_ADDR));
				if ( hmiNETNOWAddNode( &OtherAddress ) == _NETNOW_ADD_COMPLETE )
				{
						AddNetworkNode( &OtherAddress );
						assert( NodesIFound <= MAX_BYKES );
				}
				else
				{
					if (UpdateNodeFoundList(&OtherAddress, InitPacket.NodesIKnow))
						MaxNodeChangeCount = 0;
				}
				hmiNETNOWSortNodes();
				GameNode = hmiNETNOWGetConsoleNode();
				NodesIFound = hmiNETNOWGetActiveNodes();
				//and bump up nodes I found
				MyInitPacket.NodesIKnow = NodesIFound;
				//if it has found more nodes than i change MaxNodesFound
				//    set MaxNodeChangeCount to 0
        		//if it is a game start, mark that node in the arry
			}
			else
				_outtext("!");
			hmiNETNOWPostListen();
			MaxNodeChangeCount++;
		}
	}
	if (MaxNodeChangeCount > waittime)
		return NodesIFound;
	else
		return NO_GAME; // defensive catch all
}	//IsNetGame()



// sends a packet to all nodes on the network
// returns TRUE for success FALSE for faliure
int NetworkTxPacket(NetworkPacket *NetPacket, word Type)
{
int i;
NetworkPacketHeader MyHeader;
static NetworkPacket MyPacket;

	memcpy(&MyPacket[0],NetPacket,sizeof(NetworkPacket));
	assert(NetPacket != NULL);
	assert(Type >= 0);
	assert(Type < MAX_PACKET_TYPES);
	assert(*((char *) (&MyPacket)) == 2);
	assert(*((char *) ((&MyPacket[0])+1)) < 5);

	// setup header
	MyHeader.PacketType = Type;
	MyHeader.MyNode = GameNode;

	// send to all nodes
	for(i=0;i<NodesIFound;i++)
	{
		if (i==GameNode)
			continue;
		if (hmiNETNOWSendData((PSTR)&MyHeader,sizeof(NetworkPacketHeader),
				(PSTR)&MyPacket,sizeof(NetworkPacket),i)==FALSE)
			return FALSE;
	}
	return TRUE;
} // NetworkTxPacket



void NetworkRxPoll(void)
{
static NetworkPacketHeader MyHeader;
static NetworkPacket       MyPacket;

  while( hmiNETNOWGetData( (PSTR) &MyHeader, sizeof(NetworkPacketHeader), (PSTR) &MyPacket, sizeof(NetworkPacket) ) )
	{
		// we got someone trying to initalise a game
	 	if ( MyHeader.PacketType == NET_INIT_PACKET )
			hmiNETNOWPostListen();
	   else
		{
			assert(MyHeader.MyNode < NodesIFound);
			assert(*((char *) ((&MyPacket[0]))) == 2);
			assert(*((char *) ((&MyPacket[0])+1)) < 5);
			assert(MyHeader.PacketType < MAX_PACKET_TYPES);
			memcpy(&receivers[NETqueueindex++], &MyPacket[0], sizeof(NetworkPacket));
			hmiNETNOWPostListen();
		}
	}
} // NetworkRxPacket()
