#import "DXAsciiHexConverter.h"

static char* hexDigitsL = "0123456789abcdef";
static char* hexDigitsU = "0123456789ABCDEF";

static char* decDigits = "0123456789";

int decDigitValue(int d)
{
	int i;
	for (i = 0; i < 10; i++)
		if (d == decDigits[i])
			return i;
	return 0;
}

BOOL isDecDigit(int d)
{
	int i;
	for (i = 0; i < 10; i++)
		if (d == decDigits[i])
			return YES;
	return NO;
}

int strToDec(NSString* str)
{
	return [str intValue] % 256;
}

NSString* decToStr(int d)
{
	d = d % 256;
	return [[NSNumber numberWithInt: d] stringValue];
}

int hexDigitValue(int d)
{
	int i;
	for (i = 0; i < 16; i++)
	{
		if ((d == hexDigitsL[i])
			||
			(d == hexDigitsU[i])
			)
			return i;
	}
	return 0;
}

BOOL isHexDigit(int d)
{
	int i;
	for (i = 0; i < 16; i++)
	{
		if ((d == hexDigitsL[i])
			||
			(d == hexDigitsU[i])
			)
			return YES;
	}
	return NO;	
}

int strToHex(NSString* str)
{
	int v = 0;
	if ([str length] > 1)
	{
		v = hexDigitValue((int) (([str characterAtIndex: 0]) & 0xff)) << 4;
		v += hexDigitValue((int) (([str characterAtIndex: 1] & 0xff)));
	}
	else if ([str length] > 0)
	{
		v = hexDigitValue((int) (([str characterAtIndex: 0] & 0xff)));
	}
	return v;
}

NSString* hexToStr(int v)
{
	return [NSString stringWithFormat: @"%c%c",
		hexDigitsL[(v & 0xf0) >> 4], hexDigitsL[v & 0x0f]
		];
}


@implementation DXAsciiHexConverter

- (void) awakeFromNib
{
	settingData = NO;
	[hexField setTokenizingCharacterSet: [NSCharacterSet whitespaceCharacterSet]];
	[decField setTokenizingCharacterSet: [NSCharacterSet whitespaceCharacterSet]];
	[asciiField setEditable: NO];
}

- (void) setData: (NSData*) theData
{
	settingData = YES;
	NSMutableArray* hexArray;
	int c, i;
	c = [theData length];
	hexArray = [[NSMutableArray alloc] initWithCapacity: c];
	for (i = 0; i < c; i++)
	{
		[hexArray addObject: hexToStr(((unsigned char*)[theData bytes])[i])];
	}
	[hexField setObjectValue: hexArray];
	[hexArray release];
	[self hexToOthers];	
	settingData = NO;
}

- (NSString*) makeDecStringFrom: (NSString*) str
{
	NSMutableString* res;
	int i, c;
	unsigned char digit;
	
	res = [[NSMutableString alloc] init];
	c = [str length];
	for (i = 0; i < c; i++)
	{
		digit = (unsigned char) [str characterAtIndex: i];
		if (isDecDigit(digit))
			[res appendString: [str substringWithRange: NSMakeRange(i,1)]];
	}
	if ([res length] == 0)
		[res setString: @"0"];
	c = [res length];
	[res setString: [res substringToIndex: c < 3 ? c : 3]];
	c = [res intValue] % 256;
	[res release];
	return [[NSNumber numberWithInt: c] stringValue];
}


- (NSString*) makeHexStringFrom: (NSString*) str
{
	int i, c;
	NSMutableString *res;
	unsigned char digit;	
	res = [[NSMutableString alloc] init];	
	c = [str length];
	for (i = 0; i < c; i++)
	{
		digit = (unsigned char) [str characterAtIndex: i];
		if (isHexDigit(digit))
			[res appendString: [str substringWithRange: NSMakeRange(i,1)]];
	}
	c = [res length];
	for (i = c; i < 2; i++)
		[res insertString: @"0" atIndex: 0];
	[res setString: [res substringWithRange: NSMakeRange(0,2)]];
	return [res autorelease];
}

