#include "pch.hpp"
//
//
//
// This file is the interface between GameOS and the gosScript generic networking scripts.
//
// When an application comes to rewrite the generic Network scripts it may have to alter
// functions or callbacks in this file.
//
// This file includes GameOS\Network.hpp which exposes more network functions that are
// require to write a lobby or connection screens.
//
//
//
#include <GameOS\Network.hpp>
#include <GosScript\gosScriptHeaders.hpp>
#include <string.h>
#include <stdlib.h>
#include "GUNGameList.h"

//========================================================================
// definitions for callbacks
//========================================================================
#define SCRIPTCALLBACK(func) int __stdcall func( void * instance, int args, void * arg[])
#define SCRIPTVAR_INT(var) int var
#define SCRIPTVAR_STR(var) char * var
#define SCRIPTVAR_ARR(var) char ** var
#define RESET_NULL_TO_EMPTY(ptr) if ((ptr)==NULL) ptr=EMPTY_STRING
#define FREE_PTR(ptr) if ((void *)ptr) { gos_Free((void *)ptr); (ptr)=NULL; }
#define STRING_SIZE		128
#define NUM_ELEMENTS	20



char * const EMPTY_STRING = "";

const char * const APP_HIVE_PATH = "SOFTWARE\\Microsoft\\Microsoft Games\\GUN";

// GUN server fields
//const char * const GUN_IP_HEADER = "Server Address";
//const char * const GUN_INSTANCE_HEADER = "Instance";
//const char * const GUN_NAME_HEADER = "Server Name";
//const char * const GUN_MAX_PLAYERS_HEADER = "Max Players";
//const char * const GUN_PASSWORD_HEADER = "Password Protected";
//const char * const GUN_NUM_PLAYERS_HEADER = "Num Players";
#define GUN_IP_HEADER			GAMELIST_KEY_SERVER_ADDRESS
#define GUN_INSTANCE_HEADER		GAMELIST_KEY_INSTANCE
#define GUN_NAME_HEADER			GAMELIST_KEY_SERVER_NAME
#define GUN_MAX_PLAYERS_HEADER	GAMELIST_KEY_MAX_PLAYERS
#define GUN_PASSWORD_HEADER		GAMELIST_KEY_PASSWORD_PROTECTED
#define GUN_NUM_PLAYERS_HEADER	GAMELIST_KEY_NUM_PLAYERS

// GUN player fields
const char * const GUN_PLAYER_NAME_HEADER = "Player Name";

//
// Used to register all gosScript variables
//
void* NetworkInstance=(void*)-200;



int CheckThisConnection = 0;
int Available=0;
DWORD RegisteredData=0;


DWORD gInSecureGame=0;


//
// Which protocol is being used -1=None
//
// NP_TCP		1
// NP_IPX		2
// NP_SERIAL	3
// NP_MODEM		4
//
int gConnectionType = -1;

//
// Currently entered player name string
//
char* PlayerName=0;

//
// Currently entered server IP address string
//
char* ServerIPAddress=0;

// 
// Location of zone server, filled in from registry key value
//
char* ZoneServerAddress=0;

//
// Current phone number string
//
char* PhoneNumber=0;

//
// Currently selected game name string (or current game if joined/created)
//
char* GameName=0;

//
// Password for game
//
char* Password=0;

// Password for NGStats
char* NGPassword=0;

//
// Current status of GUN connection
//
extern int GUNStatus;

//
// Number of games in game list
//
int NumberOfGames=0;
//
// List box strings of games
//
char** ListOfGameNames=0;
char** ListOfDescriptions=0;
char** ListOfNumPlayers=0;	
char** ListOfPassworded=0;	
char** ListOfLocked=0;
char** ListOfSecure=0;

//
// Number of players in player list
//
int NumberOfPlayers=0;
//
// List box strings of players
//
char** ListOfPlayers=0;


//
// Currently selected serial port
//
DWORD CurrentSerialPort=0;
//
// List box strings of serial ports
//
char** ListOfSerialPorts=0;
//
// Number of serial ports in list
//
DWORD NumberOfSerialPorts=0;


//
// Currently selected modem
//
DWORD CurrentModem=0;
//
// List box strings of modems
//
char** ListOfModems=0;
//
// Number of modems in list
//
DWORD NumberOfModems=0;


const char * const MOD_NAME_FIELD = "Mod Name";
// --
const char * const PRODUCT_NAME_FIELD = "Product Name";
const char * const GAME_VERSION_FIELD = "Game Version";
const char * const INSTANCE_FIELD = "Instance";
const char * const SERVER_ADDRESS_FIELD = "Server Address";
const char * const SERVER_PORT_FIELD = "Server Port";
const char * const SERVER_NAME_FIELD = "Server Name";
const char * const NUM_PLAYERS_FIELD = "Num Players";
const char * const MAX_PLAYERS_FIELD = "Max Players";
const char * const MAP_TYPE_FIELD = "Map Type";
const char * const PASSWORD_STATUS_FIELD = "Password Protected";


