//
//	MiscStringReplacing.m
//		Written by Don Yacktman (c) 1993 by Don Yacktman.
//				Version 1.95  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(Replacing)

// This category is composed of methods which modify a MiscString
// by replacing a character or substring with a new character or
// substring.

- replaceFrom:(int)start length:(int)len with:(const char *)aString
{
  return [[self removeFrom:start length:len] insert:aString at:start];
}

- replaceFrom:(int)start to:(int)end with:(const char *)aString
{
  return [[self removeFrom:start to:end] insert:aString at:start];
}

- replaceFrom:(int)start length:(int)len withString:(id)sender
{
  if (![sender respondsTo:@selector(stringValue)]) return self;
  return [self replaceFrom:start length:len with:[sender stringValue]];
}

- replaceFrom:(int)start to:(int)end withString:(id)sender
{
  if (![sender respondsTo:@selector(stringValue)]) return self;
  return [self replaceFrom:start to:end with:[sender stringValue]];
}

- replace:(const char *)subString with:(const char *)newString
{
  const char *spot;
  
  if ((spot = [self strstr:subString]))
    [self replaceFrom:(int)(spot-buffer) length:strlen(subString) with:newString];
  return self;
}

- replace:(const char *)subString withString:(id)sender
{
  if (![sender respondsTo:@selector(stringValue)]) return self;
  return [self replace:subString with:[sender stringValue]];
}

- replaceCharAt:(int)index withChar:(char)aChar
{	// no change if index is out of range.
	// Other option is to limit index to be in range.  which is better?
  if ((index < 0) || (index >= length)) return self;

  if (aChar == 0) return self; // should this return nil? DAY: leave it.

  buffer[index] = aChar;
  return self;
}

- replaceFrom:(int)start length:(int)len withChar:(char)aChar
{
    id retval,tempStr;
   
    if (aChar == 0) return nil;
    tempStr = [[[[self class] alloc] init] addChar:aChar];
    retval = [self  replaceFrom:start length:len
					withString:tempStr];
    [tempStr free];
    return retval;
}

- replaceFrom:(int)start to:(int)end withChar:(char)aChar
{
  return [self replaceFrom:start length:end-start+1 withChar:aChar];
}

- replaceEveryOccurrenceOfChars:(const char *)aString
		with:(const char *)replaceString
{
	return [self replaceEveryOccurrenceOfChars:aString
			with:replaceString caseSensitive:YES];
}

- replaceEveryOccurrenceOfChars:(const char *)aString
		with:(const char *)replaceString caseSensitive:(BOOL)sense
{
	int i;
	id tempStr;

	if (!aString) return self;
		// I think a null replace string should be allowed here...
 
	tempStr = [MiscString newWithString:aString];
	for (i=length-1;i>=0;i--)
	if ([tempStr spotOf:buffer[i] caseSensitive:sense] != -1)
		[self replaceFrom:i to:i with:replaceString];

	[tempStr free];
	return self;
}

- replaceEveryOccurrenceOfChars:(const char *)aString
		withChar:(char)replaceChar
{
	return [self replaceEveryOccurrenceOfChars:aString
			withChar:replaceChar caseSensitive:YES];
}

- replaceEveryOccurrenceOfChars:(const char *)aString
		withChar:(char)replaceChar caseSensitive:(BOOL)sense
{
	int i;
	id tempStr;

	if (!aString) return self;
	if (!replaceChar) return nil;  //or return self?

	tempStr = [MiscString newWithString:aString];
	for (i=length-1;i>=0;i--)
		if ([tempStr spotOf:buffer[i] caseSensitive:sense] != -1)
			buffer[i] = replaceChar;

	[tempStr free];
	return self;
}

- replaceEveryOccurrenceOfChars:(const char *)aString withString:(id)sender
{
	if (![sender respondsTo:@selector(stringValue)]) return self;
	return [self replaceEveryOccurrenceOfChars:aString
			with:[sender stringValue] caseSensitive:YES];
}

- replaceEveryOccurrenceOfChars:(const char *)aString
		withString:(id)sender caseSensitive:(BOOL)sense
{
	if (![sender respondsTo:@selector(stringValue)]) return self;
	return [self replaceEveryOccurrenceOfChars:aString
			with:[sender stringValue] caseSensitive:sense];
}

- replaceEveryOccurrenceOfChar:(char)aChar with:(const char *)aString
		caseSensitive:(BOOL)sense
{
	int i;

	if (!aChar) return self; // I think a null string should be allowed here...
	if (sense) {
		for (i=length-1;i>=0;i--)
			if (buffer[i] == aChar)
				[self replaceFrom:i to:i with:aString];
	} else {
		for (i=length-1;i>=0;i--)
			if (NXToUpper(buffer[i]) == NXToUpper(aChar))
				[self replaceFrom:i to:i with:aString];
	}
	return self;
}

- replaceEveryOccurrenceOfChar:(char)aChar with:(const char *)aString
{
	return [self replaceEveryOccurrenceOfChar:aChar
			with:aString caseSensitive:YES];
}

- replaceEveryOccurrenceOfChar:(char)aChar withString:(id)sender
{
	if (![sender respondsTo:@selector(stringValue)]) return self;
	return [self replaceEveryOccurrenceOfChar:aChar
			with:[sender stringValue] caseSensitive:YES];
}

- replaceEveryOccurrenceOfChar:(char)aChar withString:(id)sender
		caseSensitive:(BOOL)sense
{
	if (![sender respondsTo:@selector(stringValue)]) return self;
	return [self replaceEveryOccurrenceOfChar:aChar
			with:[sender stringValue] caseSensitive:sense];
}

- replaceEveryOccurrenceOfChar:(char)aChar withChar:(char)replaceChar
		caseSensitive:(BOOL)sense
{
	int i;

	if (!aChar) return self;
	if (!replaceChar) return nil;  //or return self?

	if (sense) {
		for (i=length-1; i>=0; i--)
			if (buffer[i] == aChar)
				buffer[i] = replaceChar;
	} else {
		for (i=length-1; i>=0; i--)
			if (NXToUpper(buffer[i]) == NXToUpper(aChar))
				buffer[i] = replaceChar;
	}
	return self;
}


- replaceEveryOccurrenceOfChar:(char)aChar withChar:(char)replaceChar
{
	return [self replaceEveryOccurrenceOfChar:aChar
			withChar:replaceChar caseSensitive:YES];
}

// string replacements by Bruce McKenzie <bruce@trwlasd.com>
- replaceEveryOccurrenceOf:(const char *)subString	
	with:(const char *)newString
{
	const char *spot;
	int subStringLen;
	
	if (!subString) return nil;
	subStringLen = strlen(subString);
	if (!subStringLen) return nil;
	while ((spot = [self strstr:subString]))
		[self replaceFrom:(int)(spot-buffer) length:subStringLen
				with:(newString ? newString : "")];
	return self;
}

// and three extra covers by Don Yacktman:
- replaceEveryOccurrenceOfString:(id)subString with:(const char *)newString
{
	return [self replaceEveryOccurrenceOf:[subString stringValue]
				with:newString];
}

- replaceEveryOccurrenceOf:(const char *)subString withString:(id)newString
{
	return [self replaceEveryOccurrenceOf:subString
				with:[newString stringValue]];
}

- replaceEveryOccurrenceOfString:(id)subString withString:(id)newString
{
	return [self replaceEveryOccurrenceOf:[subString stringValue]
				with:[newString stringValue]];
}

@end
