public void TestMethod01()
        {
            CalculationRequest request = new CalculationRequest()
            {
                Students = new List<Student>()
                {
                    new Student {
                        Name = "Jack", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "Gas", Amount = 40m},
                            new Expense() { Name = "Store", Amount = 50m},
                        }
                    },
                    new Student {
                        Name = "Charlie", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "Sun screen", Amount = 10m},
                            new Expense() { Name = "Beer", Amount = 150m},
                        }
                    },
                }
            };

            CalculationResponse response = CalculationService.CalculateExpenses(request);

            Assert.AreEqual(1, response.PaymentsDue.Count);
            Assert.AreEqual(35m, response.PaymentsDue[0].Amount);
            Assert.AreEqual("Jack", response.PaymentsDue[0].From);
            Assert.AreEqual("Charlie", response.PaymentsDue[0].To);
        }
        public static CalculationResponse CalculateExpenses(CalculationRequest request)
        {
            CalculationResponse response = new CalculationResponse();

            if (request == null || request.Students == null || !request.Students.Any())
            {
                throw new ArgumentException("No students in request");
            }
            decimal costPerStudent = decimal.Round(request.Students.Sum(st => st.TotalPaid) / request.Students.Count, 2);

            //todo: come up with a more elegant way to check if all students are all paid up or within $.01.
            //todo: This same statement is used down in the "while" clause. Centralize it.
            if (request.Students.All(student => student.TotalPaid >= (costPerStudent - .01m) && student.TotalPaid <= (costPerStudent + .01m)))
            {
                //all students are paid already, no need to continue here.
                return response;
            }

            do
            {
                request.Students = request.Students.OrderBy(st => st.TotalPaid).ToList();
                Student smallestContributer = request.Students.First();
                Student biggestContributer = request.Students.Last();
                decimal contributionAmt = Math.Min(biggestContributer.TotalPaid - costPerStudent,
                    costPerStudent - smallestContributer.TotalPaid);

                smallestContributer.Expenses.Add(new Expense { Amount = contributionAmt, Name = string.Format("Payment to {0}", biggestContributer.Name)});
                biggestContributer.Expenses.Add(new Expense { Amount = contributionAmt * -1, Name = string.Format("Payment from {0}", smallestContributer.Name)});
                response.PaymentsDue.Add(new Payment { Amount = contributionAmt, From = smallestContributer.Name, To = biggestContributer.Name});
            } while (!request.Students.All(student => student.TotalPaid >= (costPerStudent - .01m) && student.TotalPaid <= (costPerStudent + .01m)));

            return response;
        }
 public CalculationResponse CalculateExpenses(CalculationRequest request)
 {
     return CalculationService.CalculateExpenses(request);
 }
        public void TestMethod03()
        {
            CalculationRequest request = new CalculationRequest()
            {
                Students = new List<Student>()
                {
                    new Student {
                        Name = "Jack", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "Gas", Amount = 40m},
                            new Expense() { Name = "Store", Amount = 10m},
                        }
                    },
                    new Student {
                        Name = "Charlie", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "Sun screen", Amount = 10m},
                            new Expense() { Name = "Beer", Amount = 50m},
                        }
                    },
                    new Student {
                        Name = "Loren", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "More beer", Amount = 80m},
                            new Expense() { Name = "Limes", Amount = 40m},
                        }
                    },
                    new Student {
                        Name = "Zach", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "Aspirin", Amount = 5m},
                            new Expense() { Name = "Gatorade", Amount = 5m},
                        }
                    },
                }
            };

            CalculationResponse response = CalculationService.CalculateExpenses(request);

            Assert.AreEqual(2, response.PaymentsDue.Count);

            Assert.AreEqual(50m, response.PaymentsDue[0].Amount);
            Assert.AreEqual("Zach", response.PaymentsDue[0].From);
            Assert.AreEqual("Loren", response.PaymentsDue[0].To);

            Assert.AreEqual(10m, response.PaymentsDue[1].Amount);
            Assert.AreEqual("Jack", response.PaymentsDue[1].From);
            Assert.AreEqual("Loren", response.PaymentsDue[1].To);
        }
        public void TestMethod08()
        {
            CalculationRequest request = new CalculationRequest()
            {
                Students = new List<Student>()
                {
                    new Student {
                        Name = "Jack", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "Gas", Amount = 3m}
                        }
                    },
                    new Student {
                        Name = "Charlie", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "Sun screen", Amount = 2m}
                        }
                    },
                    new Student {
                        Name = "Loren", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "More beer", Amount = 5m}
                        }
                    },
                }
            };

            CalculationResponse response = CalculationService.CalculateExpenses(request);

            Assert.AreEqual(2, response.PaymentsDue.Count);

            Assert.AreEqual(1.33m, response.PaymentsDue[0].Amount);
            Assert.AreEqual("Charlie", response.PaymentsDue[0].From);
            Assert.AreEqual("Loren", response.PaymentsDue[0].To);

            Assert.AreEqual(.33m, response.PaymentsDue[1].Amount);
            Assert.AreEqual("Jack", response.PaymentsDue[1].From);
            Assert.AreEqual("Loren", response.PaymentsDue[1].To);
        }
        public void TestMethod07()
        {
            CalculationRequest request = new CalculationRequest()
            {
                Students = new List<Student>()
                {
                    new Student {
                        Name = "Jack", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "Gas", Amount = 1m},
                        }
                    },
                    new Student {
                        Name = "Charlie", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "Sun screen", Amount = 1m},
                        }
                    },
                    new Student {
                        Name = "Loren", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "Vitamins", Amount = 3m},
                        }
                    },
                    new Student {
                        Name = "Zach", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "Aspirin", Amount = 3m},
                            new Expense() { Name = "Gatorade", Amount = 3m},
                            new Expense() { Name = "Beef Jerkey", Amount = 4m},
                        }
                    },
                    new Student {
                        Name = "Ian", Expenses = new List<Expense>
                        {
                            new Expense() { Name = "Chips. Lots of chips", Amount = 10m}
                        }
                    },
                }
            };

            CalculationResponse response = CalculationService.CalculateExpenses(request);

            Assert.AreEqual(4, response.PaymentsDue.Count);

            Assert.AreEqual(4m, response.PaymentsDue[0].Amount);
            Assert.AreEqual("Jack", response.PaymentsDue[0].From);
            Assert.AreEqual("Ian", response.PaymentsDue[0].To);

            Assert.AreEqual(4m, response.PaymentsDue[1].Amount);
            Assert.AreEqual("Charlie", response.PaymentsDue[1].From);
            Assert.AreEqual("Zach", response.PaymentsDue[1].To);

            Assert.AreEqual(1m, response.PaymentsDue[2].Amount);
            Assert.AreEqual("Loren", response.PaymentsDue[2].From);
            Assert.AreEqual("Zach", response.PaymentsDue[2].To);

            Assert.AreEqual(1m, response.PaymentsDue[3].Amount);
            Assert.AreEqual("Loren", response.PaymentsDue[3].From);
            Assert.AreEqual("Ian", response.PaymentsDue[3].To);
        }
        public void TestMethod06()
        {
            CalculationRequest request = new CalculationRequest()
            {
                Students = new List<Student>()
            };

            CalculationResponse response = CalculationService.CalculateExpenses(request);

            Assert.AreEqual(0, response.PaymentsDue.Count);
        }
        public void TestMethod05()
        {
            CalculationRequest request = new CalculationRequest()
            {
                Students = new List<Student>()
                {
                    new Student
                    {
                        Name = "Jack",
                        Expenses = new List<Expense>
                        {
                            new Expense() {Name = "Gas", Amount = 5m},
                            new Expense() {Name = "Store", Amount = 5m},
                        }
                    },
                    new Student
                    {
                        Name = "Charlie",
                        Expenses = new List<Expense>
                        {
                            new Expense() {Name = "Sun screen", Amount = 7m},
                            new Expense() {Name = "Beer", Amount = 3m},
                        }
                    },
                    new Student
                    {
                        Name = "Loren",
                        Expenses = new List<Expense>
                        {
                            new Expense() {Name = "More beer", Amount = 3m},
                            new Expense() {Name = "Limes", Amount = 4m},
                            new Expense() {Name = "More Lime", Amount = 3m},
                        }
                    },
                }
            };

            CalculationResponse response = CalculationService.CalculateExpenses(request);

            Assert.AreEqual(0, response.PaymentsDue.Count);
        }