14b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar/*
24b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * Copyright (C) 2014 The Android Open Source Project
34b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar *
44b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
54b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * you may not use this file except in compliance with the License.
64b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * You may obtain a copy of the License at
74b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar *
84b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
94b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar *
104b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * Unless required by applicable law or agreed to in writing, software
114b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
124b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * See the License for the specific language governing permissions and
144b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar * limitations under the License.
154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar */
164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
174b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarpackage android.support.v7.widget;
184b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
194b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport java.util.List;
204b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
214b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport android.support.v7.widget.AdapterHelper.UpdateOp;
224b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport static android.support.v7.widget.AdapterHelper.UpdateOp.ADD;
234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport static android.support.v7.widget.AdapterHelper.UpdateOp.MOVE;
244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport static android.support.v7.widget.AdapterHelper.UpdateOp.REMOVE;
254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarimport static android.support.v7.widget.AdapterHelper.UpdateOp.UPDATE;
264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyarclass OpReorderer {
284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
294b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    final Callback mCallback;
304b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
314b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    public OpReorderer(Callback callback) {
324b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        mCallback = callback;
334b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
344b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
354b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    void reorderOps(List<UpdateOp> ops) {
364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        // since move operations breaks continuity, their effects on ADD/RM are hard to handle.
374b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        // we push them to the end of the list so that they can be handled easily.
384b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        int badMove;
394b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        while ((badMove = getLastMoveOutOfOrder(ops)) != -1) {
404b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            swapMoveOp(ops, badMove, badMove + 1);
414b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
424b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
434b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private void swapMoveOp(List<UpdateOp> list, int badMove, int next) {
454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        final UpdateOp moveOp = list.get(badMove);
464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        final UpdateOp nextOp = list.get(next);
474b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        switch (nextOp.cmd) {
484b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case REMOVE:
494b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                swapMoveRemove(list, badMove, moveOp, next, nextOp);
504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case ADD:
524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                swapMoveAdd(list, badMove, moveOp, next, nextOp);
534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            case UPDATE:
554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                swapMoveUpdate(list, badMove, moveOp, next, nextOp);
564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                break;
574b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
584b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
594b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
604b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    void swapMoveRemove(List<UpdateOp> list, int movePos, UpdateOp moveOp,
614b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            int removePos, UpdateOp removeOp) {
624b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        UpdateOp extraRm = null;
634b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        // check if move is nulled out by remove
644b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        boolean revertedMove = false;
654b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        final boolean moveIsBackwards;
664b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
674b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (moveOp.positionStart < moveOp.itemCount) {
684b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            moveIsBackwards = false;
694b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            if (removeOp.positionStart == moveOp.positionStart
704b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    && removeOp.itemCount == moveOp.itemCount - moveOp.positionStart) {
714b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                revertedMove = true;
724b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
734b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        } else {
744b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            moveIsBackwards = true;
754b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            if (removeOp.positionStart == moveOp.itemCount + 1 &&
764b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    removeOp.itemCount == moveOp.positionStart - moveOp.itemCount) {
774b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                revertedMove = true;
784b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
794b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
804b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
814b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        // going in reverse, first revert the effect of add
824b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (moveOp.itemCount < removeOp.positionStart) {
834b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            removeOp.positionStart--;
844b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        } else if (moveOp.itemCount < removeOp.positionStart + removeOp.itemCount) {
854b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            // move is removed.
864b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            removeOp.itemCount --;
874b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            moveOp.cmd = REMOVE;
884b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            moveOp.itemCount = 1;
894b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            if (removeOp.itemCount == 0) {
904b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                list.remove(removePos);
914b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                mCallback.recycleUpdateOp(removeOp);
924b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
934b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            // no need to swap, it is already a remove
944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            return;
954b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
964b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
974b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        // now affect of add is consumed. now apply effect of first remove
984b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (moveOp.positionStart <= removeOp.positionStart) {
994b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            removeOp.positionStart++;
1004b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        } else if (moveOp.positionStart < removeOp.positionStart + removeOp.itemCount) {
1014b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            final int remaining = removeOp.positionStart + removeOp.itemCount
1024b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    - moveOp.positionStart;
1034b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            extraRm = mCallback.obtainUpdateOp(REMOVE, moveOp.positionStart + 1, remaining);
1044b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            removeOp.itemCount = moveOp.positionStart - removeOp.positionStart;
1054b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
1064b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
1074b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        // if effects of move is reverted by remove, we are done.
1084b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (revertedMove) {
1094b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            list.set(movePos, removeOp);
1104b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            list.remove(removePos);
1114b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            mCallback.recycleUpdateOp(moveOp);
1124b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            return;
1134b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
1144b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
1154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        // now find out the new locations for move actions
1164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (moveIsBackwards) {
1174b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            if (extraRm != null) {
1184b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                if (moveOp.positionStart > extraRm.positionStart) {
1194b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    moveOp.positionStart -= extraRm.itemCount;
1204b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                }
1214b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                if (moveOp.itemCount > extraRm.positionStart) {
1224b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    moveOp.itemCount -= extraRm.itemCount;
1234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                }
1244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
1254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            if (moveOp.positionStart > removeOp.positionStart) {
1264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                moveOp.positionStart -= removeOp.itemCount;
1274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
1284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            if (moveOp.itemCount > removeOp.positionStart) {
1294b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                moveOp.itemCount -= removeOp.itemCount;
1304b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
1314b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        } else {
1324b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            if (extraRm != null) {
1334b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                if (moveOp.positionStart >= extraRm.positionStart) {
1344b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    moveOp.positionStart -= extraRm.itemCount;
1354b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                }
1364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                if (moveOp.itemCount >= extraRm.positionStart) {
1374b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    moveOp.itemCount -= extraRm.itemCount;
1384b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                }
1394b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
1404b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            if (moveOp.positionStart >= removeOp.positionStart) {
1414b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                moveOp.positionStart -= removeOp.itemCount;
1424b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
1434b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            if (moveOp.itemCount >= removeOp.positionStart) {
1444b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                moveOp.itemCount -= removeOp.itemCount;
1454b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
1464b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
1474b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
1484b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        list.set(movePos, removeOp);
1494b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (moveOp.positionStart != moveOp.itemCount) {
1504b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            list.set(removePos, moveOp);
1514b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        } else {
1524b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            list.remove(removePos);
1534b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
1544b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (extraRm != null) {
1554b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            list.add(movePos, extraRm);
1564b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
1574b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1584b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
1594b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private void swapMoveAdd(List<UpdateOp> list, int move, UpdateOp moveOp, int add,
1604b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            UpdateOp addOp) {
1614b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        int offset = 0;
1624b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        // going in reverse, first revert the effect of add
1634b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (moveOp.itemCount < addOp.positionStart) {
1644b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            offset--;
1654b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
1664b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (moveOp.positionStart < addOp.positionStart) {
1674b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            offset++;
1684b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
1694b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (addOp.positionStart <= moveOp.positionStart) {
1704b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            moveOp.positionStart += addOp.itemCount;
1714b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
1724b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (addOp.positionStart <= moveOp.itemCount) {
1734b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            moveOp.itemCount += addOp.itemCount;
1744b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
1754b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        addOp.positionStart += offset;
1764b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        list.set(move, addOp);
1774b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        list.set(add, moveOp);
1784b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
1794b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
1804b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    void swapMoveUpdate(List<UpdateOp> list, int move, UpdateOp moveOp, int update,
1814b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            UpdateOp updateOp) {
1824b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        UpdateOp extraUp1 = null;
1834b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        UpdateOp extraUp2 = null;
1844b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        // going in reverse, first revert the effect of add
1854b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (moveOp.itemCount < updateOp.positionStart) {
1864b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            updateOp.positionStart--;
1874b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        } else if (moveOp.itemCount < updateOp.positionStart + updateOp.itemCount) {
1884b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            // moved item is updated. add an update for it
1894b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            updateOp.itemCount--;
1904b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            extraUp1 = mCallback.obtainUpdateOp(UPDATE, moveOp.positionStart, 1);
1914b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
1924b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        // now affect of add is consumed. now apply effect of first remove
1934b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (moveOp.positionStart <= updateOp.positionStart) {
1944b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            updateOp.positionStart++;
1954b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        } else if (moveOp.positionStart < updateOp.positionStart + updateOp.itemCount) {
1964b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            final int remaining = updateOp.positionStart + updateOp.itemCount
1974b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    - moveOp.positionStart;
1984b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            extraUp2 = mCallback.obtainUpdateOp(UPDATE, moveOp.positionStart + 1, remaining);
1994b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            updateOp.itemCount -= remaining;
2004b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2014b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        list.set(update, moveOp);
2024b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (updateOp.itemCount > 0) {
2034b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            list.set(move, updateOp);
2044b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        } else {
2054b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            list.remove(move);
2064b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            mCallback.recycleUpdateOp(updateOp);
2074b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2084b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (extraUp1 != null) {
2094b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            list.add(move, extraUp1);
2104b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2114b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        if (extraUp2 != null) {
2124b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            list.add(move, extraUp2);
2134b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2144b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2154b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
2164b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    private int getLastMoveOutOfOrder(List<UpdateOp> list) {
2174b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        boolean foundNonMove = false;
2184b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        for (int i = list.size() - 1; i >= 0; i--) {
2194b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            final UpdateOp op1 = list.get(i);
2204b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            if (op1.cmd == MOVE) {
2214b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                if (foundNonMove) {
2224b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                    return i;
2234b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                }
2244b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            } else {
2254b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar                foundNonMove = true;
2264b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar            }
2274b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        }
2284b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        return -1;
2294b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2304b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
2314b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    static interface Callback {
2324b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
2334b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        UpdateOp obtainUpdateOp(int cmd, int startPosition, int itemCount);
2344b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar
2354b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar        void recycleUpdateOp(UpdateOp op);
2364b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar    }
2374b9b4d3fca81486051bac9aadb73d8865948c3bfYigit Boyar}
238