/*
         * public static bool RemoveFromA_AddToB(
         *  IItemContainer containerA, int idxA,
         *  IItemContainer containerB)
         * {
         *  // verify idxA
         *  if (IsNotInRange(idxA, containerA.Size)) return false;
         *  var id = containerA.Provider.GetId(idxA);
         *
         *  // calc changes
         *  var remFromA = ItemChangeInfo.Remove(idxA);
         *  var addToB = containerB.CalcChangeInfo(id,
         *      containerA.Provider.GetAmount(idxA));
         *
         *  // verify add to b
         *  if (!addToB.IsValid && addToB.OverflowAmount != 0) return false;
         *
         *  // execute
         *  if (!SafeDoubleInfoExecute(
         *      containerA, remFromA,
         *      containerB, addToB)) return false;
         *
         *  return true;
         * }
         */

        // TODO : write tests for InterManagerSwap

        /// <summary>
        /// Swaps items between two containers without preserving the item indicies.
        /// </summary>
        /// <returns>True on success, false otherwise</returns>
        public static bool InterManagerSwap(
            IItemContainer containerA, int idxA,
            IItemContainer containerB, int idxB)
        {
            // if idxB is null, find either an item idx with the same id or an empty slot.

            // validate indicies
            if (IsNotInRange(idxA, containerA.Provider.Count))
            {
                return(false);
            }
            if (IsNotInRange(idxB, containerB.Provider.Count))
            {
                return(false);
            }

            // get items
            var itemA = containerA.Provider[idxA];
            var itemB = containerB.Provider[idxB];

            // calc change info
            // add A to containerB
            var cAtoB = containerB.CalcChangeInfo(itemA);
            // add B to containerA
            var cBtoA = containerA.CalcChangeInfo(itemB);

            // operation is undefinied if any changeInfo's are invalid or have overflow, return false
            bool IsInvalidChangeInfo(ref ItemChangeInfo info)
            => !info.IsValid || info.OverflowAmount != 0;

            if (IsInvalidChangeInfo(ref cAtoB))
            {
                return(false);
            }
            if (IsInvalidChangeInfo(ref cBtoA))
            {
                return(false);
            }

            // managed remove A and B
            if (!SafeDoubleInfoExecute(
                    containerA, ItemChangeInfo.Remove(idxA),
                    containerB, ItemChangeInfo.Remove(idxB)))
            {
                return(false);
            }

            // execute change infos we calculated earlier
            if (!SafeDoubleInfoExecute(
                    containerA, cBtoA,
                    containerB, cAtoB))
            {
                return(false);
            }

            return(true);
        }