/*
    GameList Script API Variables
*/
struct APIVars
{
    char * ProductName;
    char * ModName;
    char * GameVersion;
    char * Instance;
    char * ServerAddress;
    char * ServerPort;
    char * ServerName;
    char * NumPlayers;
    char * MaxPlayers;
    char * PasswordStatus;
    char * MapType;
    char * ExtraField0;
    char * ExtraField1;
    char * ExtraField2;
    char * ExtraField3;
    char * ExtraField4;
    char * ExtraField5;
    char * ExtraField6;
    char * ExtraField7;
    char * ExtraField8;
    char * ExtraField9;

    // internal vars
    char selectID[255];
};

APIVars g_APIVars;

/*
    MoveNext API Callback Functions
*/

/*
This callback indicates the current size of the game list.
*/
int __stdcall GetListSize( void *, int, void *[])
{
    return (ServerBrowser::GetGameList())->GetIndexedView()->GetCount();
}


/*
    This callback instructs the internal game list to sort itself according
    to the column specified.  If sortAscending is non-zero, then the list
    will be sorted in descending order.  Otherwise, the list will be sorted
    in ascending order.
*/
int __stdcall SortGameList( void * instance, int args, void * arg[])
{
    if ( args != 3)
    {
        PAUSE(( "Invalid number of arguments (%d) to SortGameList().", args ));
        return 0;
    }

    const char * column = (char *) arg[0];
    const char * sortType = (char *)arg[1];
    const int sortOrder =  (int)(arg[2]); // literals aren't pointers

    Browse::IndexedTableView::SortOrderType sortEnum;

    // parse sort order
    if ( !strcmp(sortType, "numeric") )
    {
        if ( sortOrder )
        {
            sortEnum = Browse::IndexedTableView::DESCENDING_NUMERIC;
        }
        else
        {
            sortEnum = Browse::IndexedTableView::ASCENDING_NUMERIC;
        }
    }
    else
    {
        if ( sortOrder )
        {
            sortEnum = Browse::IndexedTableView::DESCENDING_ALPHABETICAL;
        }
        else
        {
            sortEnum = Browse::IndexedTableView::ASCENDING_ALPHABETICAL;
        }
    }

    return (int) ServerBrowser::GetGameList()->GetIndexedView()->Sort(column, sortEnum);
}

/*
    This callback selects the row at the specified index.  
    The selection serves as a reference point for the client application when
    the server list is updated (through sorting or new server updates, for example).
    See GetSelection() below.
*/
int __stdcall Select( void * instance, int args, void * arg[])
{
    if ( args != 1 )
    {
        PAUSE(( "Invalid number of arguments (%d) to Select().", args ));
        return 0;
    }

    int selIndex = *(int *)(arg[0]);

    ServerBrowser::GetGameList()->Lock();
    Browse::IndexedTableView * indexView = ServerBrowser::GetGameList()->GetIndexedView();
    gosASSERT(indexView);


    if ( selIndex < 0 || selIndex >= indexView->GetCount() )
    {
        PAUSE(( "Invalid select index %d, should be >= 0 and <= %d", selIndex, indexView->GetCount() ));
        goto CLEANUP;
    }

    char * gameID;

    if ( indexView->GetIndex( selIndex, &gameID ) == false )
    {
        PAUSE(( "Unable to find gameID for select index %d.", selIndex ));
        goto CLEANUP;
    }

    strcpy(g_APIVars.selectID, gameID);

CLEANUP:
    ServerBrowser::GetGameList()->Unlock();
    return 1;
}

/*
    This callback returns an integer indicating the index of the currently
    selected row.  This callback can be used to keep a specific game server
    in the client's view visible after a call to UpdateGUNGameList() or
    SortGameList().  By calling Select() and specifying the game server you
    want to keep track of, you can later call GetSelection() to obtain the
    current index of that game server in the list.
*/
int __stdcall GetSelection( void *, int, void *arg[])
{
    int index = ServerBrowser::GetGameList()->GetIndexedView()->GetIndexFromID( g_APIVars.selectID );
    return index;
}


/*
    This callback provides information about the game server located at
    the specified index.  The callback sets the following script
    variables, which represent the standard GUN server info fields:

        $$ProductName$$
        $$ModName$$
        $$GameVersion$$
        $$Instance$$
        $$ServerAddress$$
        $$ServerPort$$
        $$ServerName$$
        $$NumPlayers$$
        $$MaxPlayers$$
        $$PasswordStatus$$
        $$MapType$$
        $$ExtraField0$$
        $$ExtraField1$$
        $$ExtraField2$$
        $$ExtraField3$$
        $$ExtraField4$$
        $$ExtraField5$$
        $$ExtraField6$$
        $$ExtraField7$$
        $$ExtraField8$$
        $$ExtraField9$$
*/

