/*
 *  network_lookup_sdl.cpp - Network entity lookup functions, SDL implementation

	Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
	and the "Aleph One" developers.
 
	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 3 of the License, or
	(at your option) any later version.

	This program 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 General Public License for more details.

	This license is contained in the file "COPYING",
	which is included with this source code; it is available online at
	http://www.gnu.org/licenses/gpl.html

*/
/*
 *  network_lookup_sdl.cpp - Network entity lookup functions, SDL implementation
 *
 *  Created in 2000 by Christian Bauer (skeletal)
 *
 *  Actual code (SSLP-based) written in September 2001 by Woody Zenfell, III.
 *
 */

#if !defined(DISABLE_NETWORKING)

#ifdef __MWERKS__
#include 	<stdlib.h>
#include 	<extras.h>
#endif

#include 	"cseries.h"
#include 	"sdl_network.h"

#include	"SSLP_API.h"

// ZZZ: Note: I have taken some pains to make sure lookup and name registration accept P-strings, and do the right thing
// (i.e. make a 'hybrid string') so the C-style SSLP code works.  I hope this makes it easier to port this code back into
// the MacOS "classic" version, should somebody want to do that.  (Would want to implement NetLookupOpen with the Mac-style
// interface, and manage lists etc.  Code to do that sort of thing in SDL version is inside the found_players widget.)


// FILE-LOCAL TYPES


// FILE-LOCAL STORAGE
static	bool	sNameRegistered		= false;
static	bool	sLookupInProgress	= false;


// Helper function: make the "\p%s%d", type, version string C-string compatible and truncate it to fit
static void
NetLookup_BuildTypeString(char* outDest, const unsigned char* inType, short inVersion) {
    char theLength = inType[0];
    
    // Make Pstring Cstring-compatible - we truncate to SSLP_MAX_TYPE_LENGTH - 8 string length.
    if(theLength > SSLP_MAX_TYPE_LENGTH - 8)
        theLength = SSLP_MAX_TYPE_LENGTH - 8;
    
    // This leaves room for length byte, terminating null, and longest 'short' string (-32768).

    // Length byte will be written last
    
    // Type string characters (this is the part that gets truncated if necessary)
    memcpy(&outDest[1], &inType[1], theLength);
    
    // Version as string
    sprintf(&outDest[theLength + 1], "%hd", inVersion);

    // sprintf null-terminates the string for us.

	// OK, now that we know the correct length, go back and write it
	outDest[0] = strlen(&outDest[1]);
}


/*
 *  Start lookup
 */

OSErr NetLookupOpen_SSLP(const unsigned char *type, short version,
        SSLP_Service_Instance_Status_Changed_Callback foundInstance,
        SSLP_Service_Instance_Status_Changed_Callback lostInstance,
        SSLP_Service_Instance_Status_Changed_Callback nameChanged)
{
//    fdprintf("NetLookupOpen_SSLP %d\n", version);

    char theType[SSLP_MAX_TYPE_LENGTH];

    NetLookup_BuildTypeString(theType, type, version);

    // Want to hear about service instances.
    SSLP_Locate_Service_Instances(theType, foundInstance, lostInstance, nameChanged);
    
    sLookupInProgress = true;
    
    return 0;
}


/*
 *  Stop lookup
 */

void NetLookupClose(void)
{
//    fdprintf("NetLookupClose\n");

    if(sLookupInProgress) {
        // No longer interested in hearing about service instances.
        SSLP_Stop_Locating_Service_Instances(NULL);
        
        sLookupInProgress = false;
    }
}


/*
 *  Remove entity from name list
 */

void NetLookupRemove(short index)
{
//    fdprintf("NetLookupRemove %d\n", index);
}


/*
 *  Get information for entity
 */

void NetLookupInformation(short index, NetAddrBlock *address, NetEntityName *entity)
{
//    fdprintf("NetLookupInformation %d\n", index);
}


/*
 *  Update entity list
 */

void NetLookupUpdate(void)
{
//    fdprintf("NetLookupUpdate\n");
}


/*
 *  Register entity
 */

OSErr NetRegisterName(const unsigned char *name, const unsigned char *type, short version, short socketNumber,
					  const char* hint_addr_string)
{
//    fdprintf("NetRegisterName %d, %d\n", version, socketNumber);

	OSErr theError = noErr;

    // Construct a service-instance for the player
    struct SSLP_ServiceInstance	thePlayer;

    NetLookup_BuildTypeString(thePlayer.sslps_type, type, version);

    // Truncate and copy Pstring name; add a terminating null for C-friendliness.
    unsigned char theLength = name[0];
    if(theLength > SSLP_MAX_NAME_LENGTH - 2)
        theLength = SSLP_MAX_NAME_LENGTH - 2;
    
    thePlayer.sslps_name[0] = theLength;
    memcpy(&thePlayer.sslps_name[1], &name[1], theLength);
    thePlayer.sslps_name[theLength + 1] = '\0';

    thePlayer.sslps_address.host = 0;
    thePlayer.sslps_address.port = socketNumber;
    
    // Publish it
    SSLP_Allow_Service_Discovery(&thePlayer);
    
    sNameRegistered = true;

	// If we're supposed to hint, resolve the address string and start hinting.
	if(hint_addr_string != NULL) {
		IPaddress	theAddress;

		// SDL_net declares ResolveAddress without "const" on the char; we can't guarantee
		// our caller that it will remain const unless we protect it like this.
		char*		theStringCopy = strdup(hint_addr_string);

		theError = SDLNet_ResolveHost(&theAddress, theStringCopy, 0);
		if(theError == 0) {
			SSLP_Hint_Service_Discovery(&thePlayer, &theAddress);
		}

		free(theStringCopy);
	}
    
    return theError;
}


/*
 *  Unregister entity
 */

OSErr NetUnRegisterName(void)
{
//    fdprintf("NetUnRegisterName\n");

    if(sNameRegistered) {
        // Stop publishing player name (we can get away with NULL, meaning "all", since we only publish one at a time)
        SSLP_Disallow_Service_Discovery(NULL);
    
        sNameRegistered = false;
    }

    return 0;
}

#endif // !defined(DISABLE_NETWORKING)
