public bool Replace(string input, int startPosition, int endPosition, out int testPosition, out MaskedTextResultHint resultHint)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
if (endPosition >= _testString.Length)
{
testPosition = endPosition;
resultHint = MaskedTextResultHint.PositionOutOfRange;
return false;
//throw new ArgumentOutOfRangeException("endPosition");
}
if (startPosition < 0 || startPosition > endPosition)
{
testPosition = startPosition;
resultHint = MaskedTextResultHint.PositionOutOfRange;
return false;
//throw new ArgumentOutOfRangeException("startPosition");
}
if (input.Length == 0) // remove character at position.
{
return RemoveAt(startPosition, endPosition, out testPosition, out resultHint);
}
// If replacing the entire text with a same-lenght text, we are just setting (not replacing) the test string to the new value;
// in this case we just call SetString.
// If the text length is different than the specified range we would need to remove or insert characters; there are three possible
// cases as follows:
// 1. The text length is the same as edit positions in the range (or no assigned chars): just replace the text, no additional operations needed.
// 2. The text is shorter: replace the text in the text string and remove (range - text.Length) characters.
// 3. The text is larger: replace range count characters and insert (range - text.Length) characters.
// Test input string first and get the last test position to determine what to do.
if (!TestString(input, startPosition, out testPosition, out resultHint))
{
return false;
}
if (_assignedCharCount > 0)
{
// cache out params to preserve the ones from the primary operation (in case of success).
int tempPos;
MaskedTextResultHint tempHint;
if (testPosition < endPosition) // Case 2. Replace + Remove.
{
// Test removing remaining characters.
if (!RemoveAtInt(testPosition + 1, endPosition, out tempPos, out tempHint, /*testOnly*/ false))
{
testPosition = tempPos;
resultHint = tempHint;
return false;
}
// If current result hint is not success (no effect), and character shifting is actually performed, hint = side effect.
if (tempHint == MaskedTextResultHint.Success && resultHint != tempHint)
{
resultHint = MaskedTextResultHint.SideEffect;
}
}
else if (testPosition > endPosition) // Case 3. Replace + Insert.
{
// Test shifting existing characters to make room for inserting part of the input.
int lastAssignedPos = LastAssignedPosition;
int dstPos = testPosition + 1;
int srcPos = endPosition + 1;
while (true)
{
srcPos = FindEditPositionFrom(srcPos, forward);
dstPos = FindEditPositionFrom(dstPos, forward);
if (dstPos == invalidIndex)
{
testPosition = _testString.Length;
resultHint = MaskedTextResultHint.UnavailableEditPosition;
return false;
}
if (!TestChar(_testString[srcPos], dstPos, out tempHint))
{
testPosition = dstPos;
resultHint = tempHint;
return false;
}
// If current result hint is not success (no effect), and character shifting is actually performed, hint = success effect.
if (tempHint == MaskedTextResultHint.Success && resultHint != tempHint)
{
resultHint = MaskedTextResultHint.Success;
}
if (srcPos == lastAssignedPos)
{
break;
}
srcPos++;
dstPos++;
}
// shift test passed, now do it.
while (dstPos > testPosition)
{
SetChar(_testString[srcPos], dstPos);
srcPos = FindEditPositionFrom(srcPos - 1, backward);
dstPos = FindEditPositionFrom(dstPos - 1, backward);
}
}
// else endPosition == testPosition, this means replacing the entire text which is the same as Set().
}
// in all cases we need to replace the input.
SetString(input, startPosition);
return true;
}