/// <summary>
        ///     Create a ColumnPermutation object with a given set of
        ///     visible columns, in the order they should be displayed.
        /// </summary>
        /// <param name="totalColumns">
        ///     The total number of columns that can be visible. This
        ///     should correspond to the ColumnCount on the multicolumn tree.
        /// </param>
        /// <param name="visibleColumns">The columns that are visible.</param>
        /// <param name="preferLeftBlanks">
        ///     If there is a choice, attach blank cells to the
        ///     cell on the right instead of the cell on the left. Generally corresponds to the
        ///     RightToLeft property on the tree control.
        /// </param>
        public ColumnPermutation(int totalColumns, int[] visibleColumns, bool preferLeftBlanks)
        {
            var columns = new int[totalColumns];
            int i;

            // Initialize to -1
            for (i = 0; i < totalColumns; ++i)
            {
                columns[i] = -1;
            }

            // Walk the visibleColumns array and fill in the values. When we're done,
            // if (myColumns[i] != -1) then myVisibleColumns[myColumns[i]] == i
            int targetColumn;
            var visibleColumnCount = visibleColumns.Length;

            for (i = 0; i < visibleColumnCount; ++i)
            {
                targetColumn = visibleColumns[i];
                if (columns[targetColumn] != -1) // Let this throw naturally if the argument is out of range
                {
                    throw new ArgumentException(VirtualTreeStrings.GetString(VirtualTreeStrings.DuplicateColumnException), "visibleColumns");
                }
                columns[targetColumn] = i;
            }

            myColumns = columns;
            if (visibleColumns.IsReadOnly)
            {
                myVisibleColumns = visibleColumns;
            }
            else
            {
                myVisibleColumns = (int[])visibleColumns.Clone();
            }

            myPreferLeftBlanks = preferLeftBlanks;
        }
        /// <summary>
        ///     Change the visible order to match the new order. This allows
        ///     a secondary ordering permutation, such as that used by the header control,
        ///     to work well with our permutation. This routine is optimized to expect a
        ///     single column moving, but will work correctly with any order modification.
        /// </summary>
        /// <param name="oldOrder">The old order, should correspond to the current display order.</param>
        /// <param name="newOrder">The new order. Compare columns to old order to deduce current display order.</param>
        public void ChangeVisibleColumnOrder(int[] oldOrder, int[] newOrder)
        {
            var columns = myVisibleColumns.Length;

            if (oldOrder.Length != columns &&
                newOrder.Length != columns)
            {
                throw new ArgumentException(VirtualTreeStrings.GetString(VirtualTreeStrings.InvalidColumnOrderArrayException));
            }

            // The algorithm finds the old values in the new array and moves a column
            // as soon as it is found. To make an accurate move, this means that the
            // positions that have already moved need to be marked as already processed,
            // so we duplicate the old array to enable writing to it.
            var startOrder = oldOrder.Clone() as int[];
            var startIndex = 0;
            var newIndex   = 0;
            int startCurrent;
            int newCurrent;
            var totalMarked             = 0;
            var permanentlyPassedMarked = 0;

            while (startIndex < columns &&
                   newIndex < columns)
            {
                if (-1 == (startCurrent = startOrder[startIndex]))
                {
                    // Slot already handle, go look for one that hasn't been
                    ++startIndex;
                    ++permanentlyPassedMarked;
                }
                else if (startCurrent == (newCurrent = newOrder[newIndex]))
                {
                    ++startIndex;
                    ++newIndex;
                }
                else
                {
                    // The values are different. The first step is to find the
                    // new value in the old array. We care about the position of
                    // the new value, as well as the number of already handled values
                    // after the located, which can be calculated by seeing how
                    // many marked values we pass on the value.
                    var passedMarked    = 0;
                    var foundStartIndex = -1;
                    int testValue;
                    for (var i = startIndex + 1; i < columns; ++i)
                    {
                        testValue = startOrder[i];
                        if (testValue == newCurrent)
                        {
                            foundStartIndex = i;
                            break;
                        }
                        else if (testValue == -1)
                        {
                            ++passedMarked;
                        }
                    }
                    if (foundStartIndex == -1)
                    {
                        // We're not going to find any more
                        break;
                    }

                    // Update the arrays accordingly
                    MoveVisibleColumn(foundStartIndex + (totalMarked - permanentlyPassedMarked - passedMarked), newIndex);

                    // Mark this node as processed
                    ++totalMarked;
                    startOrder[foundStartIndex] = -1;

                    // Move to next new item
                    ++newIndex;
                }
            }
        }