public void AddPosition(Position position)
        {
            if (_positions.Any())
            {
                var previousPosition = _positions.Last();

                position.DinstanceToPrevious = previousPosition.GeoCoordinate.GetDistanceTo(position.GeoCoordinate);

                if (position.Accuracy < MinimumAccuracyToCalculateSpeed)
                {
                    var secondsBetween = (position.DateTime - previousPosition.DateTime).TotalSeconds;
                    position.Speed = position.DinstanceToPrevious / secondsBetween;
                }
            }
            _positions.Add(position);
            CleanupPositions();
        }
        /// <returns>Returns null if exited Stationary modus, else returns Report Interval in milliseconds (lazy or aggressive)</returns>
        public double? GetNewReportInterval(Position newPosition)
        {
            if (_previousPosition == null) // first position-update in stationary, always aggresive
            {
                _previousPosition = newPosition;
                return _stationaryPollingIntervalAggresive.TotalMilliseconds;
            }

            var distance = GetDistanceToStationary(newPosition);
            if (distance > _stationaryRadius)
            {
                // exit stationary
                _stationaryPosition = null;
                _stationaryGeocoordinate = null;
                return null;
            }
            var percentage = distance / _stationaryRadius;

            return percentage < 0.5 ? _stationaryPollingIntervalLazy.TotalMilliseconds : _stationaryPollingIntervalAggresive.TotalMilliseconds;
        }
        private StationaryUpdateResult StationaryUpdate(Geoposition geoPosition, Position newPosition)
        {
            if (!_stationaryManager.InStationary) return StationaryUpdateResult.NotInStationary;

            var newStationaryReportInterval = _stationaryManager.GetNewReportInterval(newPosition);

            if (!newStationaryReportInterval.HasValue || !_stationaryManager.InStationary) return StationaryUpdateResult.ExitedFromStationary;

            PositionChanged(this, new GeolocatorWrapperPositionChangedEventArgs
            {
                GeolocatorLocationStatus = Geolocator.LocationStatus,
                Position = geoPosition,
                PositionUpdateDebugData =
                    PostionUpdateDebugData.ForStationaryUpdate((uint)newStationaryReportInterval,
                        _stationaryManager.GetDistanceToStationary(newPosition))
            });

            // stay in stationary
            UpdateReportInterval((uint)newStationaryReportInterval);

            return StationaryUpdateResult.InStationary;
        }
        private void OnGeolocatorPositionChanged(Geolocator sender, PositionChangedEventArgs positionChangesEventArgs)
        {
            if (_skipNextPosition)
            {
                _skipNextPosition = false;
                return;
            }

            var newGeoCoordinate = new GeoCoordinate(positionChangesEventArgs.Position.Coordinate.Latitude, positionChangesEventArgs.Position.Coordinate.Longitude);
            var newPosition = new Position(newGeoCoordinate, DateTime.Now, positionChangesEventArgs.Position.Coordinate.Accuracy);

            _positionPath.AddPosition(newPosition);

            var stationaryUpdateResult = StationaryUpdate(positionChangesEventArgs.Position, newPosition);
            if (stationaryUpdateResult == StationaryUpdateResult.InStationary) return;

            var currentAvgSpeed = _positionPath.GetCurrentSpeed(TimeSpan.FromMilliseconds(_reportInterval * 5)); // avg speed of last 5 (at max) positions

            var updateScaledDistanceFilterResult = UpdateScaledDistanceFilter(currentAvgSpeed, positionChangesEventArgs.Position.Coordinate);
            if (updateScaledDistanceFilterResult.SkipPositionBecauseOfDistance)
            {
                SkipPosition(updateScaledDistanceFilterResult.StartStationary, updateScaledDistanceFilterResult.StartStationary, updateScaledDistanceFilterResult.Distance);
                return;
            }

            var newReportInterval = CalculateNewReportInterval(currentAvgSpeed);
            if (updateScaledDistanceFilterResult.ScaledDistanceFilterChanged) UpdateReportInterval(newReportInterval);

            PositionChanged(this, new GeolocatorWrapperPositionChangedEventArgs
            {
                GeolocatorLocationStatus = Geolocator.LocationStatus,
                Position = positionChangesEventArgs.Position,
                EnteredStationary = false,
                PositionUpdateDebugData = PostionUpdateDebugData.ForNewPosition(positionChangesEventArgs, currentAvgSpeed, updateScaledDistanceFilterResult, Geolocator.ReportInterval, stationaryUpdateResult == StationaryUpdateResult.ExitedFromStationary)
            });
        }
 public void StartStationary(Position stationaryPosition, Geocoordinate geocoordinate)
 {
     _stationaryPosition = stationaryPosition;
     _stationaryGeocoordinate = geocoordinate;
 }
 public double GetDistanceToStationary(Position position)
 {
     return _stationaryPosition.GeoCoordinate.GetDistanceTo(position.GeoCoordinate);
 }
        private void OnGeolocatorPositionChanged(Geolocator sender, PositionChangedEventArgs positionChangesEventArgs)
        {
            if (_skipNextPosition)
            {
                _skipNextPosition = false;
                return;
            }

            var newGeoCoordinate = new GeoCoordinate(positionChangesEventArgs.Position.Coordinate.Latitude, positionChangesEventArgs.Position.Coordinate.Longitude);
            var newPosition      = new Position(newGeoCoordinate, DateTime.Now, positionChangesEventArgs.Position.Coordinate.Accuracy);

            _positionPath.AddPosition(newPosition);

            var stationaryUpdateResult = StationaryUpdate(positionChangesEventArgs.Position, newPosition);
            if (stationaryUpdateResult == StationaryUpdateResult.InStationary && !_useFixedTimeInterval)
            {
                return;
            }

            var currentAvgSpeed = _positionPath.GetCurrentSpeed(TimeSpan.FromMilliseconds(_reportInterval * 5)); // avg speed of last 5 (at max) positions

            var updateScaledDistanceFilterResult = UpdateScaledDistanceFilter(currentAvgSpeed, positionChangesEventArgs.Position.Coordinate);
            if (updateScaledDistanceFilterResult.SkipPositionBecauseOfDistance && !_useFixedTimeInterval)
            {
                SkipPosition(updateScaledDistanceFilterResult.StartStationary, updateScaledDistanceFilterResult.StartStationary, updateScaledDistanceFilterResult.Distance);
                return;
            }

            if (updateScaledDistanceFilterResult.ScaledDistanceFilterChanged && !_useFixedTimeInterval)
            {
                var newReportInterval = CalculateNewReportInterval(currentAvgSpeed);
                UpdateReportInterval(newReportInterval);
            }

            _reportedPositionsCount++;
            _reportedIntervalsPositionsCount++;

            var geolocatorWrapperPositionChangedEventArgs = new GeolocatorWrapperPositionChangedEventArgs
            {
                GeolocatorLocationStatus = Geolocator.LocationStatus,
                Position                 = positionChangesEventArgs.Position,
                EnteredStationary        = false,
                PositionUpdateDebugData  = PostionUpdateDebugData.ForNewPosition(positionChangesEventArgs, currentAvgSpeed, updateScaledDistanceFilterResult, Geolocator.ReportInterval, stationaryUpdateResult == StationaryUpdateResult.ExitedFromStationary)
            };

            if (_notificationIndex < _notifications.Count)
            {
                using (IsolatedStorageFileStream file = new IsolatedStorageFileStream("geoLocatorWrapperOutput.txt", FileMode.Append, FileAccess.Write, IsolatedStorageFile.GetUserStoreForApplication()))
                {
                    using (StreamWriter writeFile = new StreamWriter(file))
                    {
                        writeFile.WriteLine("_reportedPositionsCount: " + _reportedPositionsCount);
                        writeFile.WriteLine("_notificationIndex: " + _notificationIndex);
                        writeFile.WriteLine("_notificationOffsetSeconds: " + _notificationOffsetSeconds);
                        writeFile.WriteLine("_notifications.Count: " + _notifications.Count);
                        writeFile.WriteLine("_notifications[_notificationIndex].intervalSeconds: " + _notifications[_notificationIndex].intervalSeconds);
                        writeFile.WriteLine("Current Time: " + (_reportInterval / 1000) * _reportedIntervalsPositionsCount);
                        writeFile.WriteLine("Next Interval Time: " + (_notifications[_notificationIndex].intervalSeconds + _notificationOffsetSeconds));
                        writeFile.Close();
                    }
                    file.Close();
                }

                if (_reportedPositionsCount > 1 && ((_reportInterval / 1000) * _reportedPositionsCount) >= (_notifications[_notificationIndex].intervalSeconds + _notificationOffsetSeconds))
                {
                    using (IsolatedStorageFileStream file = new IsolatedStorageFileStream("geoLocatorWrapperOutput.txt", FileMode.Append, FileAccess.Write, IsolatedStorageFile.GetUserStoreForApplication()))
                    {
                        using (StreamWriter writeFile = new StreamWriter(file))
                        {
                            writeFile.WriteLine("_notifications[_notificationIndex].text: " + _notifications[_notificationIndex].text);
                            writeFile.Close();
                        }
                        file.Close();
                    }
                    _notificationOffsetSeconds += _notifications[_notificationIndex].intervalSeconds;
                    geolocatorWrapperPositionChangedEventArgs.NotiticationText = _notifications[_notificationIndex].text;
                    _notificationIndex++;
                }
                else
                {
                    geolocatorWrapperPositionChangedEventArgs.NotiticationText = "";
                }
            }
            else
            {
                geolocatorWrapperPositionChangedEventArgs.NotiticationText = "";
            }

            if (_intervalReportSeconds > 0 && ((_reportInterval / 1000) * _reportedIntervalsPositionsCount) == _intervalReportSeconds)
            {
                _reportedIntervalsPositionsCount = 0;
                geolocatorWrapperPositionChangedEventArgs.SpeachReportReady = true;
                //Get Average speed
                geolocatorWrapperPositionChangedEventArgs.AverageSpeed =
                    _positionPath.GetCurrentSpeed(TimeSpan.FromMilliseconds(_reportInterval * _reportedPositionsCount));

                //Get Current speed
                geolocatorWrapperPositionChangedEventArgs.CurrentSpeed =
                    _positionPath.GetCurrentSpeed(TimeSpan.FromSeconds(_intervalReportSeconds));

                if (_reportInMiles)
                {
                    //Convert Average speed to MPH
                    geolocatorWrapperPositionChangedEventArgs.AverageSpeed =
                        geolocatorWrapperPositionChangedEventArgs.AverageSpeed * 2.23694;

                    //Convert Current speed to MPH
                    geolocatorWrapperPositionChangedEventArgs.CurrentSpeed =
                        geolocatorWrapperPositionChangedEventArgs.CurrentSpeed * 2.23694;

                    //Get Total Distance
                    geolocatorWrapperPositionChangedEventArgs.TotalDistance =
                        _positionPath.GetTotalDistance(TimeSpan.FromMilliseconds(_reportInterval * _reportedPositionsCount)) * 0.000621371;
                }

                //Get Average Pace
                geolocatorWrapperPositionChangedEventArgs.AveragePace =
                    60 / geolocatorWrapperPositionChangedEventArgs.AverageSpeed;

                //Get Current Pace
                geolocatorWrapperPositionChangedEventArgs.CurrentPace =
                    60 / geolocatorWrapperPositionChangedEventArgs.CurrentSpeed;

                //Get Total Time
                geolocatorWrapperPositionChangedEventArgs.TotalTime =
                    TimeSpan.FromMilliseconds(_reportInterval * _reportedPositionsCount);
            }
            PositionChanged(this, geolocatorWrapperPositionChangedEventArgs);
        }