//
//  SFSObject.m
//  SFS2X
//
//  Original development by Infosfer Game Technologies Ltd. | http://www.infosfer.com.
//
//  Maintained and developed by A51 Integrated.
//  Copyright 2012 A51 Integrated | http://a51integrated.com. All rights reserved.
//

#import "SFSObject.h"
#import "DefaultSFSDataSerializer.h"
#import "DefaultObjectDumpFormatter.h"
#import "SFSDataWrapper.h"
#import "SFSDataType.h"
#import "SFSArray.h"

@implementation SFSObject
	

-(id)init {
	if ((self = [super init])) {
		_dataHolder = [NSMutableDictionary dictionary];
		_serializer = [DefaultSFSDataSerializer getInstance];
	}
	return self;
}

+(id)newInstance {
	SFSObject *obj = [[SFSObject alloc] init];
    return obj;
}

+(id)newFromBinaryData:(NSData *)packet {

	return [[DefaultSFSDataSerializer getInstance] binary2object:packet];
}


-(NSString *)dump {
	
	NSString *strDump = DefaultObjectDumpFormatter_TOKEN_INDENT_OPEN;
	SFSDataWrapper *wrapper;
	int type;
	
	for (NSString *key in [_dataHolder allKeys]) {
		
		wrapper = [self getData:key];
		type = (int)wrapper.type;
		
		strDump = [NSString stringWithFormat:@"%@(%@) %@: ", strDump, [[SFSDataType fromId:wrapper.type] lowercaseString], key];
	
		if (type == SFSDataType_SFS_OBJECT) {
			strDump = [NSString stringWithFormat:@"%@%@", strDump, [(SFSObject *)wrapper.data getDump:NO]];
		}
		else if (type == SFSDataType_SFS_ARRAY) {
			strDump = [NSString stringWithFormat:@"%@%@", strDump, [(SFSArray *)wrapper.data getDump:NO]];
		}
		else if (type > SFSDataType_UTF_STRING && type < SFSDataType_CLASS) {
			strDump = [NSString stringWithFormat:@"%@[%@]", strDump, wrapper.data];
		}
		else {
			strDump = [NSString stringWithFormat:@"%@%@", strDump, wrapper.data];
		}
		strDump = [NSString stringWithFormat:@"%@%@", strDump, DefaultObjectDumpFormatter_TOKEN_DIVIDER];

	}
	
	if ([self size] > 0) {
		strDump = [strDump substringToIndex:[strDump length] - 1];
	}
	
	strDump = [NSString stringWithFormat:@"%@%@", strDump, DefaultObjectDumpFormatter_TOKEN_INDENT_CLOSE];
	
	return strDump;
}

-(NSArray *)getArray:(NSString *)key {
	SFSDataWrapper *wrapper = [_dataHolder objectForKey:key];
	
	if (wrapper != nil) {
		return (NSArray *)wrapper.data;
	}
	else {
		return nil;
	}
}

#pragma mark -
#pragma mark ISFSObject protocol
#pragma mark -

-(BOOL)isNull:(NSString *)key {
	SFSDataWrapper *wrapper = [_dataHolder objectForKey:key];
	
	if (wrapper == nil) {
		return YES;
	}
	
	return wrapper.data == nil;
}

-(BOOL)containsKey:(NSString *)key {
	BOOL found = NO;
	
	for (NSString *keyInDic in [_dataHolder allKeys]) {
		if ([keyInDic isEqualToString:key]) {
			found = YES;
			break;
		}
	}
	
	return found;
}

-(void)removeElement:(NSString *)key {
	[_dataHolder removeObjectForKey:key];
}

-(NSArray *)getKeys {
	return [_dataHolder allKeys];
}

-(NSInteger)size {
	return [_dataHolder count];
}

-(NSData *)toBinary {
	return [_serializer object2binary:self];
}

-(NSString *)getDump:(BOOL)format {
	if (!format) {
		return [self dump];
	}
	else {
		return [DefaultObjectDumpFormatter prettyPrintDump:[self dump]];
	}

}

-(NSString *)getHexDump {
	return [DefaultObjectDumpFormatter hexDump:[self toBinary] bytesPerLine:-1];
}

-(SFSDataWrapper *)getData:(NSString *)key {
	return [_dataHolder objectForKey:key];
}


-(BOOL)getBool:(NSString *)key {
	SFSDataWrapper *wrapper = [_dataHolder objectForKey:key];
	
	if (wrapper != nil) {
		return [(NSNumber *)wrapper.data boolValue];
	}
	else {
		return NO;
	}

}

-(NSInteger)getInt:(NSString *)key {
	SFSDataWrapper *wrapper = [_dataHolder objectForKey:key];
	
	if (wrapper != nil) {
		return [(NSNumber *)wrapper.data intValue];
	}
	else {
		return 0;
	}

}

-(NSInteger)getByte:(NSString *)key {
	return [self getInt:key];
}

-(NSInteger)getUnsignedByte:(NSString *)key {
	return [self getInt:key] & 0x000000FF;
}

-(NSInteger)getShort:(NSString *)key {
	return [self getInt:key];
}



-(NSNumber *)getLong:(NSString *)key {
	return [self getDouble:key];
}

-(NSNumber *)getFloat:(NSString *)key {
	return [self getDouble:key];
}

-(NSNumber *)getDouble:(NSString *)key {
	SFSDataWrapper *wrapper = [_dataHolder objectForKey:key];
	
	if (wrapper != nil) {
		return (NSNumber *)wrapper.data;
	}
	else {
		return nil;
	}
}