int __stdcall GetGameData( void * instance, int nargs, void * args[16] )
{
    if ( nargs != 1 )
    {
        PAUSE(( "Invalid number of arguments (%d) to GetGameData callback.", args ));
        return 0;
    }

    ServerBrowser::GetGameList()->Lock();

    int index = *((int *) args[0]);

    char * gameID;
    if ( ServerBrowser::GetGameList()->GetIndexedView()->GetIndex(index, &gameID) == false )
    {
        ServerBrowser::GetGameList()->Unlock();
        return 0;
    }

    g_APIVars.ProductName		= (char *)ServerBrowser::GetGameList()->GetDataField( gameID, GAMELIST_KEY_PRODUCT_NAME);
    g_APIVars.ModName			= (char *)ServerBrowser::GetGameList()->GetDataField( gameID, GAMELIST_KEY_MOD_NAME);
    g_APIVars.GameVersion		= (char *)ServerBrowser::GetGameList()->GetDataField( gameID, GAMELIST_KEY_PRODUCT_VERSION);
    g_APIVars.Instance			= (char *)ServerBrowser::GetGameList()->GetDataField( gameID, GAMELIST_KEY_INSTANCE);
    g_APIVars.ServerAddress		= (char *)ServerBrowser::GetGameList()->GetDataField( gameID, GAMELIST_KEY_SERVER_ADDRESS);
    g_APIVars.ServerPort		= (char *)ServerBrowser::GetGameList()->GetDataField( gameID, GAMELIST_KEY_SERVER_PORT);
    g_APIVars.ServerName		= (char *)ServerBrowser::GetGameList()->GetDataField( gameID, GAMELIST_KEY_SERVER_NAME);
    g_APIVars.NumPlayers		= (char *)ServerBrowser::GetGameList()->GetDataField( gameID, GAMELIST_KEY_NUM_PLAYERS);
    g_APIVars.MaxPlayers		= (char *)ServerBrowser::GetGameList()->GetDataField( gameID, GAMELIST_KEY_MAX_PLAYERS);
    g_APIVars.PasswordStatus	= (char *)ServerBrowser::GetGameList()->GetDataField( gameID, GAMELIST_KEY_PASSWORD_PROTECTED);
    g_APIVars.MapType			= (char *)ServerBrowser::GetGameList()->GetDataField( gameID, GAMELIST_KEY_MAP_TYPE);

	RESET_NULL_TO_EMPTY(g_APIVars.ProductName);
	RESET_NULL_TO_EMPTY(g_APIVars.ModName);
	RESET_NULL_TO_EMPTY(g_APIVars.GameVersion);
	RESET_NULL_TO_EMPTY(g_APIVars.Instance);
	RESET_NULL_TO_EMPTY(g_APIVars.ServerAddress);
	RESET_NULL_TO_EMPTY(g_APIVars.ServerPort);
	RESET_NULL_TO_EMPTY(g_APIVars.ServerName);
	RESET_NULL_TO_EMPTY(g_APIVars.NumPlayers);
	RESET_NULL_TO_EMPTY(g_APIVars.MaxPlayers);
	RESET_NULL_TO_EMPTY(g_APIVars.PasswordStatus);
	RESET_NULL_TO_EMPTY(g_APIVars.MapType);

    // tbd - set the extra fields
    ServerBrowser::GetGameList()->Unlock();
    return 1;
}


/*
    Start the ping server.  This should only be invoked by the game when
    it is hosting.
*/
int _stdcall StartPingServer( void * instance, int nargs, void * args[] )
{
    if ( ServerBrowser::GetGameList() )
    {
        return ServerBrowser::GetGameList()->StartPingServer();
    }
    return -1;
}

/*
    Start the ping client.  This will start pinging any games that are
    in g_GameList.
*/
int _stdcall StartPingClient( void * instance, int nargs, void * args[] )
{
    if ( ServerBrowser::GetGameList() )
    {
        return ServerBrowser::GetGameList()->StartPingClient( 10 );
    }
    return -1;
}

/*
    Shutdown the ping service.  THis should be called when joining a game.
    THis should also be called to shutdown client pinging before calling
    StartPingServer() when hosting a game.
*/
int _stdcall ShutdownPing( void * instance, int nargs, void * args[] )
{
    if ( ServerBrowser::GetGameList() )
    {
        ServerBrowser::GetGameList()->ShutdownPing();
    }
    return 1;
}

/*
    returns the ping time of the game server at the indicated index.
*/
int _stdcall GetPing( void * instance, int nargs, void * args[] )
{
    if ( nargs != 1 )
    {
        return -1;
    }

    if ( !ServerBrowser::GetGameList() )
    {
        return -1;
    }

    int index = *((int *) args[0]);

    if ( index > ServerBrowser::GetGameList()->GetIndexedView()->GetCount() )
    {
        index = (unsigned int) atoi( (char *) args[0] );
        if ( index > ServerBrowser::GetGameList()->GetIndexedView()->GetCount() )
        {
            return -1;
        }
    }

    return ServerBrowser::GetGameList()->GetPing(index);
}

