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

typedef int switch_core_session_t;

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

typedef enum {
	URI_TAG_USERNAME,
	URI_TAG_DESTINATION,
	URI_TAG_HOST,
	URI_TAG_PORT,
	URI_TAG_PARAMETERS,
	URI_TAG_URIONLY
} uri_tag_type;

/*
 * union?
 */
struct uri_generic_tag {
	uri_tag_type type;
};

struct uri_string_tag {
	uri_tag_type type;
	char *val;
};

struct uri_int_tag {
	uri_tag_type type;
	int val;
};


/*
 * Tag helper macros
 */
#define TAG_GENERIC_FLAG(typeval)	({ struct uri_generic_tag __uri_gen_##__LINE__ = { .type = typeval }; &__uri_gen_##__LINE__; })
#define TAG_GENERIC_STRING(typeval, x)	({ struct uri_string_tag __uri_str_##__LINE__ = { .type = typeval, .val = x }; &__uri_str_##__LINE__; })
#define TAG_GENERIC_INT(typeval, x)	({ struct uri_int_tag __uri_int_##__LINE__ = { .type = typeval, .val = x }; &__uri_int_##__LINE__; })

/*
 * Actual tags
 */
#define TAG_USERNAME(x)		TAG_GENERIC_STRING(URI_TAG_USERNAME, x)
#define TAG_DESTINATION(x)	TAG_GENERIC_STRING(URI_TAG_DESTINATION, x)
#define TAG_HOST(x)		TAG_GENERIC_STRING(URI_TAG_HOST, x)
#define TAG_PARAMETERS(x)	TAG_GENERIC_STRING(URI_TAG_PARAMETERS, x)

#define TAG_PORT(x)		TAG_GENERIC_INT(URI_TAG_PORT, x)
#define TAG_URI_ONLY(x)		TAG_GENERIC_INT(URI_TAG_URIONLY, x)

#define TAG_END 		NULL

char * sofia_printf_uri( switch_core_session_t *session, ... )
{
	struct uri_generic_tag *tag;
	va_list ap;
	char *username = NULL,
		*destination = NULL,
		*host = NULL,
		*params = NULL,
		*uri_str = NULL;
	int port = 0, uri_only = 0;

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

		switch( tag->type ) {
		case URI_TAG_USERNAME:
			username = ((struct uri_string_tag *)tag)->val;
			break;

		case URI_TAG_DESTINATION:
			destination = ((struct uri_string_tag *)tag)->val;
			break;

		case URI_TAG_HOST:
			host = ((struct uri_string_tag *)tag)->val;
			break;

		case URI_TAG_PARAMETERS:
			params = ((struct uri_string_tag *)tag)->val;
			break;

		case URI_TAG_PORT:
			port = ((struct uri_int_tag *)tag)->val;
			break;

		case URI_TAG_URIONLY:
			uri_only = ((struct uri_int_tag *)tag)->val;
			break;

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

	/*
	 * We need at least host and destination here
	 */
	if( !host )
		return NULL;

	if( !destination )
		return NULL;

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


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


int main( void )
{
	switch_core_session_t session;

	printf( "\nCreating full uri...\n" );
	sofia_printf_uri( &session,
				TAG_USERNAME( "foobar" ),
				TAG_HOST( "konata" ),
				TAG_PORT( 1234 ),
				TAG_DESTINATION( "myext" ),
				TAG_END );


	printf( "\nCreating uri only (output w/o username)...\n" );
	sofia_printf_uri( &session,
				TAG_USERNAME( "foobar" ),
				TAG_HOST( "konata" ),
				TAG_PORT( 1234 ),
				TAG_DESTINATION( "myext" ),
				TAG_URI_ONLY( 1 ),
				TAG_END );


	printf( "\nCreating full uri w/o port...\n" );
	sofia_printf_uri( &session,
				TAG_USERNAME( "foobar" ),
				TAG_HOST( "konata" ),
				TAG_DESTINATION( "myext" ),
				TAG_END );

	return 0;
}

