//
//	MiscStringComparing.m
//		Written by Don Yacktman (c) 1993 by Don Yacktman.
//				Version 1.7  All rights reserved.
//		This notice may not be removed from this source code.
//
//	This object is included in the MiscKit by permission from the author
//	and its use is governed by the MiscKit license, found in the file
//	"LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
//	for a list of all applicable permissions and restrictions.
//	

#import <misckit/MiscString.h>

@implementation MiscString(Comparing)

// This category is composed of methods which compare
// MiscStrings with other strings.

- (BOOL)isEqual:anObject
{
	if (anObject == self) return YES;
	// doesn't have to be a MiscString object to be equal...
	if ([anObject respondsTo:@selector(stringValue)]) {
		if (!NXOrderStrings((unsigned char *)buffer,
				(unsigned char *)[anObject stringValue],
				YES, -1, orderTable)) return YES;
	}
	return NO;
}

- (unsigned int)hash
// Use the NextStep string hashing functiuon NXStrHash()  instead of 
// the pointer hashing function. 
{
	return NXStrHash(NULL, buffer);
}

- (int)compareTo:sender
{
	return [self compareTo:sender n:(-1) caseSensitive:YES];
}

- (int)compareTo:sender n:(int)n
{
	return [self compareTo:sender n:n caseSensitive:YES];
}

- (int)cmp:(const char *)aString
{
	if (!aString && !buffer) return 0;		// both NULL, so "equal"
	if (!aString) return 1;	// only one is NULL, so not equal
	if (!buffer) return -1;	// only one is NULL, so not equal
	return strcmp(buffer, aString);
}

- (int)cmp:(const char *)aString n:(int)n
{
	if (!aString && !buffer) return 0;		// both NULL, so "equal"
	if (!aString) return 1;	// only one is NULL, so not equal
	if (!buffer) return -1;	// only one is NULL, so not equal
	// we don't check n; use strncmp's behavior here.
	return strncmp(buffer, aString, n);
}

- (int)compareTo:sender caseSensitive:(BOOL)sense
{
	return [self compareTo:sender n:(-1) caseSensitive:sense];
}

- (int)compareTo:sender n:(int)n caseSensitive:(BOOL)sense
{
	const char *s; int senderLength, size = n;
	if (!sender) {
		if (!buffer) return 0;
		return 1;
	}
	if (![sender respondsTo:@selector(stringValue)]) return 1; // !=
	s = [sender stringValue];
	if (!buffer && !s) return 0;		// both are NULL
	if (!buffer) return -1;	// buffer is NULL
	if (!s) return 1;	// sender is NULL
	if ([sender respondsTo:@selector(length)]) senderLength = [sender length];
	else senderLength = strlen(s);
	if ((size > length) || (size > senderLength))  {
		size = MIN(length, senderLength);
		if (!size) if (senderLength) return -1;
		else if (length) return 1;
		else return 0;
	}
	return NXOrderStrings((unsigned char *)buffer,
			(unsigned char *)s, sense, size, orderTable);
}

- (int)casecmp:(const char *)aString
{
	if (!aString && !buffer) return 0;		// both NULL, so "equal"
	if (!aString || !buffer) return -1;	// only one is NULL, so not equal
	return strcasecmp(buffer, aString);
}

- (int)casecmp:(const char *)aString n:(int)n
{
	if (!aString && !buffer) return 0;		// both NULL, so "equal"
	if (!aString || !buffer) return -1;	// only one is NULL, so not equal
	// we don't check n; use strncasecmp's behavior here.
	return strncasecmp(buffer, aString, n);
}

- (int)endcmp:(const char *)aString
{
  return [self endcmp:aString n:-1];
}

- (int)endcmp:(const char *)aString n:(int)n
{
  id tempStr;
  int retval;
  if (!aString) return -1;
  tempStr = [[self class] newWithString:aString];
  retval = [self endCompareTo:tempStr n:n caseSensitive:YES];
  [tempStr free];
  return retval;
}

- (int)endcasecmp:(const char *)aString
{
  return [self endcasecmp:aString n:-1];
}

- (int)endcasecmp:(const char *)aString n:(int)n
{
  id tempStr;
  int retval;
  if (!aString) return -1;
  tempStr = [[self class] newWithString:aString];
  retval = [self endCompareTo:tempStr n:n caseSensitive:NO];
  [tempStr free];
  return retval;
}

- (int)endCompareTo:(id)sender
{
  return [self endCompareTo:sender n:-1 caseSensitive:YES];
}

- (int)endCompareTo:(id)sender caseSensitive:(BOOL)sense
{
  return [self endCompareTo:sender n:-1 caseSensitive:sense];
}

- (int)endCompareTo:(id)sender n:(int)n
{
  return [self endCompareTo:sender n:n caseSensitive:YES];
}

- (int)endCompareTo:(id)sender n:(int)n caseSensitive:(BOOL)sense
{ // DAY: fixed it: sender doesn't have to be a MiscString anymore.
	id tempStr, temp2, temp3;
	int retval, smallLen, senderLength;
	const char *s;
	// unlike MOKit, we allow NULL/empty strings, and we adjust n if
	// it is too big.  also, this method is slower than MOKit complement.
	if (!sender) {
		if (!buffer) return 0;
		return 1;
	}
	if (!([sender respondsTo:@selector(stringValue)])) return -1;
	s = [sender stringValue];
	if (!s || !buffer) return -1;
	if ([sender respondsTo:@selector(length)]) senderLength = [sender length];
	else senderLength = strlen(s);
	// find the shorter of the two lengths
	smallLen = ((length >= senderLength) ? senderLength : length);
	if ((n == -1) || (n > smallLen)) n = smallLen;
	tempStr = [self right:n];
	if ([sender respondsTo:@selector(right:)]) temp2 = [sender right:n];
	else {
		temp3 = [[self class] newWithString:[sender stringValue]];
		temp2 = [temp3 right:n];
		[temp3 free];
	}
	retval = [tempStr compareTo:temp2 caseSensitive:sense];
	[tempStr free];
	[temp2 free];
	return retval;
}

@end
