#import "PGConnection.h"

#import "PGConnectionFailedException.h"
#import "PGCommandFailedException.h"

@implementation PGConnection
- (void)dealloc
{
	[parameters release];

	if (conn != NULL)
		PQfinish(conn);

	[super dealloc];
}

- (void)setParameters: (OFDictionary*)parameters_
{
	OF_SETTER(parameters, parameters_, YES, YES)
}

- (OFDictionary*)parameters
{
	OF_GETTER(parameters, YES)
}

- (void)connect
{
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFEnumerator *keyEnumerator = [parameters keyEnumerator];
	OFEnumerator *objectEnumerator = [parameters objectEnumerator];
	OFMutableString *conninfo = nil;
	OFString *key, *object;

	while ((key = [keyEnumerator nextObject]) != nil &&
	    (object = [objectEnumerator nextObject]) != nil) {
		if (conninfo != nil)
			[conninfo appendFormat: @" %@=%@", key, object];
		else
			conninfo = [OFMutableString stringWithFormat:
			    @"%@=%@", key, object];
	}

	if ((conn = PQconnectdb([conninfo UTF8String])) == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithClass: [self class]];

	if (PQstatus(conn) == CONNECTION_BAD)
		@throw [PGConnectionFailedException
		    exceptionWithClass: [self class]
			    connection: self];

	[pool release];
}

- (void)reset
{
	PQreset(conn);
}

- (PGResult*)executeCommand: (OFString*)command
{
	PGresult *result = PQexec(conn, [command UTF8String]);

	if (PQresultStatus(result) == PGRES_FATAL_ERROR) {
		PQclear(result);
		@throw [PGCommandFailedException
		    exceptionWithClass: [self class]
			    connection: self
			       command: command];
	}

	if (PQresultStatus(result) == PGRES_TUPLES_OK)
		return [PGResult PG_resultWithResult: result];

	PQclear(result);
	return nil;
}

- (PGResult*)executeCommand: (OFString*)command
		 parameters: (id)parameter, ...
{
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	PGresult *result;
	const char **values;
	va_list args, args2;
	size_t argsCount;

	va_start(args, parameter);
	va_copy(args2, args);

	for (argsCount = 1; va_arg(args2, id) != nil; argsCount++);

	values = [self allocMemoryWithSize: sizeof(*values)
				     count: argsCount];
	@try {
		size_t i = 0;

		do {
			if ([parameter isKindOfClass: [OFNull class]])
				values[i++] = NULL;
			else
				values[i++] = [parameter UTF8String];
		} while ((parameter = va_arg(args, id)) != nil);

		result = PQexecParams(conn, [command UTF8String],
		    argsCount, NULL, values, NULL, NULL, 0);
	} @finally {
		[self freeMemory: values];
	}

	[pool release];

	if (PQresultStatus(result) == PGRES_FATAL_ERROR) {
		PQclear(result);
		@throw [PGCommandFailedException
		    exceptionWithClass: [self class]
			    connection: self
			       command: command];
	}

	if (PQresultStatus(result) == PGRES_TUPLES_OK)
		return [PGResult PG_resultWithResult: result];

	PQclear(result);
	return nil;
}

- (PGconn*)PG_connection
{
	return conn;
}
@end