//
// Update the list of players
//
int _stdcall UpdatePlayerList(void *, int, void *[])
{
	NumberOfPlayers=(DWORD)gos_NetInformation( gos_NumberOfPlayersInGame, 0, GameName );
	
	if( NumberOfPlayers>19 )
		NumberOfPlayers=19;
	
	for( int t0=0; t0<NumberOfPlayers; t0++ )
	{
		strncpy( ListOfPlayers[t0], (char*)gos_NetInformation( gos_NameOfPlayersInGame, t0, GameName ), 127 );
	}

	return 1;
}

//========================================================================
//========================================================================
int _stdcall UpdateGUNPlayerList(void *, int, void *[])
{
    if ( ServerBrowser::GetGameList() == NULL )
    {
        return 0;
    }

    Browse::GameList::Lock(); // enter crit section
    int i;
    NumberOfPlayers = 0;
    const char * gameID;
    Browse::PlayerList * pList = 0;
    int count = 0;
    Browse::IndexedTableView * indexView = 0;


    if ( !GameName ) goto CLEANUP;

	if (ServerBrowser::GetGameList()==NULL)
		return 0;

    gameID = ServerBrowser::GetGameList()->GetIDFromField( GAMELIST_KEY_SERVER_NAME, GameName );
    if ( !gameID )
    {
        // not able to find the game named in GameName variable
        goto CLEANUP;
    }

    pList = ServerBrowser::GetGameList()->GetPlayerList( gameID );
    indexView = pList->GetIndexedView();

    for (i = 0; i < indexView->GetCount(); i++)
    {
        char * playerID;

        if ( indexView->GetIndex( i, &playerID ) == false )
        {
            PAUSE(( "Unable to find playerID for index %d", i ));
            continue;
        }

        const char * playerName = pList->GetDataField(playerID, PLAYERLIST_KEY_PLAYER_NAME );
        if ( playerName )
        {
            strncpy(ListOfPlayers[count], playerName, 19);
            ListOfPlayers[count][19] = 0;
            count++;
        }
        if (count >= 18)
        {
            break;
        }
    }

    NumberOfPlayers = count;

CLEANUP:
    Browse::GameList::Unlock(); // leave critical section

    return 0;

}


//========================================================================
// Update the list of GUN games.  This should only be called by
// the GUNTech scripts, LAN scripts should invoke UpdateGameList.
//========================================================================
int _stdcall UpdateGUNGameList(void *, int, void *[])
{
	if (ServerBrowser::GetGameList() == NULL)
		return 0;

    Browse::GameList::Lock();  // enter crit section

    Browse::IndexedTableView * indexView = ServerBrowser::GetGameList()->GetIndexedView();
    gosASSERT(indexView);
    int count;

    for ( count = 0; count < indexView->GetCount(); count++ )
    {
        char * gameID;
        if ( indexView->GetIndex(count, &gameID) == false )
        {
            PAUSE(( "Unable to get gamelist id at index %d", count ));
            continue;
        }

        // fill in game name array entry
        const char * gameName = ServerBrowser::GetGameList()->GetDataField(gameID,
            GAMELIST_KEY_SERVER_NAME);
        if ( !gameName )
        {
            // server without full data -- skip it for now
            continue;
        }

        strncpy( ListOfGameNames[count], gameName, 19 );
        ListOfGameNames[19] = 0;

        // fill in ListOfDescriptions entry
        // mdm - todo

        // fill in num players list
        const char * activePlayers = ServerBrowser::GetGameList()->GetDataField(
            gameID, GAMELIST_KEY_NUM_PLAYERS );
        const char * maxPlayers = ServerBrowser::GetGameList()->GetDataField(
            gameID, GAMELIST_KEY_MAX_PLAYERS );

        char buffer[32];

        sprintf( buffer, "%s/%s", activePlayers ? activePlayers : "?",
            maxPlayers ? maxPlayers : "?");

        strncpy( ListOfNumPlayers[count], buffer, 19 );
        ListOfNumPlayers[count][19] = 0;

        // fill in passworded array
        const char * passworded = ServerBrowser::GetGameList()->GetDataField(
            gameID, GAMELIST_KEY_PASSWORD );
        if ( passworded && !stricmp(passworded, "yes") )
        {
            sprintf(ListOfPassworded[count], "X");
        }
        else
        {
            ListOfPassworded[count][0] = ' ';
            ListOfPassworded[count][1] = 0;
        }

        // MDM - THESE NEED TO BE PROPERLY FILLED IN LATER
        ListOfDescriptions[count][0] = 0;
        ListOfLocked[count][0] = 0;
        ListOfSecure[count][0] = 0;

        // prepare for next iteration
        if ( count >= 18 )
        {
            // don't display more than the first 19
            break;
        }
    }

    NumberOfGames = ServerBrowser::GetGameList()->GetIndexedView()->GetCount();
    Browse::GameList::Unlock(); // leave crit. section

	return 1;

/*     MDM --- THESE FIELDS ARE NOT YET DONE!

		ListOfDescriptions[t0][0]=0;
		if( Environment.DecodeGameInfo )
		{
			strncpy( ListOfDescriptions[t0], Environment.DecodeGameInfo((char*)gos_NetInformation( gos_InformationAboutGame, 0, (char*)gos_NetInformation( gos_NameOfGame, t0 ) )), 19 );
			ListOfDescriptions[t0][19]=0;
		}
//
// Locked?
//
		Buffer[0]=(gos_NetInformation( gos_IsGameLocked, 0, (char*)gos_NetInformation( gos_NameOfGame, t0 ) ) ? 'X' : ' ' );
		strncpy( ListOfLocked[t0], Buffer, 20 );
//
// Secure?
//
		Buffer[0]=(gos_NetInformation( gos_IsGameSecure, 0, (char*)gos_NetInformation( gos_NameOfGame, t0 ) ) ? 'X' : ' ' );
		strncpy( ListOfSecure[t0], Buffer, 20 );
	}
*/
}




