#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>

typedef int switch_core_session_t;

char * sofia_printf_uri( switch_core_session_t *session, ... );

typedef enum {
	URI_TAG_TYPE_USERNAME = 1,
	URI_TAG_TYPE_DESTINATION,
	URI_TAG_TYPE_HOST,
	URI_TAG_TYPE_PORT,
	URI_TAG_TYPE_PARAMETER,
	URI_TAG_TYPE_PARAMETER_LIST,
	URI_TAG_TYPE_URIONLY
} uri_tag_type;

#define URI_TAG_USERNAME(x)		URI_TAG_TYPE_USERNAME, (x)
#define URI_TAG_DESTINATION(x)		URI_TAG_TYPE_DESTINATION, (x)
#define URI_TAG_HOST(x)			URI_TAG_TYPE_HOST, (x)
#define URI_TAG_PARAMETER(n, v)		URI_TAG_TYPE_PARAMETER, (n), (v)
#define URI_TAG_PARAMETER_LIST(x)	URI_TAG_TYPE_PARAMETER_LIST, (x)

#define URI_TAG_PORT(x)		URI_TAG_TYPE_PORT, (x)
#define URI_TAG_URI_ONLY(x)	URI_TAG_TYPE_URIONLY, (x)

#define TAG_END 		NULL

#define URI_MAX_PARAMS		10


char * sofia_printf_uri( switch_core_session_t *session, ... )
{
	va_list ap;
	char *username = NULL,
		*destination = NULL,
		*host = NULL,
		*param_str = NULL,
		*uri_str = NULL;
	struct { char *name, *val; } param[URI_MAX_PARAMS];
	int tag, port = 0, uri_only = 0, num_params = 0, len_params = 0;

	va_start( ap, session );
	while( 1 ) {
		tag = va_arg( ap, int );
		if( !tag )
			break;

		switch( tag ) {
		case URI_TAG_TYPE_USERNAME:
			username = va_arg( ap, char * );
			break;

		case URI_TAG_TYPE_DESTINATION:
			destination = va_arg( ap, char * );
			break;

		case URI_TAG_TYPE_HOST:
			host = va_arg( ap, char * );
			break;

		case URI_TAG_TYPE_PARAMETER:
			param[num_params].name = va_arg( ap, char * );
			param[num_params].val  = va_arg( ap, char * );
			len_params += strlen(param[num_params].name) + strlen(param[num_params].val);
			num_params++;
			break;

		case URI_TAG_TYPE_PARAMETER_LIST:
			param_str = va_arg( ap, char * );
			num_params = -1;
			break;

		case URI_TAG_TYPE_PORT:
			port = va_arg( ap, int );
			break;

		case URI_TAG_TYPE_URIONLY:
			uri_only = va_arg( ap, int );
			break;

		default:
			printf( "Unknown tag type\n" );
		}
	}
	va_end( ap );

	/*
	 * We need at least host and destination here
	 */
	if( !host ) {
		printf( "no host tag specified\n" );
		return NULL;
	}

	if( !destination ) {
		printf( "no destination tag specified\n" );
		return NULL;
	}

	/*
	 * Default value
	 */
	if( !username )
		username = "user";

	/*
	 * Ugly code ahead...
	 * Now if we'd manually allocate memory here we could count string lengths
	 * and reserve enough room for the uri incl. parameters in one go and
	 * put the params in after snprint'ing the first part...
	 * (saving us the trouble of using alloca here)
	 */
	if( num_params > 0 ) {
		int n, len;
		char *p;

		param_str = alloca( len_params + num_params );
		if( !param_str )
			return NULL;

		p = param_str;

		for( n=0; n < num_params; n++ ) {
			len = strlen( param[n].name );

			memcpy( p, param[n].name, len );
			p += len;

			*p++ = '=';

			len = strlen( param[n].val );

			memcpy( p, param[n].val, len );
			p += len;

			if( n < num_params - 1 )
				*p++ = '&';
		}
		*p = '\0';

	} else if( num_params == 0 ) {
		param_str = "";
	}

	/*
	 * The (fugly) output part
	 */
	if( !uri_only ) {
		if( port ) {
			printf( "\"%s\" <sip:%s@%s:%d>%s%s\n",
				username,
				destination,
				host,
				port,
				num_params ? ";" : "",
				param_str );
		} else {
			printf( "\"%s\" <sip:%s@%s>%s%s\n",
				username,
				destination,
				host,
				num_params ? ";" : "",
				param_str );
		}
	} else {
		if( port ) {
			printf( "sip:%s@%s:%d%s%s\n",
				destination,
				host,
				port,
				num_params ? ";" : "",
				param_str );
		} else {
			printf( "sip:%s@%s%s%s\n",
				destination,
				host,
				num_params ? ";" : "",
				param_str );
		}
	}
	return uri_str;
}


int main( void )
{
	switch_core_session_t session;

	printf( "\nCreating full uri...\n" );
	sofia_printf_uri( &session,
				URI_TAG_USERNAME( "foobar" ),
				URI_TAG_HOST( "konata" ),
				URI_TAG_PORT( 1234 ),
				URI_TAG_DESTINATION( "myext" ),
				URI_TAG_PARAMETER( "transport", "tls" ),
				URI_TAG_PARAMETER( "rport", "12345" ),
				TAG_END );


	printf( "\nCreating uri only (output w/o username)...\n" );
	sofia_printf_uri( &session,
				URI_TAG_USERNAME( "foobar" ),
				URI_TAG_HOST( "konata" ),
				URI_TAG_PORT( 1234 ),
				URI_TAG_DESTINATION( "myext" ),
				URI_TAG_URI_ONLY( 1 ),
				URI_TAG_PARAMETER( "transport", "tls" ),
				TAG_END );


	printf( "\nCreating full uri w/o port...\n" );
	sofia_printf_uri( &session,
				URI_TAG_USERNAME( "foobar" ),
				URI_TAG_HOST( "konata" ),
				URI_TAG_DESTINATION( "myext" ),
				URI_TAG_PARAMETER_LIST( "transport=tls;bla=foo" ),
				TAG_END );

	return 0;
}

