public void Add(int key, CarInformation value)
 {
     _cacheLock.EnterWriteLock();
     try
     {
         _innerCache.Add(key, value);
     }
     finally
     {
         _cacheLock.ExitWriteLock();
     }
 }
 public AddOrUpdateStatus AddOrUpdate(int key, CarInformation value)
 {
     _cacheLock.EnterUpgradeableReadLock();
     try
     {
         if (_innerCache.TryGetValue(key, out var result))
         {
             if (result == value)
             {
                 return(AddOrUpdateStatus.Unchanged);
             }
             else
             {
                 _cacheLock.EnterWriteLock();
                 try
                 {
                     _innerCache[key] = value;
                 }
                 finally
                 {
                     _cacheLock.ExitWriteLock();
                 }
                 return(AddOrUpdateStatus.Updated);
             }
         }
         else
         {
             _cacheLock.EnterWriteLock();
             try
             {
                 _innerCache.Add(key, value);
             }
             finally
             {
                 _cacheLock.ExitWriteLock();
             }
             return(AddOrUpdateStatus.Added);
         }
     }
     finally
     {
         _cacheLock.ExitUpgradeableReadLock();
     }
 }
 public bool AddWithTimeout(int key, CarInformation value, int timeout)
 {
     if (_cacheLock.TryEnterWriteLock(timeout))
     {
         try
         {
             _innerCache.Add(key, value);
         }
         finally
         {
             _cacheLock.ExitWriteLock();
         }
         return(true);
     }
     else
     {
         return(false);
     }
 }
        /// <summary>
        /// Get the last known location and calculate speed. Then Publish back to the MQTT Broker.
        /// </summary>
        /// <param name="mqttClient">The MQTT Client</param>
        /// <param name="topic">The most recent topic</param>
        /// <returns>A Task which performs the operation</returns>
        public async Task Work(IManagedMqttClient mqttClient, CarCoordinates topic)
        {
            try
            {
                // Get lastCoordinate from key
                var carInformation = _carCache.Read(topic.CarIndex);

                // Get Geo coordinate
                var lastGeoCoordinate    = new GeoCoordinate(carInformation.LastLocation.Latitude, carInformation.LastLocation.Longitude);
                var currentGeoCoordinate = new GeoCoordinate(topic.Location.Latitude, topic.Location.Longitude);

                // Calculate the distance and the speed
                var distance = lastGeoCoordinate.GetDistanceTo(currentGeoCoordinate);
                var speed    = Speedometer.CalculateSpeedMph(distance, carInformation.LastRecordedTimestamp,
                                                             topic.TimeStamp);

                // using the total distance driven
                var carValues = _carCache.Values().ToList();
                var position  = carValues.OrderByDescending(x => x.TotalDistanceTraveled)
                                .Select(x => x.CarIndex).ToList().IndexOf(topic.CarIndex) + 1;

                //  has the car position changed
                if (position != carInformation.Position)
                {
                    //  who is now in that position?
                    var carInPreviousPos = carValues.FirstOrDefault(x => x.Position == position);

                    if (carInPreviousPos != null)
                    {
                        var eventStatus = new EventMessage()
                        {
                            Timestamp = topic.TimeStamp,
                            Text      =
                                $"Car {carInPreviousPos.CarIndex} races ahead of Car {carInformation.CarIndex} in a dramatic overtake."
                        };
                        var messageEvent = MessageBuilder.CreateMessage(eventStatus);

                        //  send event for the overtake
                        await mqttClient.PublishAsync(messageEvent);
                    }
                }

                // Set information car information
                carInformation.TotalDistanceTraveled += distance;
                carInformation.LastRecordedTimestamp  = topic.TimeStamp;
                carInformation.LastLocation           = topic.Location;
                carInformation.Position = position;
                _carCache.AddOrUpdate(topic.CarIndex, carInformation);

                // The response
                var messageSpeed    = MessageBuilder.CreateMessage(CarStatus.SpeedStatus(topic, speed));
                var messagePosition = MessageBuilder.CreateMessage(CarStatus.PositionStatus(topic, position));

                await mqttClient.PublishAsync(messageSpeed);

                await mqttClient.PublishAsync(messagePosition);
            }
            catch (KeyNotFoundException)
            {
                // Must be first time round, add topic to dictionary
                var carInformation = new CarInformation()
                {
                    LastLocation          = topic.Location,
                    LastRecordedTimestamp = topic.TimeStamp,
                    Position = 0,
                    TotalDistanceTraveled = 0,
                    CarIndex = topic.CarIndex
                };

                _carCache.AddOrUpdate(topic.CarIndex, carInformation);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.ToString());
            }
        }