//
// Update the list of games - if GunTech don't use this, use
// UpdateGUNGameList instead.
//
int _stdcall UpdateGameList(void *, int, void *[])
{
	NumberOfGames=(DWORD)gos_NetInformation( gos_NumberOfGames );
	
	if( NumberOfGames>19 )
		NumberOfGames=19;

	for( int t0=0; t0<NumberOfGames; t0++ )
	{
//
// Get the name of the game
//n
		strncpy( ListOfGameNames[t0], (char*)gos_NetInformation( gos_NameOfGame, t0 ), 19 );
		ListOfGameNames[t0][19]=0;
//
// Get the game specific data and decode it
//
		ListOfDescriptions[t0][0]=0;
		if( Environment.DecodeGameInfo )
		{
			strncpy( ListOfDescriptions[t0], Environment.DecodeGameInfo((char*)gos_NetInformation( gos_InformationAboutGame, 0, (char*)gos_NetInformation( gos_NameOfGame, t0 ) )), 19 );
			ListOfDescriptions[t0][19]=0;
		}
//
// Get the number of players and the maximum number of players
//
		char Buffer[32];
		if( gos_NetInformation( gos_IsGameSecure, 0, (char*)gos_NetInformation(gos_NameOfGame, t0) ))
		{
			ListOfNumPlayers[t0][0]=0;
		}
		else
		{
			if( gos_NetInformation( gos_IsGamePassworded, 0, (char*)gos_NetInformation(gos_NameOfGame, t0) ) )
			{
				sprintf( Buffer, "?/%d", (DWORD)gos_NetInformation( gos_MaxPlayersInGame, 0, (char*)gos_NetInformation( gos_NameOfGame )));
				strncpy( ListOfNumPlayers[t0], Buffer, 20 );
			}
			else
			{
				sprintf( Buffer, "%d/%d", (DWORD)gos_NetInformation( gos_NumberOfPlayersInGame, 0, (char*)gos_NetInformation( gos_NameOfGame, t0 )), (DWORD)gos_NetInformation( gos_MaxPlayersInGame, 0, (char*)gos_NetInformation( gos_NameOfGame )));
				strncpy( ListOfNumPlayers[t0], Buffer, 20 );
			}
		}
//
// Passworded?
//
		Buffer[1]=0;
		Buffer[0]=(gos_NetInformation( gos_IsGamePassworded, 0, (char*)gos_NetInformation( gos_NameOfGame, t0 ) ) ? 'X' : ' ' );
        strncpy( ListOfPassworded[t0], Buffer, 20 );
//
// Locked?
//
		Buffer[0]=(gos_NetInformation( gos_IsGameLocked, 0, (char*)gos_NetInformation( gos_NameOfGame, t0 ) ) ? 'X' : ' ' );
		strncpy( ListOfLocked[t0], Buffer, 20 );
//
// Secure?
//
		Buffer[0]=(gos_NetInformation( gos_IsGameSecure, 0, (char*)gos_NetInformation( gos_NameOfGame, t0 ) ) ? 'X' : ' ' );
		strncpy( ListOfSecure[t0], Buffer, 20 );
	}

	return 1;
}




//
// Update the list of modems
//
int _stdcall UpdateModemList(void *, int, void *[])
{
	NumberOfModems=(DWORD)gos_NetInformation( gos_NumberOfModems );
	
	if( NumberOfModems>19 )
		NumberOfModems=19;
	
	for( UINT t0=0; t0<NumberOfModems; t0++ )
	{
		strncpy( ListOfModems[t0], (char*)gos_NetInformation( gos_NameOfModem, t0 ), 127 );
	}

	return 1;
}


//
// Update the list of serial ports
//
int _stdcall UpdateSerialPortList(void *, int, void *[])
{
	NumberOfSerialPorts=(DWORD)gos_NetInformation( gos_NumberOfSerialPorts );
	
	if( NumberOfSerialPorts>19 )
		NumberOfSerialPorts=19;
	
	for( UINT t0=0; t0<NumberOfSerialPorts; t0++ )
	{
		strncpy( ListOfSerialPorts[t0], (char*)gos_NetInformation( gos_NameOfSerialPort, t0 ), 127 );
	}

	return 1;
}







