
#import "MiniSQLAdaptor.h"
#import "MiniSQLAdaptorContext.h"
#import "MiniSQLAdaptorChannel.h"
#import "MiniSQLExpression.h"

#import <foundation/NSArray.h>
#import <foundation/NSString.h>
#import <foundation/NSBundle.h>
#import <foundation/NSDictionary.h>
#import <foundation/NSUtilities.h>
#import <foundation/NSString.h>
#import <foundation/NSValue.h>

#import <eoaccess/eoaccess.h>

#import <objc/objc-runtime.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

@implementation MiniSQLAdaptor

- (Class)expressionClass
// Returns the subclass of EOSQLExpression used by this adaptor for query
// language expressions.  You directly invoke this method, but an
// adaptor subclass must properly implement this method.
{
    return [MiniSQLExpression class];
}

- (EOAdaptorContext *)createAdaptorContext
// Returns a new EOAdaptorContext, or nil if a new context cannot be
// created.  EOAdaptors by default have no contexts at all.  The newly
// created context retains its adaptor.
{
    return [[[MiniSQLAdaptorContext alloc] initWithAdaptor:self] autorelease];
}


- (BOOL) hasOpenChannels
// Returns YES if the adaptor has any open channels, NO otherwise. See
// -openChannel in EOAdaptorChannel.h.
{
    return (openChannels > 0) ? YES : NO;
}

- (void) miniSQLChannelDidConnect
{
    openChannels += 1;
}

- (void)miniSQLChannelDidDisconnect
{
    if (openChannels > 0) {
	openChannels -= 1;
    }
}

- (BOOL)hasValidConnectionDictionary
// Returns YES if the adaptor can connect with the current connection
// dictionary, NO otherwise. An actual connection is made when the first
// adaptor channel is sent an -openChannel message.
{
    if ([self hasOpenChannels]) {
	return YES;
    } else {
	MiniSQLAdaptorChannel *aChannel = [[[MiniSQLAdaptorChannel alloc]
					    initWithAdaptor:self
					    andContext:nil]
					    autorelease];

	return [aChannel connectWithConnectionDictionary:[self connectionDictionary]];
    }
}

- formatAttribute:(EOAttribute *)attribute
{
    return attribute;
}

- formatValue:value forAttribute:(EOAttribute *) attribute
{
    if ((value == nil) || (value == [EONull null])) {
	return @"NULL";
    } else {
	if ([value respondsToSelector:@selector(stringForType:)]) {
	    NSString           *type = [attribute valueType];

	    return[[[EOQuotedExpression alloc]
		    initWithExpression:[value stringForType:type]
		    quote:@"'"
		    escape:@"'"]
		   autorelease];
	} else {
	    NSString           *type = [attribute externalType];

	// MiniSQL now seems to deal with REAL values sans decimal in 
	// a reasonable way, hence code written to force a decimal point 
	// inside REAL numbers has disappeared... 
	    if ([type isEqualToString:@"INT"] ||
		[type isEqualToString:@"REAL"]) {
		return [(NSNumber *)value stringValue];
	    } else {
		return[[[EOQuotedExpression alloc]
			initWithExpression:value
			quote:@"'"
			escape:@"'"]
		       autorelease];
	    }
	}
    }
}
- valueForCString:(const char *)expression
    attribute:(EOAttribute *) attribute
    zone:(NSZone *) zone
{
    id                  ret = nil;

    const char         *className;
    NSString           *valueType;
    NSString           *externalType;

    Class               valueClass = (Class) 0;

 // get the type of the column 
    className = [attribute valueClassName];
    valueType = [attribute valueType];
    externalType = [attribute externalType];

    if (className != NULL) {
	valueClass = objc_lookUpClass(className);
    } else {
	if ([externalType isEqualToString:@"INT"] ||
	    [externalType isEqualToString:@"REAL"]) {
	    valueClass = [NSNumber class];
	} else {
	    valueClass = [NSString class];
	}
    }

    if (valueClass != NULL) {
	if ([valueClass instancesRespondToSelector:
		    @selector(initWithString:type:)]) {
	    NSString           *string;

	    string = [[[NSString allocWithZone:zone]
		       initWithCString:expression]
		      autorelease];

	    ret = [[[valueClass allocWithZone:zone]
		    initWithString:string
		    type:valueType]
		   autorelease];
	} else if (valueClass == [NSString class]) {
	    ret = [[[valueClass allocWithZone:zone]
		    initWithCString:expression]
		   autorelease];
	} else {
	    if ([externalType isEqualToString:@"INT"]) {
		ret = [[[valueClass allocWithZone:zone]
			initWithInt:atoi(expression)]
		       autorelease];
	    } else {
		ret = [[[valueClass allocWithZone:zone]
			initWithDouble:atof(expression)]
		       autorelease];
	    }
	}
    } else {
	[self reportError:
	 [NSString stringWithFormat:
	  @"Adaptor could not create object for attribute %@.",
	  [attribute name]]];

	ret = [[[NSString allocWithZone:zone]
		initWithCString:expression]
	       autorelease];
    }

    return ret;
}

- (BOOL) isValidQualifierType:(NSString *)typeName
{
 // everything is permitted...
    return YES;
}
@end
