#import "NSString+tsv.h"

@implementation NSString ( tsv )

/*"	Split a string into lines separated by any of the various newline characters.  Equivalent to componentsSeparatedByString:@"\n" but it works with the different line separators: \r, \n, \r\n, 0x2028, 0x2029
"*/

- (NSArray *) componentsSeparatedByLineSeparators
{
	NSMutableArray *result	= [NSMutableArray array];
	NSRange range = NSMakeRange(0,0);
	unsigned start, end;
	unsigned contentsEnd = 0;

	while (contentsEnd < [self length])
	{
		[self getLineStart:&start end:&end contentsEnd:&contentsEnd forRange:range];
		[result addObject:[self substringWithRange:NSMakeRange(start,contentsEnd-start)]];
		range.location = contentsEnd+1;
		range.length = 0;
	}
	return result;
}


/*"	Build an array of dictionaries from a TSV (tab-separated values) string.  Blank lines and lines starting with "#" are ignored.  The first non-empty, non-comment line is assumed to be the keys.  Empty lines are not added to the array, so blank lines (or lines with just tabs) are safely ignored.  Missing items aren't added to the dictionary.  The string is assumed to be separated with UNIX newlines only.
"*/

- (NSArray *) arrayFromTSV
{
	NSMutableArray *result	= [NSMutableArray array];
	NSArray		*lines		= [self componentsSeparatedByLineSeparators];
	NSEnumerator*theEnum	= [lines objectEnumerator];
	NSArray		*keys		= nil;
	int			keyCount	= 0;
	NSString	*theLine;

	while (nil != (theLine = [theEnum nextObject]) )
	{
		if (![theLine isEqualToString:@""] && ![theLine hasPrefix:@"#"])	// ignore empty lines and lines that start with #
		{
			if (nil == keys)	// Is keys not set yet? If so, process first real line as list of keys
			{
				keys = [theLine componentsSeparatedByString:@"\t"];
				keyCount = [keys count];
			}
			else	// A data line
			{
				NSMutableDictionary	*lineDict	= [NSMutableDictionary dictionary];
				NSArray				*values		= [theLine componentsSeparatedByString:@"\t"];
				int					valueCount	= [values count];
				int i;
		
				for ( i = 0 ; i < keyCount && i < valueCount ; i++ )
				{
					NSString *value = [values objectAtIndex:i];
					if (nil != value && ![value isEqualToString:@""])
					{
						[lineDict setObject:value forKey:[keys objectAtIndex:i]];
					}
				}
				if ([lineDict count])	// only add the line if there was any data
				{
					[result addObject:lineDict];
				}
			}
		}
	}
	return result;
}

@end