//
// Create a game.
//
// 0=OK
// 1=Bad game name
// 2=Bad player name
// 3=Failed
// 4=Waiting for answer
//
int _stdcall CreateSession(void *, int, void *[])
{
	return gos_CreateGame( GameName, PlayerName, Environment.NetworkMaxPlayers, Password, gInSecureGame!=0,NGPassword);
}

//
// Join a game (On a serial or modem game, enumerate the current game and join that)
//
// 0=OK
// 1=Bad game name (or waiting for game on modem/serial)
// 2=Bad player name
// 3=Failed to connect
// 4=No dial tone
// 5=Invalid password
// 6=Too many players in the game
//
int _stdcall JoinSelected(void *, int, void *[])
{
    return gos_JoinGame( GameName, PlayerName, Password,NGPassword);
}












//
// Wait for a call, then create a game
//
int _stdcall HostModemGame(void *, int, void *[])
{
	//int hr=gos_ConnectModem( 0, CurrentModem );
	//if( !hr )
	//	return 1;
	return gos_CreateGame( GameName, PlayerName, Environment.NetworkMaxPlayers, Password, gInSecureGame!=0 );
}



//
// Dial a number and look for a game to join 
//
int _stdcall JoinModemGame(void *, int, void *[])
{
	//int hr=gos_ConnectModem( PhoneNumber, CurrentModem );
	//if( !hr )
	//	return 1;
	return gos_JoinGame( GameName, PlayerName, Password );
}



//
// Hang up the line or disconnect a network game
//
int _stdcall Disconnect(void *, int, void *[])
{
    if ( ServerBrowser::GetGameList() )
    {
    	ServerBrowser::GetGameList()->ShutdownPing();
    }
	ServerBrowser::ReleaseAll();
	ServerAdvertiser::ReleaseAll();
 	gos_Disconnect();
	return true;
}

//
// Open a TCPIP connection
//
int _stdcall ConnectTCP(void *, int, void *[])
{
    InitTCPIPServerBrowser(ServerIPAddress);
	Available=1;
	return 1;
}


//
// Open a TCPIP and ZoneMatch connection
//
int _stdcall ConnectZoneMatch(void *, int, void *[])
{
    InitGUNServerBrowser();
    InitGUNServerAdvertiser();

    return 1;
}

//
// Open an IPX connection
//
int _stdcall ConnectIPX(void *, int, void *[])
{
    InitIPXServerBrowser();
	//Available=gos_ConnectIPX();
	return 1;
}


//
// Open an Serial Port connection
//
int _stdcall ConnectSerialPort(void *, int, void *[])
{
	//Available=gos_ConnectSerialPort( CurrentSerialPort );
	return 1;
}





//
// Check to see if a protocol is available
//
// NP_TCP		1
// NP_IPX		2
// NP_SERIAL	3
// NP_MODEM		4
//
int _stdcall IsConnectionAvailable(void *, int, void *[])
{
	Available=gos_CheckConnectionAvailable( CheckThisConnection );
	return  1;
}





//
// Remove all script variables
//
void UnRegisterData()
{
	gosScript_UnregisterAll( NetworkInstance );

	if (PlayerName)
	{
		gos_Free(PlayerName);
		PlayerName=0;
	}
	if (ServerIPAddress)
	{
		gos_Free(ServerIPAddress);
		ServerIPAddress=0;
	}
    if (ZoneServerAddress)
    {
        gos_Free(ZoneServerAddress);
        ZoneServerAddress = 0;
    }
	if (PhoneNumber)
	{
		gos_Free(PhoneNumber);
		PhoneNumber=0;
	}
	if( GameName )
	{
		gos_Free(GameName);
		GameName=0;
	}
	if( Password )
	{
		gos_Free(Password);
		Password=0;
	}
    if ( NGPassword )
    {
        gos_Free(NGPassword);
        NGPassword = NULL;
    }

	for( int i=0; i < 20; i++)
	{
		gos_Free(ListOfGameNames[i]);
		gos_Free(ListOfDescriptions[i]);
		gos_Free(ListOfNumPlayers[i]);	
		gos_Free(ListOfPassworded[i]);	
		gos_Free(ListOfLocked[i]);
		gos_Free(ListOfSecure[i]);
		gos_Free(ListOfPlayers[i]);
		gos_Free(ListOfModems[i]);;
		gos_Free(ListOfSerialPorts[i]);;
	}

	gos_Free(ListOfGameNames);
	gos_Free(ListOfDescriptions);
	gos_Free(ListOfNumPlayers);	
	gos_Free(ListOfPassworded);	
	gos_Free(ListOfLocked);
	gos_Free(ListOfSecure);
	gos_Free(ListOfPlayers);
	gos_Free(ListOfModems);
	gos_Free(ListOfSerialPorts);

	RegisteredData=0;
}



void __stdcall gos_NetEndGame()
{
	gos_ShutdownNetwork();
	if( RegisteredData )
	{
		UnRegisterData();
	}
}


