//
//  DXKey.m
//  DefEcs
//
//  Created by ttomek on 06-08-18.
//  Copyright 2006 hipercom.pl. All rights reserved.
//

#import "DXKey.h"


@implementation DXKey

- (id) initWithName: (id) aName
			  value: (id) aValue
			 parent: (DXKey*) aParent
			 domain: (NSString*) aDomain
{
	if (self = [super init])
	{
		name = [aName copy];
		parent = aParent;
		domain = [aDomain copy];
		value = [[[self class] processValue: aValue forKey: self] retain];
	}
	return self;
}

- (void) encodeWithCoder: (NSCoder*) coder
{
	[coder encodeObject: domain];
	[coder encodeObject: name];
	[coder encodeObject: value];
}

- (id) initWithCoder: (NSCoder*) coder
{
	if (self = [super init])
	{
		parent = nil;
		domain = [[coder decodeObject] retain];
		name = [[coder decodeObject] retain];
		value = [[coder decodeObject] retain];
		if ([self isCompound])
			[self performForAll: @selector(setParent:) withObject: self];
	}
	return self;
}

- (void) dealloc
{
	[name release];
	[value release];
	[domain release];
	[super dealloc];
}

- (BOOL) isCompound
{
	return ([self isArray] || [self isDictionary]);
}

- (BOOL) isArray
{
	return [[self class] isObjectArray: value];
}

- (BOOL) isDictionary
{
	return [[self class] isObjectDictionary: value];
}

- (id) name
{
	return name;
}

- (NSString*) nameDescription
{
	if ([[self class] isObjectNumber: name])
		return [NSString stringWithFormat: DXmsgArrayItemNumber, [name intValue]];
	else
		return name;
}


- (id) value
{
	return value;
}

- (NSString*) valueDescription
{
	if ([self isCompound])
		return [NSString stringWithFormat: DXmsgNumberOfSubitems, [self count]];
	else if ([[self class] isObjectBoolean: value])
	{
		if ([value boolValue])
			return DXmsgYES;
		else
			return DXmsgNO;
	}
	else return [value description];
}

- (DXKey*) parent
{
	return parent;
}

- (void) setParent: (DXKey*) aParent
{
	parent = aParent;
}

- (NSString*) domain
{
	return domain;
}

- (int) count
{
	if ([self isCompound])
		return [value count];
	else
		return 0;
}

- (DXKey*) childAtIndex: (int) index
{
	if ([self isArray])
		return [value objectAtIndex: index];
	else if ([self isDictionary])
		return [value objectForKey: [[value allKeys] objectAtIndex: index]];
	else
		return nil;
}

- (DXKey*) childForName: (id) aName
{
	if ([self isArray])
		return [self childAtIndex: [aName intValue]];
	else if ([self isDictionary])
		return [value objectForKey: aName];
	else
		return nil;
}

- (void) addKey: (DXKey*) newKey forName: (id) keyName
{
	if ([self isArray])
		[value insertObject: newKey atIndex: [keyName intValue]];
	else if ([self isDictionary])
		[value setObject: newKey forKey: keyName];
}

- (void) addKey: (DXKey*) newKey
{
	if ([self isArray])
		[value addObject: newKey];
	else
		[value setObject: newKey forKey: [newKey name]];
}

- (void) removeKey: (DXKey*) aKey
{
	if ([self isArray])
		[value removeObjectAtIndex: [[aKey name] intValue]];
	else
		[value removeObjectForKey: [aKey name]];
}

- (void) replaceKey: (DXKey*) oldKey withKey: (DXKey*) newKey
{
	if ([self isArray])
		[value replaceObjectAtIndex: [[oldKey name] intValue] 
						 withObject: newKey];
	else
		[value setObject: newKey forKey: [oldKey name]];
}

- (NSString*) typeName
{
	return [[self class] valueTypeName: value];
}

- (void) performForAll: (SEL) aSelector withObject: (id) anArgument
{
	if ([self isArray])
		[value makeObjectsPerformSelector: aSelector withObject: anArgument];
	else if ([self isDictionary])
		[[value allValues] makeObjectsPerformSelector: aSelector withObject: anArgument];
}