- (NSData*) data
{
	NSMutableData* res;
	NSArray* hex;
	int i, c;
	unsigned char* bytes;
	unsigned char byte;
	
	hex = [hexField objectValue];
	c = [hex count];
	res = [[NSMutableData alloc] initWithLength: c];
	bytes = [res mutableBytes];
	for (i = 0; i < c; i++)
	{
		byte = (unsigned char) strToHex([hex objectAtIndex: i]);
		bytes[i] = byte;
	}
	return [res autorelease];
}

- (void) hexToAscii
{
	NSArray* hex;
	NSMutableArray* ascii;
	int i,c;
	unichar h;
	hex = [hexField objectValue];
	c = [hex count];
	ascii = [[NSMutableArray alloc] initWithCapacity: c];
	for (i = 0; i < c; i++)
	{
		h = (unichar) strToHex([self makeHexStringFrom: [hex objectAtIndex: i]]);
		if (h < 32) h = '.';
		[ascii addObject: [NSString stringWithCharacters: &h length: 1]];
	}
	[asciiField setObjectValue: ascii];
	[ascii release];
}

- (void) hexToDec
{
	NSArray* hex;
	NSMutableArray* dec;
	int i, c, h;
	hex = [hexField objectValue];
	c = [hex count];
	dec = [[NSMutableArray alloc] initWithCapacity: c];
	for (i = 0; i < c; i++)
	{
		h = strToHex([self makeHexStringFrom: [hex objectAtIndex: i]]);
		[dec addObject: [NSString stringWithFormat: @"%d", h]];
	}
	[decField setObjectValue: dec];
	[dec release];	
}

- (void) decToHex
{
	NSArray* dec;
	NSMutableArray* hex;
	int i, c, d;
	dec = [decField objectValue];
	c = [dec count];
	hex = [[NSMutableArray alloc] initWithCapacity: c];
	for (i = 0; i < c; i++)
	{
		d = strToDec([self makeDecStringFrom: [dec objectAtIndex: i]]);
		d %= 256;
		[hex addObject: hexToStr(d)];
	}
	[hexField setObjectValue: hex];
	[hex release];
}

- (void) hexToOthers
{
	[self hexToAscii];
	[self hexToDec];
}

- (void) decToOthers
{
	[self decToHex];
	[self hexToAscii];
}

- (BOOL) isValidHex: (NSString*) hexString
{
	int i, l;
	unsigned char c;
	l = [hexString length];
	for (i = 0; i < l; i++)
	{
		c = (unsigned char) [hexString characterAtIndex: i];
		if (! isHexDigit(c))
			return NO;
	}
	return YES;
}

- (BOOL) isValidDec: (NSString*) decString
{
	int i, l;
	unsigned char c;
	l = [decString length];
	for (i = 0; i < l; i++)
	{
		c = (unsigned char) [decString characterAtIndex: i];
		if (! isDecDigit(c))
			return NO;
	}
	return YES;
}

- (NSString *)tokenField:(NSTokenField *)tokenField displayStringForRepresentedObject:(id)representedObject
{
	if (settingData) return representedObject;
	if (tokenField == hexField)
		return [self makeHexStringFrom: representedObject];
	else if (tokenField == decField)
		return [self makeDecStringFrom: representedObject];
	else return representedObject;
}

- (void) controlTextDidChange: (NSNotification*) n
{
	id sender;
	sender = [n object];
	if (sender == hexField)
	{
		if (! settingData)
		{
			settingData = YES;
			[self hexToOthers];
			settingData = NO;			
		}
	}
	else if (sender == decField)
	{
		if (! settingData)
		{
			settingData = YES;
			[self decToOthers];
			settingData = NO;
		}
	}
}

@end
