private void Overtake(StringBuilder result)
    {
        List <IDriver> drivers = this.racingDriverByName
                                 .Values
                                 .OrderByDescending(driver => driver.TotalTime)
                                 .ToList();

        for (int i = 0; i < drivers.Count - 1; i++)
        {
            IDriver driver      = drivers[i];
            IDriver driverAhead = drivers[i + 1];

            double timeDifference = driver.TotalTime - driverAhead.TotalTime;

            if (timeDifference > 3)
            {
                continue;
            }

            bool isAggressiveDriverOnUltrasoftTyre =
                driver.GetType() == typeof(AggressiveDriver) &&
                driver.Car.Tyre.GetType() == typeof(UltrasoftTyre);
            bool isEnduranceDriverOnHardTyre =
                driver.GetType() == typeof(EnduranceDriver) &&
                driver.Car.Tyre.GetType() == typeof(HardTyre);

            bool isCrashedAggressiveDriver =
                isAggressiveDriverOnUltrasoftTyre &&
                this.weather == Weather.Foggy;
            bool isCrashedEnduranceDriver =
                isEnduranceDriverOnHardTyre &&
                this.weather == Weather.Rainy;

            bool isAggressiveDriverOnUltrasoftTyreOrEnduranceDriverOnHardTyre =
                isAggressiveDriverOnUltrasoftTyre || isEnduranceDriverOnHardTyre;

            if (isCrashedAggressiveDriver || isCrashedEnduranceDriver)
            {
                this.failureReasonByDriver[driver] = Crashed;
                this.racingDriverByName.Remove(driver.Name);
            }
            else if (isAggressiveDriverOnUltrasoftTyreOrEnduranceDriverOnHardTyre ||
                     timeDifference <= 2)
            {
                int interval = isAggressiveDriverOnUltrasoftTyreOrEnduranceDriverOnHardTyre ? 3 : 2;

                driver.AddTime(-interval);
                driverAhead.AddTime(interval);

                result.AppendLine(string.Format(
                                      OvertakeMessage,
                                      driver.Name,
                                      driverAhead.Name,
                                      this.currentLapNumber));

                i++;
            }
        }
    }
    public void DriverBoxes(List <string> commandArgs)
    {
        string reasonToBox = commandArgs[0];
        string driverName  = commandArgs[1];

        IDriver driver = this.racingDriverByName[driverName];

        switch (reasonToBox)
        {
        case ChangeTyres:
            Tyre tyre = this.tyreFactory.CreateTyre(commandArgs.Skip(2).ToArray());

            driver.Car.ChangeTyres(tyre);
            break;

        case Refuel:
            double fuelAmount = double.Parse(commandArgs[2]);

            driver.Car.Refuel(fuelAmount);
            break;
        }

        driver.AddTime(TimeInBox);
    }