/// <summary>
        /// Buys good via barter.
        /// </summary>
        /// <param name="buyerStock">The buyer's goods up for trade.</param>
        /// <param name="good">The good being traded for.</param>
        /// <param name="amount">The amount of the good being bought.</param>
        /// <param name="market">The market that the barter is taking place in.</param>
        /// <returns>The resulting change in goods for the buyer.</returns>
        public IProductAmountCollection BarterGood(IProductAmountCollection buyerStock,
                                                   IProduct good, double amount, IMarket market)
        {
            // TODO, update to use the coincidence of wants,
            // it will discourage barter more than anything.
            if (buyerStock == null)
            {
                throw new ArgumentNullException(nameof(buyerStock));
            }
            if (good == null)
            {
                throw new ArgumentNullException(nameof(good));
            }
            if (market == null)
            {
                throw new ArgumentNullException(nameof(market));
            }
            if (amount <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(amount));
            }

            // the return result of the barter
            var result = new ProductAmountCollection();

            // TODO a barter modifier, to discourage or encourage bartering.
            // This should become more flexible later.
            var BarterMod = 1;

            // Get how much we can or want to get
            amount = Math.Min(amount, ForSale.GetProductValue(good));

            // get the price of the good.
            var totalPrice = GetPrice(good, market.GetPrice(good)) * amount * BarterMod;

            // get the total price of what's offered.
            double barterVal = 0;

            foreach (var product in buyerStock)
            {
                barterVal += market.GetPrice(product.Item1) * product.Item2;
            }

            // the barter we're trading for the goods.
            IProductAmountCollection barter;

            // if the available barter is greater than the price, begin bartering
            if (barterVal >= totalPrice)
            {
                // Use get change for the easiest option.
                barter = market.ChangeForPrice(buyerStock, totalPrice);

                // don't go more accurate, barter isn't supposed to be more accurate to coins,
                // no one would accept change in bits of wheat.

                // Add the goods being bought
                result.AddProducts(good, amount);

                // Remove the goods being traded.
                result.AddProducts(barter.Multiply(-1));
            }
            else
            {
                // if it's not enough, throw it all in, and buy what you can.
                double buyableUnits = 0;

                // if the good is fractional
                if (good.Fractional)
                {
                    // just divide
                    buyableUnits = barterVal / (market.GetPrice(good) * BarterMod);
                }
                else
                {
                    // round down
                    buyableUnits = Math.Floor(barterVal / (market.GetPrice(good) * BarterMod));
                }

                // If we can buy anything, do so.
                if (buyableUnits > 0)
                {
                    // add the goods
                    result.AddProducts(good, buyableUnits);
                    // subtract the goods
                    result.AddProducts(buyerStock.Multiply(-1));
                }
            }

            // No change, this is bartering.

            // We've done what we can, move on.
            return(result);
        }
        public IProductAmountCollection BuyGood(IProductAmountCollection cash,
                                                IProduct good, double amount, IMarket market)
        {
            // Sanity check for nulls.
            if (cash is null)
            {
                throw new ArgumentNullException(nameof(cash));
            }
            if (good is null)
            {
                throw new ArgumentNullException(nameof(good));
            }
            if (market is null)
            {
                throw new ArgumentNullException(nameof(market));
            }
            if (amount <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(amount));
            }

            // The collection we're returning.
            var result = new ProductAmountCollection();

            // get how much to buy, what's available, or what's desired.
            var available = Math.Min(amount, ForSale.GetProductValue(good));

            // get the price of that good
            var totalPrice = GetPrice(good, market.GetPrice(good)) * available;

            // get the cash needed for the goods
            var money = market.ChangeForPrice(cash, totalPrice);

            // get our available money total
            var totalMoney = money.Sum(x => market.GetPrice(x.Item1, x.Item2));

            // if the money is enough, just buy outright
            if (totalMoney >= totalPrice)
            {
                // Add what they're buying.
                result.AddProducts(good, available);
                // remove what they spent
                result.AddProducts(money.Multiply(-1));
            }
            else if (!good.Fractional && totalMoney < market.GetPrice(good))
            {// If the total money is not enough for a single unit, and the good can't be divided
                // we can't actually buy anything, so just return an empty transaction
                return(new ProductAmountCollection());
            }
            else // if it's not enough
            {
                // get the buyable units of the good
                double buyableUnits = 0;

                // if we can buy fractionally
                if (good.Fractional)
                {
                    // just do the math straight.
                    buyableUnits = totalMoney / market.GetPrice(good);
                }
                else // if we can't
                {
                    // take what we can and round down, seller should always make more than the buyer here.
                    buyableUnits = Math.Floor(totalMoney / market.GetPrice(good));
                }

                // if we can buy any units
                if (buyableUnits > 0)
                {
                    // buy them add the units to the results
                    result.AddProducts(good, buyableUnits);
                    // subtract the cash.
                    result.AddProducts(money.Multiply(-1));
                }
            }

            // Get change, if any.
            var change = totalMoney - market.GetPrice(good) * result.GetProductValue(good);

            // get the change, if any
            IProductAmountCollection buyersChange = new ProductAmountCollection();

            // if change is greater than 0.
            if (change > 0) // Make said change.
            {
                buyersChange = market.ChangeForPrice(GetCash(market.AcceptedCurrencies), change);
            }

            // add back the buyer's change
            result.AddProducts(buyersChange);

            // TODO, maybe add check to see if the seller shortchanged the buyer.

            // complete the transaction for the seller, and subtract the result.
            CompleteTransaction(result.Multiply(-1));

            // we're done, return the change in the buyer's goods.
            return(result);
        }