public List <GeoRegionInfo> SearchRegions(string name, GeoCountryInfo country)
        {
            var list = new List <GeoRegionInfo>();

            if (String.IsNullOrWhiteSpace(name))
            {
                return(list);
            }

            var countryID = (country?.CountryID ?? 0);
            var region    = GeoRegionInfo.Find(name);

            if (region != null)
            {
                if (countryID == 0 || region.CountryID == countryID)
                {
                    list.Add(region);
                    return(list);
                }
            }

            var locals = GeoRegionInfo.All.Where(x => x.CountryID == countryID);

            return(locals.Where(x => x.RegionName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase) ||
                                x.RegionAbbr.StartsWith(name, StringComparison.InvariantCultureIgnoreCase) ||
                                x.RegionNameLocal.StartsWith(name, StringComparison.InvariantCultureIgnoreCase)
                                ).ToList());
        }
 /// <summary>
 /// Lists all trals in a region
 /// </summary>
 public List <TopoTrailInfo> ListByRegion(GeoRegionInfo region)
 {
     return(Report(new TopoTrailReportRequest()
     {
         Region = region.RegionISO
     }));
 }
        /// <summary>
        /// Validates the request to create a new trail
        /// </summary>
        public ValidationServiceResponse <TopoTrailInfo> ValidateCreate(ITopoTrailUpdateRequest request)
        {
            // load existing trail
            var response = new ValidationServiceResponse <TopoTrailInfo>(null);

            // do basic validation
            if (String.IsNullOrWhiteSpace(request.Name))
            {
                response.AddError("Name", "Name is required!");
            }

            // TODO: REFACTOR: use GeoPolitical
            var timezone = GeoTimezoneInfo.Find(request.Timezone);

            if (timezone == null)
            {
                response.AddError("Timezone", "Timezone is missing or invalid!");
            }

            var country = GeoCountryInfo.Find(request.Country);

            if (country == null)
            {
                response.AddError("Country", "Country is missing or invalid!");
            }

            var region = GeoRegionInfo.Find(request.Region);

            if (region == null && !String.IsNullOrWhiteSpace(request.Region))
            {
                response.AddError("Region", "Region is invalid!");
            }

            return(response);
        }
        public TopoTrailInfo(GpxFileData data)
        {
            Name        = data.Name;
            Description = data.Description;

            Keywords = data.Keywords;
            UrlText  = data.UrlText;
            UrlLink  = data.UrlLink;

            Timezone = GeoTimezoneInfo.Find(data.Extensions.Timezone);
            if (Timezone == null)
            {
                Timezone = GeoTimezoneInfo.UTC;
            }

            Country  = GeoCountryInfo.Find(data.Extensions.Country);
            Region   = GeoRegionInfo.Find(data.Extensions.Region);
            Location = data.Extensions.Location;

            foreach (var track in data.Tracks)
            {
                var t = new TopoTrackInfo(this, track);
                _tracks.Add(t);
            }
        }
        public static string ToJson(this GeoRegionInfo region)
        {
            if (region == null)
            {
                return("{}");
            }

            dynamic json = new JObject();

            json.id      = region.RegionID;
            json.iso     = region.RegionISO;
            json.name    = region.RegionName;
            json.abbr    = region.RegionAbbr;
            json.country = region.Country.ISO3;

            json.center     = new JObject();
            json.center.lat = region.Center.Latitude;
            json.center.lng = region.Center.Longitude;

            json.bounds       = new JObject();
            json.bounds.north = (region.Bounds?.NorthWest?.Latitude ?? 0);
            json.bounds.south = (region.Bounds?.SouthEast?.Latitude ?? 0);
            json.bounds.east  = (region.Bounds?.SouthEast?.Longitude ?? 0);
            json.bounds.west  = (region.Bounds?.NorthWest?.Longitude ?? 0);

            return(json.ToString());
        }
        /// <summary>
        /// Find a the best matching place in a given region
        /// </summary>
        public CartoPlaceInfo FindPlace(GeoRegionInfo region, string name, bool deep = false)
        {
            var search = _cache.All.Where(x => x.Region != null && x.Region.RegionID == region.RegionID);

            search = FindPlace(search, name, deep);
            return(search.FirstOrDefault());
        }
        public TopoTrailInfo(ITopoTrailUpdateRequest data, List <GpxTrackData> tracks)
        {
            Name        = data.Name;
            Description = data.Description;

            Keywords = data.Keywords;
            UrlText  = data.UrlText;
            UrlLink  = data.UrlLink;

            Timezone = GeoTimezoneInfo.Find(data.Timezone);
            if (Timezone == null)
            {
                Timezone = GeoTimezoneInfo.UTC;
            }

            Country  = GeoCountryInfo.Find(data.Country);
            Region   = GeoRegionInfo.Find(data.Region);
            Location = data.Location;

            if (tracks != null)
            {
                foreach (var track in tracks)
                {
                    var t = new TopoTrackInfo(this, track);
                    _tracks.Add(t);
                }
            }
        }
		public void GeoRegionInfo_ListByLocation()
		{
			var r = GeoRegionInfo.ListByLocation(new GeoPosition(38.90723, -77.036464));
			Assert.AreEqual(3, r.Count());
			Assert.IsTrue(r.Any(x => x.RegionAbbr == "DC"));
			Assert.IsTrue(r.Any(x => x.RegionAbbr == "MD"));
			Assert.IsTrue(r.Any(x => x.RegionAbbr == "VA"));
		}
        private dynamic MapRegion(GeoRegionInfo r)
        {
            dynamic d = new ExpandoObject();

            d.RegionID   = r.RegionID;
            d.RegionISO  = r.RegionISO;
            d.RegionAbbr = r.RegionAbbr;
            d.RegionName = r.RegionName;
            return(d);
        }
        private IHttpActionResult ReturnRegion(GeoRegionInfo region)
        {
            if (region == null)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }

            var d = MapRegion(region);

            return(Ok(d));
        }
        public IHttpActionResult FindTimezoneByLocation(string name)
        {
            var timezone = Graffiti.Geo.GuessTimezone(GeoRegionInfo.Find(name));

            if (timezone != null)
            {
                return(GetTimezone(timezone?.TZID ?? ""));
            }

            timezone = Graffiti.Geo.GuessTimezone(GeoCountryInfo.Find(name));
            return(GetTimezone(timezone?.TZID ?? ""));
        }
        public CartoPlaceData ParsePlace(string place)
        {
            var p = new CartoPlaceData();

            p.Name = place;

            var index = place.LastIndexOf(',');

            if (index > 0)
            {
                var name        = place.Substring(0, index).Trim();
                var countryCode = place.Substring(index + 1).Trim();

                var country = GeoCountryInfo.ByISO(countryCode);
                if (country != null)
                {
                    p.Name    = name;
                    p.Country = country.Name;

                    index = name.LastIndexOf(',');
                    if (index > 0)
                    {
                        var area = name.Substring(index + 1).Trim();
                        name = name.Substring(0, index).Trim();
                        if (country.HasRegions)
                        {
                            var region = GeoRegionInfo.ByISO(country.ISO2, area);
                            if (region != null)
                            {
                                p.Region = region.RegionName;
                                p.Name   = name;
                            }
                            else
                            {
                                p.Locality = area;
                                p.Name     = name;
                            }
                        }
                        else
                        {
                            p.Locality = area;
                            p.Name     = name;
                        }
                    }
                }
            }

            return(p);
        }
		public void GeoRegionInfo_VerifyBounds()
		{
			string[] _swapLon = { "RU-CHU" };

			foreach (var c in GeoCountryInfo.All)
			{
				foreach (var r in GeoRegionInfo.ListByCountry(c.CountryID))
				{
					var lat = r.Bounds.NorthWest.Latitude > r.Bounds.SouthEast.Latitude;
					Assert.IsTrue(lat, $"Latitude Error for {c.Name} {r.RegionName} = {r.Bounds.NorthWest.Latitude}");

					var lon = r.Bounds.NorthWest.Longitude < r.Bounds.SouthEast.Longitude;
					if (_swapLon.Contains(r.RegionISO)) lon = !lon;
					Assert.IsTrue(lon, $"Longitude Error for {c.Name} {r.RegionName} = {r.Bounds.NorthWest.Longitude}");
				}
			}
		}
        public GeoPolitical(IGeoPoliticalData data)
        {
            _data = data;

            Timezone = GeoTimezoneInfo.Find(_data.Timezone);
            Country  = GeoCountryInfo.Find(_data.Country);
            Region   = GeoRegionInfo.Find(_data.Region);

            // attempt to backfill timezone
            if (Timezone == null && Region != null)
            {
                Timezone = Graffiti.Geo.GuessTimezone(Region);
            }
            if (Timezone == null && Country != null)
            {
                Timezone = Graffiti.Geo.GuessTimezone(Country);
            }
        }
        /// <summary>
        /// Displays all of the TopoTrailInfo GPX data files in a list and on a map for a given country with optional region filter
        /// </summary>
        public ActionResult Country(string id, string region, string sort, string tag)
        {
            var model = InitModel();

            model.SelectedSort = sort;

            if (!String.IsNullOrWhiteSpace(region))
            {
                var r = GeoRegionInfo.Find(region);
                if (r == null)
                {
                    model.ErrorMessages.Add($"Invalid region: {region}");
                }
                else
                {
                    model.SelectedRegion  = r;
                    model.SelectedCountry = r.Country;
                    model.Trails          = _trailDataService.ListByRegion(r);
                }
            }
            else
            {
                var c = GeoCountryInfo.Find(id);
                if (c == null)
                {
                    model.ErrorMessages.Add($"Invalid country: {id}");
                }
                else
                {
                    model.SelectedCountry = c;
                    model.Trails          = _trailDataService.ListByCountry(c);
                }
            }

            if (!String.IsNullOrWhiteSpace(tag))
            {
                model.Trails = model.Trails.Where(x => !String.IsNullOrWhiteSpace(x.Keywords) && x.Keywords.ToLowerInvariant().Contains(tag.ToLowerInvariant())).ToList();
            }

            return(View(model));
        }
        public ActionResult Places(int?year, string country = "")
        {
            var model = new OrthoPlacesViewModel();

            model.Years        = _tripSheetService.ListYears();
            model.SelectedYear = year;

            model.Countries       = _tripSheetService.ListCountries();
            model.SelectedCountry = GeoCountryInfo.Find(country);

            var places = new List <OrthoPlaceImportModel>();
            var import = _tripSheetService.ListPlaces(year, country);

            foreach (var data in import)
            {
                var place = new OrthoPlaceImportModel();
                place.Data = data;
                places.Add(place);

                // find existing place by region
                var r = GeoRegionInfo.Find(data.Region);
                if (r != null)
                {
                    place.Place = _cartoPlaceService.FindPlace(r, data.Name, true);
                }

                // find existing place by country
                if (place.Place == null)
                {
                    var c = GeoCountryInfo.Find(data.Country);
                    if (c != null)
                    {
                        place.Place = _cartoPlaceService.FindPlace(c, data.Name, true);
                    }
                }
            }
            model.Places = places;

            return(View(model));
        }
        /// <summary>
        /// Lists all trails meeting the report request
        /// </summary>
        public List <TopoTrailInfo> Report(TopoTrailReportRequest request)
        {
            var query = _trails.All.AsQueryable();

            if (request.Year.HasValue)
            {
                query = query.Where(x => x.StartLocal.Year == request.Year);
            }
            if (request.Month.HasValue)
            {
                query = query.Where(x => x.StartLocal.Month == request.Month);
            }
            if (request.Day.HasValue)
            {
                query = query.Where(x => x.StartLocal.Day == request.Day);
            }

            if (!String.IsNullOrWhiteSpace(request.Country))
            {
                var country = GeoCountryInfo.Find(request.Country);
                if (country != null)
                {
                    query = query.Where(x => x.Country.CountryID == country.CountryID);
                }
            }

            if (!String.IsNullOrWhiteSpace(request.Region))
            {
                var region = GeoRegionInfo.Find(request.Region);
                if (region != null)
                {
                    query = query.Where(x => x.Region != null && x.Region.RegionID == region.RegionID);
                }
            }

            return(query.ToList());
        }
		public void GeoRegionInfo_ByISO()
		{
			var r = GeoRegionInfo.ByISO("uS-Md");
			Assert.AreEqual("MD", r.RegionAbbr);
			Assert.AreEqual(840, r.Country.CountryID);
		}
 public GeoTimezoneInfo GuessTimezone(GeoRegionInfo region)
 {
     return(GuessTimezone(region?.Country));
 }
        public IHttpActionResult GetRegion(string id)
        {
            var region = GeoRegionInfo.Find(id);

            return(ReturnRegion(region));
        }
        /// <summary>
        /// Reports all places which fit the criteria
        /// </summary>
        public List <CartoPlaceInfo> ReportPlaces(CartoPlaceReportRequest request)
        {
            var query = _cache.All.AsQueryable();

            var placeType = request.PlaceType;

            if (!String.IsNullOrWhiteSpace(placeType))
            {
                placeType = placeType.Replace(',', ';').ToLowerInvariant();
                if (placeType.Contains(';'))
                {
                    var placeTypes = placeType.Split(';').Select(x => x.Trim()).ToList();
                    query = query.Where(x => placeTypes.Contains(x.PlaceType.ToLowerInvariant()));
                }
                else
                {
                    query = query.Where(x => (String.Compare(x.PlaceType, placeType, true) == 0));
                }
            }

            var country = GeoCountryInfo.Find(request.Country);

            if (country != null)
            {
                query = query.Where(x => x.Country.CountryID == country.CountryID);
            }

            var region = GeoRegionInfo.Find(request.Region);

            if (region != null)
            {
                query = query.Where(x => x.Region.RegionID == region.RegionID);
            }

            /*
             * var locality = request.Locality;
             * if (!String.IsNullOrWhiteSpace(locality)) query = query.Where(x => String.Compare(x.Locality, locality, true) == 0);
             */

            var name = request.Name;

            if (!String.IsNullOrWhiteSpace(name))
            {
                name = name.Replace("%", "*");
                if (!name.Contains("*"))
                {
                    name = "*" + name + "*";                                      // default to contains search
                }
                var n = name.Trim('*').ToLowerInvariant();
                if (name.StartsWith("*") && name.EndsWith("*"))
                {
                    query = query.Where(x => x.Name.ToLowerInvariant().Contains(n));
                }
                else if (name.EndsWith("*"))
                {
                    query = query.Where(x => x.Name.ToLowerInvariant().EndsWith(n));
                }
                else if (name.StartsWith("*"))
                {
                    query = query.Where(x => x.Name.ToLowerInvariant().StartsWith(n));
                }
                else
                {
                    query = query.Where(x => x.Name.ToLowerInvariant() == n);
                }
            }

            var text = request.Text;

            if (!String.IsNullOrWhiteSpace(text))
            {
                var t = text.ToLowerInvariant();
                query = query.Where(x => GetFullTextSearch(x).Contains(t));
            }

            // apply sort
            if (country == null || region == null)
            {
                query = query.OrderBy(x => x.Country.Name).ThenBy(x => (x.Region == null ? "" : x.Region.RegionName));
            }
            query = query.OrderBy(x => x.Name);

            // return list
            return(query.ToList());
        }
		public void GeoRegionInfo_ByID()
		{
			var r = GeoRegionInfo.ByName("MaRYlAnD");
			Assert.AreEqual("MD", r.RegionAbbr);
			Assert.AreEqual(840, r.Country.CountryID);
		}
		public void GeoRegionInfo_ByAbbr()
		{
			var r = GeoRegionInfo.ByAbbr("mD");
			Assert.AreEqual("MD", r.RegionAbbr);
			Assert.AreEqual(840, r.Country.CountryID);
		}
		public void GeoRegionInfo_ListByCountry()
		{
			var states = GeoRegionInfo.ListByCountry(840);
			Assert.AreEqual(51, states.Count());
			Assert.AreEqual(840, states.First().Country.CountryID);
		}
        /// <summary>
        /// Updates the trail metadata and synchronizes file and cache
        /// </summary>
        public ValidationServiceResponse <TopoTrailInfo> UpdateTrail(ITopoTrailUpdateRequest request)
        {
            // validate update request
            var response = ValidateUpdate(request);

            if (response.HasErrors)
            {
                return(response);
            }

            // process update request
            var trail = response.Data;

            // save current filename for later
            var existing = GetFilename(trail);

            // check file system
            if (!Directory.Exists(_rootUri))
            {
                throw new Exception($"Directory not initalized: {_rootUri}");
            }
            var folder = Path.Combine(_rootUri, trail.Country.Name);

            if (!Directory.Exists(folder))
            {
                Directory.CreateDirectory(folder);
            }

            // update trail properties
            trail.Timezone = GeoTimezoneInfo.Find(request.Timezone);
            trail.Country  = GeoCountryInfo.Find(request.Country);
            trail.Region   = GeoRegionInfo.Find(request.Region);

            trail.Name        = TextMutate.TrimSafe(request.Name);
            trail.Description = TextMutate.TrimSafe(request.Description);
            trail.Location    = TextMutate.TrimSafe(request.Location);
            trail.Keywords    = TextMutate.FixKeywords(request.Keywords);

            // TODO: BUG: fix url writing for v1.1 files!
            //trail.UrlLink = TextMutate.FixUrl(request.UrlLink);
            //trail.UrlText = TextMutate.TrimSafe(request.UrlText);

            // generate new and rename/remove existing files
            var filename = GetFilename(trail);

            // check if overwrite file
            var renamed = String.Compare(existing, filename, true) != 0;

            if (!renamed)
            {
                // temp rename current file
                File.Move(existing, existing + "~temp");
                existing = existing + "~temp";
            }

            // write new file
            var contents = BuildGpx(trail);

            File.WriteAllText(filename, contents);

            // delete old file
            File.Delete(existing);

            // refresh key and cache data
            if (renamed)
            {
                trail.Key = Path.GetFileNameWithoutExtension(filename).ToUpperInvariant();
                _trails.Remove(request.Key.ToUpperInvariant());
                _trails.Add(trail);
            }

            // return successful response
            return(response);
        }
 // --------------------------------------------------
 // Region
 public List <GeoRegionInfo> NearbyRegions(IGeoLatLon point)
 {
     return(GeoRegionInfo.ListByLocation(point).OrderBy(x => GeoDistance.BetweenPoints(x.Center, point).Meters).ToList());
 }