- (id) databaseRepresentation
{
	if ([self isArray])
	{
		int c, i;
		NSMutableArray* result;
		id v;
		c = [value count];
		result = [[NSMutableArray alloc] initWithCapacity: c];
		for (i = 0; i < c; i++)
		{
			v = [[value objectAtIndex: i] databaseRepresentation];
			[result addObject: v];			
		}
		return [result autorelease];
	}
	else if ([self isDictionary])
	{
		NSEnumerator* e;
		id k;
		id v;
		NSMutableDictionary* result;
		result = [[NSMutableDictionary alloc] init];
		e = [value keyEnumerator];
		while (k = [e nextObject])
		{
			v = [[value objectForKey: k] databaseRepresentation];
			[result setObject: v forKey: k];
		}
		return [result autorelease];		
	}
	else return value;
}

- (BOOL) keyExists: (id) keyName
{
	if ([self isDictionary])
	{
		id v;
		v = [self childForName: keyName];
		if (v == nil)
			return NO;
		else
			return YES;		
	}
	else
		return NO;
		
}

+ (BOOL) isObjectArray: (id) anObject
{
	if ([anObject isKindOfClass: [NSArray class]])
		return YES;
	else
		return NO;
}
+ (BOOL) isObjectDictionary: (id) anObject
{
	if ([anObject isKindOfClass: [NSDictionary class]])
		return YES;
	else
		return NO;
}

+ (BOOL) isObjectCompound: (id) anObject
{
	return ([self isObjectArray: anObject]
			||
			[self isObjectDictionary: anObject]
			);
}

+ (BOOL) isObjectString: (id) anObject
{
	return [anObject isKindOfClass: [NSString class]];
}

+ (BOOL) isObjectBoolean: (id) anObject
{
	return ([NSStringFromClass([anObject class]) isEqualToString:@"NSCFBoolean"]);
}

+ (BOOL) isObjectNumber: (id) anObject
{
	return [anObject isKindOfClass: [NSNumber class]];
}

+ (BOOL) isObjectDate: (id) anObject
{
	return [anObject isKindOfClass: [NSDate class]];
}

+ (BOOL) isObjectData: (id) anObject
{
	return [anObject isKindOfClass: [NSData class]];
}

+ (NSString*) valueTypeName: (id) aValue
{	
	if ([self isObjectBoolean: aValue])
		return DXmsgKeyTypeBoolean;
	if ([self isObjectNumber: aValue])
		return DXmsgKeyTypeNumber;		
	else if ([self isObjectDate: aValue])
		return DXmsgKeyTypeDate;
	else if ([self isObjectData: aValue])
		return DXmsgKeyTypeData;
	else if ([self isObjectArray: aValue])
		return DXmsgKeyTypeArray;
	else if ([self isObjectDictionary: aValue])
		return DXmsgKeyTypeDictionary;
	else
		return DXmsgKeyTypeString;
}

+ (id) processValue: (id) aValue forKey: (DXKey*) aKey
{
	if ([self isObjectCompound: aValue])
	{
		if ([self isObjectArray: aValue])
		{
			NSMutableArray *newValue;
			DXKey* toAdd;
			int i, c;
			id item;
			c = [aValue count];
			newValue = [[NSMutableArray alloc] initWithCapacity: c];
			for (i = 0; i < c; i++)
			{
				item = [aValue objectAtIndex: i];
				toAdd = [[DXKey alloc] initWithName: [NSNumber numberWithInt: i]
											  value: item
											 parent: aKey
											 domain: [aKey domain]];
				[newValue addObject: toAdd];
				[toAdd release];
			}
			return [newValue autorelease];
		}
		else
		{
			NSMutableDictionary* newValue;
			NSEnumerator* e;
			DXKey* toAdd;
			id k;
			id item;
			newValue = [[NSMutableDictionary alloc] init];
			e = [aValue keyEnumerator];
			while (k = [e nextObject])
			{
				item = [aValue objectForKey: k];
				toAdd = [[DXKey alloc] initWithName: k
											  value: item
											 parent: aKey
											 domain: [aKey domain]];
				[newValue setObject: toAdd forKey: k];
				[toAdd release];
			}
			return [newValue autorelease];
		}
	}
	else return aValue;
}



@end
