//
//  SFSArray.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 "SFSArray.h"
#import "SFSException.h"
#import "SFSDataType.h"
#import "SFSObject.h"
#import "SFSDataWrapper.h"
#import "DefaultSFSDataSerializer.h"
#import "DefaultObjectDumpFormatter.h"

@implementation SFSArray


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

+(SFSArray *)newFromArray:(NSArray *)arr {
	@throw [SFSException exceptionWithReason:@"Not implemented yet!"];
	return nil;
}

+(SFSArray *)newFromBinaryData:(NSData *)data {

	return (SFSArray *)[[DefaultSFSDataSerializer getInstance] binary2array:data];
}

+(SFSArray *)newInstance {
	return [[SFSArray alloc] init];
}

-(NSString *)dump {
	
	NSString *strDump = DefaultObjectDumpFormatter_TOKEN_INDENT_OPEN;
	SFSDataWrapper *wrapper;
	NSString *objDump;
	int type;
	
	for (id key in _dataHolder) {
		if (![key isKindOfClass:[SFSDataWrapper class]]) {
			continue;
		}
		
		wrapper = key;
		type = (int)wrapper.type;
		
		if (type == SFSDataType_SFS_OBJECT) {
			objDump = [(SFSObject *)wrapper.data getDump:NO];
		}
		else if (type == SFSDataType_SFS_ARRAY) {
			objDump = [(SFSArray *)wrapper.data getDump:NO];
		}
		else if (type > SFSDataType_UTF_STRING && type < SFSDataType_CLASS) {
			objDump = [NSString stringWithFormat:@"[%@]", wrapper.data];
		}
		else {
			objDump = wrapper.data;
		}
		
		strDump = [NSString stringWithFormat:@"%@(%@)", strDump, [[SFSDataType fromId:wrapper.type] lowercaseString]];
		
		strDump = [NSString stringWithFormat:@"%@%@", strDump, objDump];
		
		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;
}


-(void)addObject:(id)value type:(NSInteger)type {
	[self add:[[SFSDataWrapper alloc] initWithType:type data:value]];
}

-(NSArray *)getArray:(NSInteger)index {
	SFSDataWrapper *wrapper = (index >= [self size]) ? nil : [_dataHolder objectAtIndex:index];
	return (wrapper != nil ? (NSArray *)wrapper.data : nil);

}

#pragma mark -
#pragma mark ISFSArray protocol


-(BOOL)contains:(id)obj {
	
	if ([obj conformsToProtocol:@protocol(ISFSArray)] || [obj conformsToProtocol:@protocol(ISFSObject)]) {
		@throw [SFSException exceptionWithReason:@"ISFSArray and ISFSObject are not supported by this method."];
	}
	
	BOOL found = NO;
	
	for (int j = 0; j < [self size]; j++) {
		SFSDataWrapper *wrappedObj = (SFSDataWrapper *)[self getElementAt:j];
		
		if (wrappedObj != nil) {
			if ([wrappedObj.data isEqual:obj]) {
				found = YES;
				break;
			}
		}
	}
	
	return found;
	
}


-(id)getElementAt:(NSInteger)index
{
	id obj = nil;
	
    /*
     * Index must be within range and not null
     */
	if ( index < _dataHolder.count && [_dataHolder objectAtIndex:index] != nil )
    {
		obj = ((SFSDataWrapper *)[_dataHolder objectAtIndex:index]).data;
	}
	
	return obj;
}

-(SFSDataWrapper *)getWrappedElementAt:(NSInteger)index {
	return [_dataHolder objectAtIndex:index];
}

-(id)removeElementAt:(NSInteger)index {
	
	id obj = [_dataHolder objectAtIndex:index];
	
	[_dataHolder removeObjectAtIndex:index];
	
	return obj;
	
}

#pragma clang diagnostic ignored "-Wunused-variable"
-(NSInteger)size {
	int count = 0;
	
	for (NSString *j in _dataHolder) {
		count++;
	}
	
	return count;
    
}

-(NSData *)toBinary {
	return [_serializer array2binary: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];
}

-(void)addNull {
	[self addObject:nil type:SFSDataType_NULL];
}

-(void)addBool:(BOOL)value {
	[self addObject:[NSNumber numberWithBool:value] type:SFSDataType_BOOL];
}

-(void)addByte:(NSInteger)value {
	[self addObject:[NSNumber numberWithInt:(int)value] type:SFSDataType_BYTE];
}

-(void)addShort:(NSInteger)value {
	[self addObject:[NSNumber numberWithInt:(int)value] type:SFSDataType_SHORT];
}

-(void)addInt:(NSInteger)value {
	[self addObject:[NSNumber numberWithInt:(int)value] type:SFSDataType_INT];
}

-(void)addLong:(NSNumber *)value {
	[self addObject:value type:SFSDataType_LONG];
}

-(void)addFloat:(NSNumber *)value {
	[self addObject:value type:SFSDataType_FLOAT];
}

-(void)addDouble:(NSNumber *)value {
	[self addObject:value type:SFSDataType_DOUBLE];
}

-(void)addUtfString:(NSString *)value {
	[self addObject:value type:SFSDataType_UTF_STRING];
}

-(void)addBoolArray:(NSArray *)value {
	[self addObject:value type:SFSDataType_BOOL_ARRAY];
}

-(void)addByteArray:(NSData *)value {
	[self addObject:value type:SFSDataType_BYTE_ARRAY];
}

-(void)addShortArray:(NSArray *)value {
	[self addObject:value type:SFSDataType_SHORT_ARRAY];
}

-(void)addIntArray:(NSArray *)value {
	[self addObject:value type:SFSDataType_INT_ARRAY];
}

-(void)addLongArray:(NSArray *)value {
	[self addObject:value type:SFSDataType_LONG_ARRAY];
}

-(void)addFloatArray:(NSArray *)value {
	[self addObject:value type:SFSDataType_FLOAT_ARRAY];
}

-(void)addDoubleArray:(NSArray *)value {
	[self addObject:value type:SFSDataType_DOUBLE_ARRAY];
}

-(void)addUtfStringArray:(NSArray *)value {
	[self addObject:value type:SFSDataType_UTF_STRING_ARRAY];
}

-(void)addSFSArray:(id<ISFSArray>)value {
	[self addObject:value type:SFSDataType_SFS_ARRAY];
}

-(void)addSFSObject:(id<ISFSObject>)value {
	[self addObject:value type:SFSDataType_SFS_OBJECT];
}

-(void)addClass:(id)value {
	[self addObject:value type:SFSDataType_CLASS];
}

-(void)addText:(NSString*)value
{
    [self addObject:value type:SFSDataType_TEXT];
}


-(void)add:(SFSDataWrapper *)wrappedObject {
	[_dataHolder addObject:wrappedObject];
}

-(BOOL)isNull:(NSInteger)index {
	BOOL isNull = NO;
	SFSDataWrapper *wrapper = (index >= [self size]) ? nil : [_dataHolder objectAtIndex:index];
	
	if (wrapper == nil || wrapper.type == SFSDataType_NULL) {
		isNull = YES;
	}
	
	return isNull;
}

-(BOOL)getBool:(NSInteger)index {
	SFSDataWrapper *wrapper = (index >= [self size]) ? nil : [_dataHolder objectAtIndex:index];
	return (wrapper != nil ? [(NSNumber *)wrapper.data boolValue] : NO);
}
-(NSInteger)getInt:(NSInteger)index {
	SFSDataWrapper *wrapper = (index >= [self size]) ? nil : [_dataHolder objectAtIndex:index];
	return (wrapper != nil ? [(NSNumber *)wrapper.data intValue] : -1);
}

-(NSInteger)getByte:(NSInteger)index {
	return [self getInt:index] & 0x000000FF;
}

-(NSInteger)getUnsignedByte:(NSInteger)index {
	return [self getInt:index];
}

-(NSInteger)getShort:(NSInteger)index {
	return [self getInt:index];
}

-(NSNumber *)getDouble:(NSInteger)index {
	SFSDataWrapper *wrapper = (index >= [self size]) ? nil : [_dataHolder objectAtIndex:index];
	return (wrapper != nil ? (NSNumber *)wrapper.data : nil);
}

-(NSNumber *)getLong:(NSInteger)index {
	return [self getDouble:index];
}

-(NSNumber *)getFloat:(NSInteger)index {
	return [self getDouble:index];
}

-(NSString *)getUtfString:(NSInteger)index {
	SFSDataWrapper *wrapper = (index >= [self size]) ? nil : [_dataHolder objectAtIndex:index];
	return (wrapper != nil ? (NSString *)wrapper.data : nil);
}

-(NSString *) getText:(NSInteger) index
{
    SFSDataWrapper *wrapper = (index >= [self size]) ? nil : [_dataHolder objectAtIndex:index];
    return (wrapper != nil ? (NSString *)wrapper.data : nil);
}

-(NSArray *)getBoolArray:(NSInteger)index {
	return [self getArray:index];
}

-(NSData *)getByteArray:(NSInteger)index {
	SFSDataWrapper *wrapper = (index >= [self size]) ? nil : [_dataHolder objectAtIndex:index];
	return (wrapper != nil ? (NSData *)wrapper.data : nil);
}

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

-(NSArray *)getShortArray:(NSInteger)index {
	
	return [self getArray:index];
}

-(NSArray *)getIntArray:(NSInteger)index {
	
	
	return [self getArray:index];
}

-(NSArray *)getLongArray:(NSInteger)index {
	
	return [self getArray:index];
}


-(NSArray *)getFloatArray:(NSInteger)index {
	
	
	return [self getArray:index];
}

-(NSArray *)getDoubleArray:(NSInteger)index {


	return [self getArray:index];
}

-(NSArray *)getUtfStringArray:(NSInteger)index {
	return [self getArray:index];
}

-(id <ISFSArray>)getSFSArray:(NSInteger)index {
	SFSDataWrapper *wrapper = (index >= [self size]) ? nil : [_dataHolder objectAtIndex:index];
	return (wrapper != nil ? (id <ISFSArray>)wrapper.data : nil);
}

-(id <ISFSObject>)getSFSObject:(NSInteger)index {
	SFSDataWrapper *wrapper = (index >= [self size]) ? nil : [_dataHolder objectAtIndex:index];
	return (wrapper != nil ? (id <ISFSObject>)wrapper.data : nil);
}

-(id)getClass:(NSInteger)index {
	SFSDataWrapper *wrapper = (index >= [self size]) ? nil : [_dataHolder objectAtIndex:index];
	return (wrapper != nil ? wrapper.data : nil);
}


#pragma mark -


@end
