/// <summary>
        ///     Parses the input, returning the facilities and customers
        /// </summary>
        /// <returns> A tuple containing the facilities and customers</returns>
        /// <param name="args">The Command-line arguments.</param>
        public static Tuple<Facility[], Customer[]> ParseInput(string[] args)
        {
            string fileName = null;

            // get the temp file name
            foreach (var arg in args.Where(arg => arg.StartsWith("-file=")))
            {
                fileName = arg.Substring(6);
            }
            if (fileName == null)
                return Tuple.Create(new Facility[0], new Customer[0]);

            // read the lines out of the file
            var lines = File.ReadAllLines(fileName);


            // parse the data in the file
            var firstLine = lines[0].Split(' ');
            int facilityCount = int.Parse(firstLine[0]);
            int customerCount = int.Parse(firstLine[1]);

            // build up facility and customer arrays
            var facilities = new Facility[facilityCount];
            var customers = new Customer[customerCount];

            // populate the facilities
            for (int i = 1; i < facilityCount + 1; i++)
            {
                var line = lines[i];
                var parts = line.Split(' ');
                var facility = new Facility(i - 1)
                {
                    SetupCost = double.Parse(parts[0], CultureInfo.InvariantCulture),
                    Capacity = int.Parse(parts[1]),
                    X = double.Parse(parts[2], CultureInfo.InvariantCulture),
                    Y = double.Parse(parts[3], CultureInfo.InvariantCulture)
                };
                facilities[i - 1] = facility;
            }

            var offset = 1 + facilityCount;

            // populate the customers
            for (int i = offset; i < offset + customerCount; i++)
            {
                var line = lines[i];
                var parts = line.Split(' ');
                var customer = new Customer(i - offset)
                {
                    Demand = int.Parse(parts[0]),
                    X = double.Parse(parts[1], CultureInfo.InvariantCulture),
                    Y = double.Parse(parts[2], CultureInfo.InvariantCulture)
                };
                customers[i - offset] = customer;
            }

            return Tuple.Create(facilities, customers);
        }
            public void FixIt(Facility[] facilities, Customer[] customers)
            {
                var sortedByAssignedCount = facilities.OrderBy(f => f.AssignedFacilityCount);

                Console.WriteLine("");
                Console.WriteLine("***********");
                foreach (var facility in sortedByAssignedCount)
                {
                    Console.WriteLine("{0} {1} {2} {3}", facility.Id, facility.AssignedFacilityCount, facility.Capacity, facility.AvailableCapacity);
                }
            }
        public void Execute(Facility[] facilities, Customer[] customers)
        {
            foreach (var customer in customers)
            {
                var first = facilities.FirstOrDefault(f => f.CanAssignCustomer(customer));
                if (first == null) throw new Exception("something went wrong");

                var actual = facilities.Aggregate(first, (curr, next) =>
                    {
                        if (!next.CanAssignCustomer(customer)) return curr;
                        if (next.Location.DistanceFrom(customer.Location) < curr.Location.DistanceFrom(customer.Location))
                            return next;
                        return curr;
                    });

                if (actual == null) throw new Exception("something else went wrong");
                if (!actual.CanAssignCustomer(customer)) throw new Exception("couldn't find one...");

                actual.AssignCustomer(customer);
            }
        }
        public SolutionResult Solve(Facility[] facilities, Customer[] customers)
        {
            var result = new SolutionResult(customers);

            var fIndex = 0;
            var remainingCapacity = facilities[fIndex].Capacity;
            var facility = facilities[fIndex];

            // trivially just add while they fit
            foreach (var customer in customers)
            {
                while (customer.Demand > remainingCapacity)
                {
                    facility = facilities[++fIndex];
                    remainingCapacity = facility.Capacity;
                }
                result.Map(customer, facility);
                remainingCapacity -= customer.Demand;
            }

            return result;
        }
        /// <summary>
        /// Map the specified customer and facility.
        /// </summary>
        /// <param name="customer">Customer.</param>
        /// <param name="facility">Facility.</param>
        public void Map(Customer customer, Facility facility)
        {           
            Facility oldFacility;

            // get rid of the old one
            if (customerToFacility.TryGetValue(customer, out oldFacility))
            {
                facilityToCustomers[oldFacility].Remove(customer);
            }
            customerToFacility[customer] = facility;
        
            // unmap existing one if it's there
            facilityToCustomers.Add(facility, customer);

            // force recalculation
            value = null;
        }
 /// <summary>
 /// Calculate the distance between a facility and customer
 /// </summary>
 /// <param name="f">Facility.</param>
 /// <param name="c">Customer.</param>
 public static double Distance(Facility f, Customer c)
 {
     var dx = f.X - c.X;
     var dy = f.Y - c.Y;
     return Math.Sqrt(dx * dx + dy * dy);
 }