/*
Does the same work as splice, but with a slightly more convenient signature. The splice
method has bugs in IE8, so this is the implementation we use on that platform.

The rippling of items in the array can be tricky. Consider two use cases:

index=2
removeCount=2
/=====\
+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+---+
/  \/  \/  \/  \
/   /\  /\  /\   \
/   /  \/  \/  \   +--------------------------+
/   /   /\  /\   +--------------------------+   \
/   /   /  \/  +--------------------------+   \   \
/   /   /   /+--------------------------+   \   \   \
/   /   /   /                             \   \   \   \
v   v   v   v                               v   v   v   v
+---+---+---+---+---+---+       +---+---+---+---+---+---+---+---+---+
| 0 | 1 | 4 | 5 | 6 | 7 |       | 0 | 1 | a | b | c | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+       +---+---+---+---+---+---+---+---+---+
A                               B        \=========/
insert=[a,b,c]

In case A, it is obvious that copying of [4,5,6,7] must be left-to-right so
that we don't end up with [0,1,6,7,6,7]. In case B, we have the opposite; we
must go right-to-left or else we would end up with [0,1,a,b,c,4,4,4,4].
function replaceSim (array, index, removeCount, insert) {
        var add = insert ? insert.length : 0,
            length = array.length,
            pos = fixArrayIndex(array, index),
            remove,
            tailOldPos,
            tailNewPos,
            tailCount,
            lengthAfterRemove,
            i;

        // we try to use Array.push when we can for efficiency...
        if (pos === length) {
            if (add) {
                array.push.apply(array, insert);
            }
        } else {
            remove = Math.min(removeCount, length - pos);
            tailOldPos = pos + remove;
            tailNewPos = tailOldPos + add - remove;
            tailCount = length - tailOldPos;
            lengthAfterRemove = length - remove;

            if (tailNewPos < tailOldPos) { // case A
                for (i = 0; i < tailCount; ++i) {
                    array[tailNewPos+i] = array[tailOldPos+i];
                }
            } else if (tailNewPos > tailOldPos) { // case B
                for (i = tailCount; i--; ) {
                    array[tailNewPos+i] = array[tailOldPos+i];
                }
            } // else, add == remove (nothing to do)

            if (add && pos === lengthAfterRemove) {
                array.length = lengthAfterRemove; // truncate array
                array.push.apply(array, insert);
            } else {
                array.length = lengthAfterRemove + add; // reserves space
                for (i = 0; i < add; ++i) {
                    array[pos+i] = insert[i];
                }
            }
        }

        return array;
    }