private void GeocodeLocationAndSave(Location matchedLocation)
        {
            // geocode - limit 900 per hour / one every 4 seconds
            var geocodeResult     = new GeocodeResult();
            var cityGeocodeResult = new GeocodeResult();
            var successFlag       = false;

            try
            {
                geocodeResult = _geocodeService.Geocode("", matchedLocation.StreetAddress, matchedLocation.City,
                                                        matchedLocation.State, matchedLocation.Zip);
                successFlag = true;
            }
            catch (Exception e)
            {
                ReportErrors.AddError(string.Format("Unable to fetch GeocodeResult for {0} {1} {2} {3}", matchedLocation.StreetAddress, matchedLocation.City, matchedLocation.State, matchedLocation.Zip));
            }
            try
            {
                cityGeocodeResult = _geocodeService.Geocode("", "", matchedLocation.City, matchedLocation.State,
                                                            matchedLocation.Zip);
                successFlag &= true;
            }
            catch (Exception e)
            {
                ReportErrors.AddError(string.Format("Unable to fetch CityGeocodeResult for {0} {1} {2} {3}", matchedLocation.StreetAddress, matchedLocation.City, matchedLocation.State, matchedLocation.Zip));
            }

            if (successFlag)
            {
                geocodeResult.SaveTo(matchedLocation);

                if (geocodeResult.IsSameAs(cityGeocodeResult))
                {
                    // geocode failure likely
                    ReportErrors.AddError(string.Format("Geocode failure for location {0}", matchedLocation.LegacyId));
                    matchedLocation.IsFailedGeocode = true;
                }

                if (matchedLocation.Id == 0 && matchedLocation.LegacyId != "0")
                {
                    _locationService.Insert(matchedLocation);
                }
                else
                {
                    _locationService.Update(matchedLocation);
                }
            }
        }
        private void AddToLocationDictionary(Location location, Dictionary <string, IList <Location> > dict)
        {
            var key = string.Format("{0},{1}", location.Latitude, location.Longitude);

            if (dict.ContainsKey(key))
            {
                var items = dict[key];
                items.Add(location);
                dict[key] = items;
            }
            else
            {
                dict.Add(key, new List <Location>()
                {
                    location
                });
            }
        }
        public ImportJobResult Process(string filePath, int subscriberId, bool syncLocations, bool syncJobs, bool saveToDatabase)
        {
            int locationErrorCount      = 0;
            int createdJobCount         = 0;
            var errorJobCount           = 0;
            int updatedJobCount         = 0;
            int existingJobCount        = 0;
            int recreatedRouteStopCount = 0;

            var result = ImportJobs(filePath, subscriberId);
            var locationsByCustomerNumber = result.GetCompanyLocations(subscriberId, true);

            Location matchingLocation = null;

            locationsByCustomerNumber.TryGetValue("1863", out matchingLocation);

            if (syncLocations)
            {
                var persistedLocations = SyncLocations(locationsByCustomerNumber.Values, subscriberId, out locationErrorCount);
                if (syncJobs)
                {
                    var extractedJobs = result.GetJobs(persistedLocations.ToDictionary(p => p.LegacyId), StopActions, subscriberId);
                    Console.WriteLine("Detected {0} jobs", extractedJobs.Count);
                    foreach (var job in extractedJobs)
                    {
                        var routeStops = job.RouteStops.Select(x =>
                                                               new PAI.Drayage.Optimization.Model.Orders.RouteStop
                        {
                            Id            = x.Id,
                            ExecutionTime =
                                x.StopDelay.HasValue ? new TimeSpan(x.StopDelay.Value) : (TimeSpan?)null,
                            Location = new PAI.Drayage.Optimization.Model.Location
                            {
                                Id          = x.Location.Id,
                                DisplayName = x.Location.DisplayName,
                                Latitude    = x.Location.Latitude.HasValue ? x.Location.Latitude.Value : 0,
                                Longitude   = x.Location.Longitude.HasValue ? x.Location.Longitude.Value : 0
                            },
                            PostTruckConfig = new TruckConfiguration(),
                            PreTruckConfig  = new TruckConfiguration(),
                            QueueTime       = null,
                            StopAction      =
                                PAI.Drayage.Optimization.Model.Orders.StopActions.Actions.First(
                                    y => y.ShortName == x.StopAction.ShortName),
                            WindowEnd   = new TimeSpan(x.WindowEnd),
                            WindowStart = new TimeSpan(x.WindowStart)
                        }).ToList();

                        var drayageJob = new PAI.Drayage.Optimization.Model.Orders.Job
                        {
                            Id                     = job.Id,
                            DisplayName            = job.OrderNumber,
                            EquipmentConfiguration = new EquipmentConfiguration(),
                            IsFlatbed              = job.IsFlatbed,
                            IsHazmat               = job.IsHazmat,
                            RouteStops             = routeStops
                        };

                        var validationResult = _validationService.ValidateJob(drayageJob, true, _distanceService);
                        job.IsValid = validationResult.Successful;
                        if (!validationResult.Successful)
                        {
                            if (job.RouteStops.Any(x => _validationService.InvalidTimes.Contains(new TimeSpan(x.WindowStart)) || _validationService.InvalidTimes.Contains(new TimeSpan(x.WindowEnd))))
                            {
                                job.RouteStops.First().StopAction = _stopActionService.GetById(Drayage.Optimization.Model.Orders.StopActions.DropOffLoadedWithChassis.Id);
                            }
                            ReportErrors.AddError(job.LegacyId + "\n" + validationResult.Errors.Aggregate((a, b) => a + "\n" + b));
                            errorJobCount++;
                        }
                        Job matchingJob = _jobService.SelectWithAll().FirstOrDefault(p => p.LegacyId == job.LegacyId);
                        if (matchingJob != null)
                        {
                            if (job.JobStatus == JobStatus.Completed)
                            {
                                Console.WriteLine("Order is already complete: {0}", job.LegacyId);
                                continue;
                            }

                            if (job.IsChangedFrom(matchingJob))
                            {
                                var updateResult = matchingJob.UpdateFrom(job);
                                if (updateResult.IsRouteStopsRecreated)
                                {
                                    recreatedRouteStopCount++;
                                }

                                if (updateResult.IsJobError)
                                {
                                    errorJobCount++;
                                }

                                if (saveToDatabase)
                                {
                                    _jobService.Update(matchingJob);
                                }

                                updatedJobCount++;
                            }
                            else
                            {
                                existingJobCount++;
                            }

                            continue;
                        }

                        Console.WriteLine("Adding new job");
                        createdJobCount++;

                        if (saveToDatabase)
                        {
                            _jobService.Insert(job);
                        }
                    }
                }
            }

            _syncLogEntryService.AddEntry(subscriberId, "Import Complete", "File: " + new FileInfo(filePath).Name,
                                          errorJobCount, updatedJobCount, createdJobCount, existingJobCount, recreatedRouteStopCount,
                                          locationErrorCount);

            return(result);
        }
        public IList <Location> SyncLocations(IEnumerable <Location> locations, int subscriberId, out int locationErrorCount)
        {
            Console.WriteLine("Processing locations.");
            var result            = new List <Location>();
            var existingLocations = _locationService.GetBySubscriberId(subscriberId).ToList();

            foreach (var location in locations)
            {
                if (string.IsNullOrEmpty(location.LegacyId) || string.IsNullOrEmpty(location.StreetAddress))
                {
                    continue;
                }

                // proceed
                var matchedLocation = existingLocations.FirstOrDefault(p => p.LegacyId == location.LegacyId);
                if (matchedLocation != null)
                {
                    if (matchedLocation.IsChangedFrom(location) && location.LegacyId != "0")
                    {
                        if (!matchedLocation.IsValidated)
                        {
                            // user has not flagged this order as verified, map new changes
                            location.MapTo(matchedLocation);
                            matchedLocation.IsFailedGeocode = false;
                            GeocodeLocationAndSave(matchedLocation);
                        }
                    }
                }
                else
                {
                    matchedLocation = new Location();
                    location.MapTo(matchedLocation);
                    matchedLocation.SubscriberId = subscriberId;
                    GeocodeLocationAndSave(matchedLocation);
                }

                result.Add(matchedLocation);
            }

            var dict = new Dictionary <string, IList <Location> >();

            foreach (var location in result)
            {
                AddToLocationDictionary(location, dict);
            }

            var dupes = dict.Where(p => p.Value.Count > 1).ToList();

            foreach (var dupeLocations in dupes)
            {
                foreach (var dupe in dupeLocations.Value)
                {
                    dupe.IsFailedGeocode = true;
                    _locationService.Update(dupe, false);
                }
            }
            _locationService.SaveChanges();

            locationErrorCount = dict.SelectMany(kvp => kvp.Value).Count(v => v.IsFailedGeocode);
            return(result);
        }