-(NSString *)getUtfString:(NSString *)key {
	SFSDataWrapper *wrapper = [_dataHolder objectForKey:key];
	
	if (wrapper != nil) {
		return (NSString *)wrapper.data;
	}
	else {
		return nil;
	}
}

-(NSString *)getText:(NSString *)key
{
    SFSDataWrapper *wrapper = [_dataHolder objectForKey:key];
    
    if (wrapper != nil)
        return (NSString *)wrapper.data;
    else
        return nil;
}

-(NSArray *)getBoolArray:(NSString *)key {
	return [self getArray:key];
}

-(NSData *)getByteArray:(NSString *)key {
	SFSDataWrapper *wrapper = [_dataHolder objectForKey:key];
	
	if (wrapper != nil) {
		return (NSData *)wrapper.data;
	}
	else {
		return nil;
	}
}

// !!
-(NSArray *)getUnsignedByteArray:(NSString *)key {
	
	NSData *data = [self getByteArray:key];
	
	if (data == nil) {
		return nil;
	}
	
	NSMutableArray *unsignedBytes = [NSMutableArray array];
	
	int pos = 0;
	for (int i = 0; i < [data length]; i++) {
		uint8_t byte;
		NSRange range = {pos, 1};
		pos++;
		[data getBytes:&byte range:range];
		[unsignedBytes addObject:[NSNumber numberWithInt:byte]];
	}
	
	return unsignedBytes;
}

-(NSArray *)getShortArray:(NSString *)key {
	return [self getArray:key];
}

-(NSArray *)getIntArray:(NSString *)key {
	return [self getArray:key];
}

-(NSArray *)getLongArray:(NSString *)key {
	return [self getArray:key];
}

-(NSArray *)getFloatArray:(NSString *)key {
	return [self getArray:key];
}

-(NSArray *)getDoubleArray:(NSString *)key {
	return [self getArray:key];
}

-(NSArray *)getUtfStringArray:(NSString *)key {
	return [self getArray:key];
}

-(id <ISFSArray>)getSFSArray:(NSString *)key {
	SFSDataWrapper *wrapper = [_dataHolder objectForKey:key];
	
	if (wrapper != nil) {
		return wrapper.data;
	}
	else {
		return nil;
	}
	
}

-(id <ISFSObject>)getSFSObject:(NSString *)key {
	
	SFSDataWrapper *wrapper = [_dataHolder objectForKey:key];
	
	if (wrapper != nil) {
		return wrapper.data;
	}
	else {
		return nil;
	}
}



-(id)getClass:(NSString *)key {
	SFSDataWrapper *wrapper = [_dataHolder objectForKey:key];
	
	if (wrapper != nil) {
		return wrapper.data;
	}
	else {
		return nil;
	}
}

-(void)putNull:(NSString *)key {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_NULL data:nil] forKey:key];
}

-(void)putBool:(NSString *)key value:(BOOL)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_BOOL data:[NSNumber numberWithBool:value]] forKey:key];
}

-(void)putByte:(NSString *)key value:(NSInteger)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_BYTE data:[NSNumber numberWithInt:(int)value]] forKey:key];
}

-(void)putShort:(NSString *)key value:(NSInteger)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_SHORT data:[NSNumber numberWithInt:(int)value]] forKey:key];
}

-(void)putInt:(NSString *)key value:(NSInteger)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_INT data:[NSNumber numberWithInt:(int)value]] forKey:key];
}

-(void)putLong:(NSString *)key value:(NSNumber *)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_LONG data:value] forKey:key];
}

-(void)putFloat:(NSString *)key value:(NSNumber *)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_FLOAT data:value] forKey:key];
}

-(void)putDouble:(NSString *)key value:(NSNumber *)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_DOUBLE data:value] forKey:key];
}

-(void)putUtfString:(NSString *)key value:(NSString *)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_UTF_STRING data:value] forKey:key];
}

-(void)putBoolArray:(NSString *)key value:(NSArray *)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_BOOL_ARRAY data:value] forKey:key];
}

-(void)putByteArray:(NSString *)key value:(NSData *)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_BYTE_ARRAY data:value] forKey:key];
}

-(void)putShortArray:(NSString *)key value:(NSArray *)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_SHORT_ARRAY data:value] forKey:key];
}

-(void)putIntArray:(NSString *)key value:(NSArray *)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_INT_ARRAY data:value] forKey:key];
}

-(void)putLongArray:(NSString *)key value:(NSArray *)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_LONG_ARRAY data:value] forKey:key];
}

-(void)putFloatArray:(NSString *)key value:(NSArray *)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_FLOAT_ARRAY data:value] forKey:key];
}

-(void)putDoubleArray:(NSString *)key value:(NSArray *)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_DOUBLE_ARRAY data:value] forKey:key];
}

-(void)putUtfStringArray:(NSString *)key value:(NSArray *)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_UTF_STRING_ARRAY data:value] forKey:key];
}

-(void)putSFSArray:(NSString *)key value:(id<ISFSArray>)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_SFS_ARRAY data:value] forKey:key];
}

-(void)putSFSObject:(NSString *)key value:(id<ISFSObject>)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_SFS_OBJECT data:value] forKey:key];
}

-(void)putClass:(NSString *)key value:(id)value {
	[_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_CLASS data:value] forKey:key];
}

-(void)putText:(NSString *)key value:(NSString*)value
{
    [_dataHolder setObject:[[SFSDataWrapper alloc] initWithType:SFSDataType_TEXT data:value] forKey:key];
}

-(void)put:(NSString *)key value:(SFSDataWrapper *)value {
	[_dataHolder setObject:value forKey:key];
}



@end