bool __stdcall gos_NetStartGame( char* GameOptionsScript, bool Secure )
{
	gosASSERT( Environment.NetworkGame && Environment.NetworkMaxPlayers>1 );

	// avoid compiler warning
	GameOptionsScript=GameOptionsScript;

	// store secure state
	gInSecureGame=Secure;

	gos_InitializeNetworking();

	if( GameName )
	{
		gos_Free(GameName);
		GameName=0;
	}
	if( Password )
	{
		gos_Free(Password);
		Password=0;
	}
    if ( NGPassword )
    {
        gos_Free(NGPassword);
        NGPassword = 0;
    }

	PlayerName=0;
	ServerIPAddress=0;

	PhoneNumber=0;
	CurrentModem=0;
	CurrentSerialPort=0;

	ListOfGameNames=(char**) gos_Malloc(20*4);
	ListOfDescriptions=(char**) gos_Malloc(20*4);
	ListOfNumPlayers=(char**) gos_Malloc(20*4);	
	ListOfPassworded=(char**) gos_Malloc(20*4);	
	ListOfLocked=(char**) gos_Malloc(20*4);
	ListOfSecure=(char**) gos_Malloc(20*4);
	ListOfPlayers=(char**) gos_Malloc(20*4);
	ListOfModems=(char**) gos_Malloc(20*4);
	ListOfSerialPorts=(char**) gos_Malloc(20*4);

	for(int i=0; i<20; i++)
	{
		ListOfGameNames[i]=(char*) gos_Malloc(128);
		ListOfDescriptions[i]=(char*) gos_Malloc(20*4);
		ListOfNumPlayers[i]=(char*) gos_Malloc(20*4);	
		ListOfPassworded[i]=(char*) gos_Malloc(20*4);	
		ListOfLocked[i]=(char*) gos_Malloc(20*4);
		ListOfSecure[i]=(char*) gos_Malloc(20*4);
		ListOfPlayers[i]=(char*) gos_Malloc(128);
		ListOfModems[i]=(char*) gos_Malloc(128);
		ListOfSerialPorts[i]=(char*) gos_Malloc(128);
	}
//
// Routines called between UI and GameOS
//
	gosScript_RegisterCallback( "ConnectIPX",			&ConnectIPX,			GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterCallback( "ConnectTCP",			&ConnectTCP,			GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterCallback( "ConnectZoneMatch",		&ConnectZoneMatch,		GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterCallback( "ConnectSerialPort",	&ConnectSerialPort,		GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterCallback( "UpdatePlayerList",		&UpdatePlayerList,		GOSVAR_INT, 0, NetworkInstance );
    gosScript_RegisterCallback( "UpdateGUNPlayerList",  &UpdateGUNPlayerList,   GOSVAR_INT, 0, NetworkInstance );
    gosScript_RegisterCallback( "UpdateGameList",		&UpdateGameList,		GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterCallback( "UpdateGUNGameList",	&UpdateGUNGameList,		GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterCallback( "JoinSelected",			&JoinSelected,			GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterCallback( "HostModemGame",		&HostModemGame,			GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterCallback( "JoinModemGame",		&JoinModemGame,			GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterCallback( "CreateSession",		&CreateSession,			GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterCallback( "UpdateModemList",		&UpdateModemList,		GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterCallback( "UpdateSerialPortList",	&UpdateSerialPortList,	GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterCallback( "Disconnect",			&Disconnect,			GOSVAR_INT, 0, NetworkInstance );
    // gamelist api callbacks
    gosScript_RegisterCallback( "GetGameData",          &GetGameData,           GOSVAR_INT, 0, NetworkInstance );
    gosScript_RegisterCallback( "SortGameList",         &SortGameList,          GOSVAR_INT, 0, NetworkInstance );
    gosScript_RegisterCallback( "Select",               &Select,                GOSVAR_INT, 0, NetworkInstance );
    gosScript_RegisterCallback( "GetSelection",         &GetSelection,          GOSVAR_INT, 0, NetworkInstance );
    gosScript_RegisterCallback( "GetListSize",          &GetListSize,           GOSVAR_INT, 0, NetworkInstance );
    // ping control callbacks
    gosScript_RegisterCallback( "StartPingServer",      &StartPingServer,       GOSVAR_INT, 0, NetworkInstance );
    gosScript_RegisterCallback( "StartPingClient",      &StartPingClient,       GOSVAR_INT, 0, NetworkInstance );
    gosScript_RegisterCallback( "ShutdownPing",         &ShutdownPing,          GOSVAR_INT, 0, NetworkInstance );
    gosScript_RegisterCallback( "GetPing",              &GetPing,               GOSVAR_INT, 0, NetworkInstance );

//
// Integers passed between the UI and GameOS
//
	gosScript_RegisterVariable( "gConnectionType",		&gConnectionType,		GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterVariable( "IsConnectionAvailable",&IsConnectionAvailable,	GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterVariable( "CheckThisConnection",	&CheckThisConnection,	GOSVAR_INT, 0, NetworkInstance );	
	gosScript_RegisterVariable( "NumberOfGames",		&NumberOfGames,			GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterVariable( "NumberOfPlayers",		&NumberOfPlayers,		GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterVariable( "NumberOfModems",		&NumberOfModems,		GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterVariable( "NumberOfSerialPorts",	&NumberOfSerialPorts,	GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterVariable( "Available",			&Available,				GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterVariable( "CurrentModem",			&CurrentModem,			GOSVAR_INT, 0, NetworkInstance );
	gosScript_RegisterVariable( "CurrentSerialPort",	&CurrentSerialPort,		GOSVAR_INT, 0, NetworkInstance );
    gosScript_RegisterVariable( "GUNStatus",            &GUNStatus,             GOSVAR_INT, 0, NetworkInstance );
    // gamelist scripting API int variables
    gosScript_RegisterVariable( "ServerPort",           &g_APIVars.ServerPort,      GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "NumPlayers",           &g_APIVars.NumPlayers,      GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "MaxPlayers",           &g_APIVars.MaxPlayers,      GOSVAR_STRING, 0, NetworkInstance );


//
// Strings
//
	gosScript_RegisterVariable( "GameName",				&GameName,				GOSVAR_STRING, 0, NetworkInstance );
	gosScript_RegisterVariable( "PlayerName",			&PlayerName,			GOSVAR_STRING, 0, NetworkInstance );
	gosScript_RegisterVariable( "ServerIPAddress",		&ServerIPAddress,		GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ZoneServerAddress",    &ZoneServerAddress,     GOSVAR_STRING, 0, NetworkInstance );
	gosScript_RegisterVariable( "PhoneNumber",			&PhoneNumber,			GOSVAR_STRING, 0, NetworkInstance );
	gosScript_RegisterVariable( "Password",				&Password,				GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "NGPassword",           &NGPassword,            GOSVAR_STRING, 0, NetworkInstance );

    // gamelist scripting API string variables
    gosScript_RegisterVariable( "ProductName",          &g_APIVars.ProductName,     GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ModName",              &g_APIVars.ModName,         GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "GameVersion",          &g_APIVars.GameVersion,     GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "Instance",             &g_APIVars.Instance,        GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ServerAddress",        &g_APIVars.ServerAddress,   GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ServerName",           &g_APIVars.ServerName,      GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "PasswordStatus",       &g_APIVars.PasswordStatus,  GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "MapType",              &g_APIVars.MapType,         GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ExtraField0",          &g_APIVars.ExtraField0, GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ExtraField1",          &g_APIVars.ExtraField1, GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ExtraField2",          &g_APIVars.ExtraField2, GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ExtraField3",          &g_APIVars.ExtraField3, GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ExtraField4",          &g_APIVars.ExtraField4, GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ExtraField5",          &g_APIVars.ExtraField5, GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ExtraField6",          &g_APIVars.ExtraField6, GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ExtraField7",          &g_APIVars.ExtraField7, GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ExtraField8",          &g_APIVars.ExtraField8, GOSVAR_STRING, 0, NetworkInstance );
    gosScript_RegisterVariable( "ExtraField9",          &g_APIVars.ExtraField9, GOSVAR_STRING, 0, NetworkInstance );

//
// Arrays of strings
//
	gosScript_RegisterVariable( "ListOfGames",			&ListOfGameNames,			GOSVAR_STRING, 20, NetworkInstance );
	gosScript_RegisterVariable( "ListOfDescriptions",	&ListOfDescriptions,	GOSVAR_STRING, 20, NetworkInstance );
	gosScript_RegisterVariable( "ListOfNumPlayers",		&ListOfNumPlayers,		GOSVAR_STRING, 20, NetworkInstance );
	gosScript_RegisterVariable( "ListOfPassworded",		&ListOfPassworded,		GOSVAR_STRING, 20, NetworkInstance );
	gosScript_RegisterVariable( "ListOfLocked",			&ListOfLocked,			GOSVAR_STRING, 20, NetworkInstance );
	gosScript_RegisterVariable( "ListOfSecure",			&ListOfSecure,			GOSVAR_STRING, 20, NetworkInstance );
	gosScript_RegisterVariable( "ListOfPlayers",		&ListOfPlayers,			GOSVAR_STRING, 20, NetworkInstance );
	gosScript_RegisterVariable( "ListOfModems",			&ListOfModems,			GOSVAR_STRING, 20, NetworkInstance );
	gosScript_RegisterVariable( "ListOfSerialPorts",	&ListOfSerialPorts,		GOSVAR_STRING, 20, NetworkInstance );
	RegisteredData=1;
//
// Run modal script to create/join network game
//
	gosScript_ExecuteScript( "Assets\\Scripts\\Network.script", 0x2000, NetworkInstance );

	UnRegisterData();

	return 	gConnectionType!=-1;
}






bool __stdcall gos_NetDoneStartGame()
{
	UnRegisterData();
	return 1;
}
