private static void UploadTrackingDataAndFlushBuffer()
 {
     if (bufferedTrackedPositions == null)
         return;
     if (bufferedTrackedPositions.Count == 0)
         return;
                 
     //copy tracking data and clear buffer
     TrackedPosition[] tmp;
     lock (bufferedTrackedPositionsLock)
     {
         int numPositions = bufferedTrackedPositions.Count;
         tmp = new TrackedPosition[numPositions];
         bufferedTrackedPositions.CopyTo(tmp);
         bufferedTrackedPositions.Clear();
     }
     
     radiomapEntities context = new radiomapEntities(radiomapUri);
     foreach (TrackedPosition pos in tmp)
     {
         context.AddToTrackedPositions(pos);
     }
     context.BeginSaveChanges(SaveChangesOptions.Batch, OnPositionEstimatesSaved, context);
     
 }
        /// <summary>
        /// Both the sniffer backend and radiomap backend define a PositionEstimate entity. 
        /// Therefore, we convert WifiSniffer position estimates to radiomap position-estimates when 
        /// we save tracking data to the radio map backend (which houses the tracking data as well)
        /// </summary>
        /// <param name="?"></param>
        /// <returns></returns>
        private static TrackedPosition CreateTrackedPosition(WifiSnifferPositioningService.PositionEstimate org)
        {
            TrackedPosition res = new TrackedPosition();
            
            res.Accuracy = org.Accuracy;
            res.Altitude = org.Altitude;
            res.Bearing = org.Bearing;
            res.Building_ID = org.Building_ID;
            res.HasAccuracy = org.HasAccuracy;
            res.HasBearing = org.HasBearing;
            res.HasSpeed = org.HasSpeed;
            res.Latitude = org.Latitude;
            res.Longitude = org.Longitude;
            res.Provider = org.Provider;
            res.Speed = org.Speed;
            res.Time = DateTime.Now; //org.Time;
            res.VertexID = org.VertexID;
            res.ClientID = ClientId; //A guid

            return res;
        }
        private static TrackedPosition CreateTrackedPosition(System.Device.Location.GeoCoordinate org)
        {
            TrackedPosition res = new TrackedPosition();
            //NaN numbers cause an exception on MSSQL Server so they must be avoided.
            
            bool hasAccuracy = false;
            bool hasBearing = false;
            bool hasSpeed = false;
            if (!double.IsNaN(org.HorizontalAccuracy))
            {
                res.Accuracy = org.HorizontalAccuracy;
                hasAccuracy = true;
            }
            if (!double.IsNaN(org.Course))
            {
                res.Bearing = org.Course;
                hasBearing = true;
            }
            if (!double.IsNaN(org.Speed))
            {
                res.Speed = org.Speed;
                hasSpeed = true;
            }
            //res.Building_ID = -1;
           
            //Latitude, longitude, altitude are non-nullable (but should also never be NaN's)
            const double errorVal = -999;
            res.Latitude = !double.IsNaN(org.Latitude) ? org.Latitude : errorVal;
            res.Longitude = !double.IsNaN(org.Longitude) ? org.Longitude : errorVal;
            res.Altitude = !double.IsNaN(org.Altitude) ? org.Altitude : errorVal;
            
            res.Provider = "MS Location API (GPS)";
            res.Time = DateTime.Now;
            //res.VertexID = -1;
            res.HasAccuracy = hasAccuracy;
            res.HasBearing = hasBearing;
            res.HasSpeed = hasSpeed;
            res.ClientID = ClientId; //A guid

            return res;
        }
 /// <summary>
 /// Add a position estimate to the buffer of tracked positions. 
 /// When the buffer is full, the data are flushed to the backend
 /// </summary>
 /// <param name="pos"></param>
 private static void AddToTrackedPositions(TrackedPosition pos)
 {
     // Wi-Fi and GPS can potentially be adding at the same time so we lock the buffer.
     lock (bufferedTrackedPositionsLock)
     {
         bufferedTrackedPositions.Add(pos);
     }
     if (IsTimeToSendTrackingData())
     {
         UploadTrackingDataAndFlushBuffer();
     }    
 }