Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2498 - 1

2
namespace GMap.NET.MapProviders
3
{
4
   using System;
5
   using System.Collections.Generic;
6
   using System.Diagnostics;
7
   using System.Globalization;
8
   using System.Net;
9
   using System.Text;
10
   using System.Text.RegularExpressions;
11
   using System.Threading;
12
   using System.Xml;
13
   using GMap.NET.Internals;
14
   using GMap.NET.Projections;
15
 
16
   public abstract class BingMapProviderBase : GMapProvider, RoutingProvider, GeocodingProvider
17
   {
18
      public BingMapProviderBase()
19
      {
20
         MaxZoom = null;
21
         RefererUrl = "http://www.bing.com/maps/";
22
         Copyright = string.Format("©{0} Microsoft Corporation, ©{0} NAVTEQ, ©{0} Image courtesy of NASA", DateTime.Today.Year);
23
      }
24
 
25
      public string Version = "4810";
26
 
27
      /// <summary>
28
      /// Bing Maps Customer Identification.
29
      /// |
30
      /// FOR LEGAL AND COMMERCIAL USAGE SET YOUR OWN REGISTERED KEY
31
      /// |
32
      /// http://msdn.microsoft.com/en-us/library/ff428642.aspx
33
      /// </summary>
34
      public string ClientKey = string.Empty;
35
 
36
      internal string SessionId = string.Empty;
37
 
38
      /// <summary>
39
      /// set true to append SessionId on requesting tiles
40
      /// </summary>
41
      public bool ForceSessionIdOnTileAccess = false;
42
 
43
      /// <summary>
44
      /// set true to avoid using dynamic tile url format
45
      /// </summary>
46
      public bool DisableDynamicTileUrlFormat = false;
47
 
48
      /// <summary>
49
      /// Converts tile XY coordinates into a QuadKey at a specified level of detail.
50
      /// </summary>
51
      /// <param name="tileX">Tile X coordinate.</param>
52
      /// <param name="tileY">Tile Y coordinate.</param>
53
      /// <param name="levelOfDetail">Level of detail, from 1 (lowest detail)
54
      /// to 23 (highest detail).</param>
55
      /// <returns>A string containing the QuadKey.</returns>       
56
      internal string TileXYToQuadKey(long tileX, long tileY, int levelOfDetail)
57
      {
58
         StringBuilder quadKey = new StringBuilder();
59
         for(int i = levelOfDetail; i > 0; i--)
60
         {
61
            char digit = '0';
62
            int mask = 1 << (i - 1);
63
            if((tileX & mask) != 0)
64
            {
65
               digit++;
66
            }
67
            if((tileY & mask) != 0)
68
            {
69
               digit++;
70
               digit++;
71
            }
72
            quadKey.Append(digit);
73
         }
74
         return quadKey.ToString();
75
      }
76
 
77
      /// <summary>
78
      /// Converts a QuadKey into tile XY coordinates.
79
      /// </summary>
80
      /// <param name="quadKey">QuadKey of the tile.</param>
81
      /// <param name="tileX">Output parameter receiving the tile X coordinate.</param>
82
      /// <param name="tileY">Output parameter receiving the tile Y coordinate.</param>
83
      /// <param name="levelOfDetail">Output parameter receiving the level of detail.</param>
84
      internal void QuadKeyToTileXY(string quadKey, out int tileX, out int tileY, out int levelOfDetail)
85
      {
86
         tileX = tileY = 0;
87
         levelOfDetail = quadKey.Length;
88
         for(int i = levelOfDetail; i > 0; i--)
89
         {
90
            int mask = 1 << (i - 1);
91
            switch(quadKey[levelOfDetail - i])
92
            {
93
               case '0':
94
               break;
95
 
96
               case '1':
97
               tileX |= mask;
98
               break;
99
 
100
               case '2':
101
               tileY |= mask;
102
               break;
103
 
104
               case '3':
105
               tileX |= mask;
106
               tileY |= mask;
107
               break;
108
 
109
               default:
110
               throw new ArgumentException("Invalid QuadKey digit sequence.");
111
            }
112
         }
113
      }
114
 
115
      #region GMapProvider Members
116
      public override Guid Id
117
      {
118
         get
119
         {
120
            throw new NotImplementedException();
121
         }
122
      }
123
 
124
      public override string Name
125
      {
126
         get
127
         {
128
            throw new NotImplementedException();
129
         }
130
      }
131
 
132
      public override PureProjection Projection
133
      {
134
         get
135
         {
136
            return MercatorProjection.Instance;
137
         }
138
      }
139
 
140
      GMapProvider[] overlays;
141
      public override GMapProvider[] Overlays
142
      {
143
         get
144
         {
145
            if(overlays == null)
146
            {
147
               overlays = new GMapProvider[] { this };
148
            }
149
            return overlays;
150
         }
151
      }
152
 
153
      public override PureImage GetTileImage(GPoint pos, int zoom)
154
      {
155
         throw new NotImplementedException();
156
      }
157
      #endregion
158
 
159
      public bool TryCorrectVersion = true;
160
 
161
      /// <summary>
162
      /// set false to use your own key. 
163
      /// FOR LEGAL AND COMMERCIAL USAGE SET YOUR OWN REGISTERED KEY
164
      /// http://msdn.microsoft.com/en-us/library/ff428642.aspx
165
      /// </summary>
166
      public bool TryGetDefaultKey = true;
167
      static bool init = false;
168
 
169
      public override void OnInitialized()
170
      {
171
         if(!init)
172
         {
173
            try
174
            {
175
               var key = ClientKey;
176
 
177
               // to avoid registration stuff, default key
178
               if(TryGetDefaultKey && string.IsNullOrEmpty(ClientKey))
179
               {
180
                  //old: Vx8dmDflxzT02jJUG8bEjMU07Xr9QWRpPTeRuAZTC1uZFQdDCvK/jUbHKdyHEWj4LvccTPoKofDHtzHsWu/0xuo5u2Y9rj88
181
                  key = Stuff.GString("Jq7FrGTyaYqcrvv9ugBKv4OVSKnmzpigqZtdvtcDdgZexmOZ2RugOexFSmVzTAhOWiHrdhFoNCoySnNF3MyyIOo5u2Y9rj88");
182
               }
183
 
184
               #region -- try get sesion key --
185
               if(!string.IsNullOrEmpty(key))
186
               {
187
                  string keyResponse = GMaps.Instance.UseUrlCache ? Cache.Instance.GetContent("BingLoggingServiceV1" + key, CacheType.UrlCache, TimeSpan.FromHours(8)) : string.Empty;
188
 
189
                  if(string.IsNullOrEmpty(keyResponse))
190
                  {
191
                     // Bing Maps WPF Control
192
                     // http://dev.virtualearth.net/webservices/v1/LoggingService/LoggingService.svc/Log?entry=0&auth={0}&fmt=1&type=3&group=MapControl&name=WPF&version=1.0.0.0&session=00000000-0000-0000-0000-000000000000&mkt=en-US
193
 
194
                     keyResponse = GetContentUsingHttp(string.Format("http://dev.virtualearth.net/webservices/v1/LoggingService/LoggingService.svc/Log?entry=0&fmt=1&type=3&group=MapControl&name=AJAX&mkt=en-us&auth={0}&jsonp=microsoftMapsNetworkCallback", key));
195
 
196
                     if(!string.IsNullOrEmpty(keyResponse) && keyResponse.Contains("ValidCredentials"))
197
                     {
198
                        if(GMaps.Instance.UseUrlCache)
199
                        {
200
                           Cache.Instance.SaveContent("BingLoggingServiceV1" + key, CacheType.UrlCache, keyResponse);
201
                        }
202
                     }
203
                  }
204
 
205
                  if(!string.IsNullOrEmpty(keyResponse) && keyResponse.Contains("sessionId") && keyResponse.Contains("ValidCredentials"))
206
                  {
207
                     // microsoftMapsNetworkCallback({"sessionId" : "xxx", "authenticationResultCode" : "ValidCredentials"})
208
 
209
                     SessionId = keyResponse.Split(',')[0].Split(':')[1].Replace("\"", string.Empty).Replace(" ", string.Empty);
210
                     Debug.WriteLine("GMapProviders.BingMap.SessionId: " + SessionId);
211
                  }
212
                  else
213
                  {
214
                     Debug.WriteLine("BingLoggingServiceV1: " + keyResponse);
215
                  }
216
               }
217
               #endregion
218
 
219
               // supporting old road
220
               if(TryCorrectVersion && DisableDynamicTileUrlFormat)
221
               {
222
                  #region -- get the version --
223
                  string url = @"http://www.bing.com/maps";
224
                  string html = GMaps.Instance.UseUrlCache ? Cache.Instance.GetContent(url, CacheType.UrlCache, TimeSpan.FromDays(7)) : string.Empty;
225
 
226
                  if(string.IsNullOrEmpty(html))
227
                  {
228
                     html = GetContentUsingHttp(url);
229
                     if(!string.IsNullOrEmpty(html))
230
                     {
231
                        if(GMaps.Instance.UseUrlCache)
232
                        {
233
                           Cache.Instance.SaveContent(url, CacheType.UrlCache, html);
234
                        }
235
                     }
236
                  }
237
 
238
                  if(!string.IsNullOrEmpty(html))
239
                  {
240
                     #region -- match versions --
241
 
242
                     Regex reg = new Regex("tilegeneration:(\\d*)", RegexOptions.IgnoreCase);
243
                     Match mat = reg.Match(html);
244
                     if(mat.Success)
245
                     {
246
                        GroupCollection gc = mat.Groups;
247
                        int count = gc.Count;
248
                        if(count == 2)
249
                        {
250
                           string ver = gc[1].Value;
251
                           string old = GMapProviders.BingMap.Version;
252
                           if(ver != old)
253
                           {
254
                              GMapProviders.BingMap.Version = ver;
255
                              GMapProviders.BingSatelliteMap.Version = ver;
256
                              GMapProviders.BingHybridMap.Version = ver;
257
#if DEBUG
258
                              Debug.WriteLine("GMapProviders.BingMap.Version: " + ver + ", old: " + old + ", consider updating source");
259
                              if(Debugger.IsAttached)
260
                              {
261
                                 Thread.Sleep(5555);
262
                              }
263
#endif
264
                           }
265
                           else
266
                           {
267
                              Debug.WriteLine("GMapProviders.BingMap.Version: " + ver + ", OK");
268
                           }
269
                        }
270
                     }
271
                     #endregion
272
                  }
273
                  #endregion
274
               }
275
 
276
               init = true; // try it only once
277
            }
278
            catch(Exception ex)
279
            {
280
               Debug.WriteLine("TryCorrectBingVersions failed: " + ex);
281
            }
282
         }
283
      }
284
 
285
      protected override bool CheckTileImageHttpResponse(WebResponse response)
286
      {
287
         var pass = base.CheckTileImageHttpResponse(response);
288
         if(pass)
289
         {
290
            var tileInfo = response.Headers.Get("X-VE-Tile-Info");
291
            if(tileInfo != null)
292
            {
293
               return !tileInfo.Equals("no-tile");
294
            }
295
         }
296
         return pass;
297
      }
298
 
299
      internal string GetTileUrl(string imageryType)
300
      {
301
         //Retrieve map tile URL from the Imagery Metadata service: http://msdn.microsoft.com/en-us/library/ff701716.aspx
302
         //This ensures that the current tile URL is always used. 
303
         //This will prevent the app from breaking when the map tiles change.
304
 
305
         string ret = string.Empty;
306
         if(!string.IsNullOrEmpty(SessionId))
307
         {
308
            try
309
            {
310
               string url = "http://dev.virtualearth.net/REST/V1/Imagery/Metadata/" + imageryType + "?output=xml&key=" + SessionId;
311
 
312
               string r = GMaps.Instance.UseUrlCache ? Cache.Instance.GetContent("GetTileUrl" + imageryType, CacheType.UrlCache, TimeSpan.FromDays(7)) : string.Empty;
313
               bool cache = false;
314
 
315
               if(string.IsNullOrEmpty(r))
316
               {
317
                  r = GetContentUsingHttp(url);
318
                  cache = true;
319
               }
320
 
321
               if(!string.IsNullOrEmpty(r))
322
               {
323
                  XmlDocument doc = new XmlDocument();
324
                  doc.LoadXml(r);
325
 
326
                  XmlNode xn = doc["Response"];
327
                  string statuscode = xn["StatusCode"].InnerText;
328
                  if(string.Compare(statuscode, "200", true) == 0)
329
                  {
330
                     xn = xn["ResourceSets"]["ResourceSet"]["Resources"];
331
                     XmlNodeList xnl = xn.ChildNodes;
332
                     foreach(XmlNode xno in xnl)
333
                     {
334
                        XmlNode imageUrl = xno["ImageUrl"];
335
 
336
                        if(imageUrl != null && !string.IsNullOrEmpty(imageUrl.InnerText))
337
                        {
338
                           if(cache && GMaps.Instance.UseUrlCache)
339
                           {
340
                              Cache.Instance.SaveContent("GetTileUrl" + imageryType, CacheType.UrlCache, r);
341
                           }
342
 
343
                           var baseTileUrl = imageUrl.InnerText;
344
 
345
                           if(baseTileUrl.Contains("{key}") || baseTileUrl.Contains("{token}"))
346
                           {
347
                              baseTileUrl.Replace("{key}", SessionId).Replace("{token}", SessionId);
348
                           }
349
                           else if(ForceSessionIdOnTileAccess)
350
                           {
351
                              // haven't seen anyone doing that, yet? ;/                            
352
                              baseTileUrl += "&key=" + SessionId;
353
                           }
354
 
355
                           Debug.WriteLine("GetTileUrl, UrlFormat[" + imageryType + "]: " + baseTileUrl);
356
 
357
                           ret = baseTileUrl;
358
                           break;
359
                        }
360
                     }
361
                  }
362
               }
363
            }
364
            catch(Exception ex)
365
            {
366
               Debug.WriteLine("GetTileUrl: Error getting Bing Maps tile URL - " + ex);
367
            }
368
         }
369
         return ret;
370
      }
371
 
372
      #region RoutingProvider
373
 
374
      public MapRoute GetRoute(PointLatLng start, PointLatLng end, bool avoidHighways, bool walkingMode, int Zoom)
375
      {
376
         string tooltip;
377
         int numLevels;
378
         int zoomFactor;
379
         MapRoute ret = null;
380
         List<PointLatLng> points = GetRoutePoints(MakeRouteUrl(start, end, LanguageStr, avoidHighways, walkingMode), Zoom, out tooltip, out numLevels, out zoomFactor);
381
         if(points != null)
382
         {
383
            ret = new MapRoute(points, tooltip);
384
         }
385
         return ret;
386
      }
387
 
388
      public MapRoute GetRoute(string start, string end, bool avoidHighways, bool walkingMode, int Zoom)
389
      {
390
         string tooltip;
391
         int numLevels;
392
         int zoomFactor;
393
         MapRoute ret = null;
394
         List<PointLatLng> points = GetRoutePoints(MakeRouteUrl(start, end, LanguageStr, avoidHighways, walkingMode), Zoom, out tooltip, out numLevels, out zoomFactor);
395
         if(points != null)
396
         {
397
            ret = new MapRoute(points, tooltip);
398
         }
399
         return ret;
400
      }
401
 
402
      string MakeRouteUrl(string start, string end, string language, bool avoidHighways, bool walkingMode)
403
      {
404
         string addition = avoidHighways ? "&avoid=highways" : string.Empty;
405
         string mode = walkingMode ? "Walking" : "Driving";
406
 
407
         return string.Format(CultureInfo.InvariantCulture, RouteUrlFormatPointQueries, mode, start, end, addition, SessionId);
408
      }
409
 
410
      string MakeRouteUrl(PointLatLng start, PointLatLng end, string language, bool avoidHighways, bool walkingMode)
411
      {
412
         string addition = avoidHighways ? "&avoid=highways" : string.Empty;
413
         string mode = walkingMode ? "Walking" : "Driving";
414
 
415
         return string.Format(CultureInfo.InvariantCulture, RouteUrlFormatPointLatLng, mode, start.Lat, start.Lng, end.Lat, end.Lng, addition, SessionId);
416
      }
417
 
418
      List<PointLatLng> GetRoutePoints(string url, int zoom, out string tooltipHtml, out int numLevel, out int zoomFactor)
419
      {
420
         List<PointLatLng> points = null;
421
         tooltipHtml = string.Empty;
422
         numLevel = -1;
423
         zoomFactor = -1;
424
         try
425
         {
426
            string route = GMaps.Instance.UseRouteCache ? Cache.Instance.GetContent(url, CacheType.RouteCache) : string.Empty;
427
 
428
            if(string.IsNullOrEmpty(route))
429
            {
430
               route = GetContentUsingHttp(url);
431
 
432
               if(!string.IsNullOrEmpty(route))
433
               {
434
                  if(GMaps.Instance.UseRouteCache)
435
                  {
436
                     Cache.Instance.SaveContent(url, CacheType.RouteCache, route);
437
                  }
438
               }
439
            }
440
 
441
            // parse values
442
            if(!string.IsNullOrEmpty(route))
443
            {
444
               #region -- title --
445
               int tooltipEnd = 0;
446
               {
447
                  int x = route.IndexOf("<RoutePath><Line>") + 17;
448
                  if(x >= 17)
449
                  {
450
                     tooltipEnd = route.IndexOf("</Line></RoutePath>", x + 1);
451
                     if(tooltipEnd > 0)
452
                     {
453
                        int l = tooltipEnd - x;
454
                        if(l > 0)
455
                        {
456
                           //tooltipHtml = route.Substring(x, l).Replace(@"\x26#160;", " ");
457
                           tooltipHtml = route.Substring(x, l);
458
                        }
459
                     }
460
                  }
461
               }
462
               #endregion
463
 
464
               #region -- points --
465
               XmlDocument doc = new XmlDocument();
466
               doc.LoadXml(route);
467
               XmlNode xn = doc["Response"];
468
               string statuscode = xn["StatusCode"].InnerText;
469
               switch(statuscode)
470
               {
471
                  case "200":
472
                  {
473
                     xn = xn["ResourceSets"]["ResourceSet"]["Resources"]["Route"]["RoutePath"]["Line"];
474
                     XmlNodeList xnl = xn.ChildNodes;
475
                     if(xnl.Count > 0)
476
                     {
477
                        points = new List<PointLatLng>();
478
                        foreach(XmlNode xno in xnl)
479
                        {
480
                           XmlNode latitude = xno["Latitude"];
481
                           XmlNode longitude = xno["Longitude"];
482
                           points.Add(new PointLatLng(double.Parse(latitude.InnerText, CultureInfo.InvariantCulture),
483
                                                      double.Parse(longitude.InnerText, CultureInfo.InvariantCulture)));
484
                        }
485
                     }
486
                     break;
487
                  }
488
                  // no status implementation on routes yet although when introduced these are the codes. Exception will be catched.
489
                  case "400":
490
                  throw new Exception("Bad Request, The request contained an error.");
491
                  case "401":
492
                  throw new Exception("Unauthorized, Access was denied. You may have entered your credentials incorrectly, or you might not have access to the requested resource or operation.");
493
                  case "403":
494
                  throw new Exception("Forbidden, The request is for something forbidden. Authorization will not help.");
495
                  case "404":
496
                  throw new Exception("Not Found, The requested resource was not found.");
497
                  case "500":
498
                  throw new Exception("Internal Server Error, Your request could not be completed because there was a problem with the service.");
499
                  case "501":
500
                  throw new Exception("Service Unavailable, There's a problem with the service right now. Please try again later.");
501
                  default:
502
                  points = null;
503
                  break; // unknown, for possible future error codes
504
               }
505
               #endregion
506
            }
507
         }
508
         catch(Exception ex)
509
         {
510
            points = null;
511
            Debug.WriteLine("GetRoutePoints: " + ex);
512
         }
513
         return points;
514
      }
515
 
516
      // example : http://dev.virtualearth.net/REST/V1/Routes/Driving?o=xml&wp.0=44.979035,-93.26493&wp.1=44.943828508257866,-93.09332862496376&optmz=distance&rpo=Points&key=[PROVIDEYOUROWNKEY!!]
517
      static readonly string RouteUrlFormatPointLatLng = "http://dev.virtualearth.net/REST/V1/Routes/{0}?o=xml&wp.0={1},{2}&wp.1={3},{4}{5}&optmz=distance&rpo=Points&key={6}";
518
      static readonly string RouteUrlFormatPointQueries = "http://dev.virtualearth.net/REST/V1/Routes/{0}?o=xml&wp.0={1}&wp.1={2}{3}&optmz=distance&rpo=Points&key={4}";
519
 
520
      #endregion RoutingProvider
521
 
522
      #region GeocodingProvider
523
 
524
      public GeoCoderStatusCode GetPoints(string keywords, out List<PointLatLng> pointList)
525
      {
526
         //Escape keywords to better handle special characters.
527
         return GetLatLngFromGeocoderUrl(MakeGeocoderUrl("q=" + Uri.EscapeDataString(keywords)), out pointList);
528
      }
529
 
530
      public PointLatLng? GetPoint(string keywords, out GeoCoderStatusCode status)
531
      {
532
         List<PointLatLng> pointList;
533
         status = GetPoints(keywords, out pointList);
534
         return pointList != null && pointList.Count > 0 ? pointList[0] : (PointLatLng?)null;
535
      }
536
 
537
      public GeoCoderStatusCode GetPoints(Placemark placemark, out List<PointLatLng> pointList)
538
      {
539
         return GetLatLngFromGeocoderUrl(MakeGeocoderDetailedUrl(placemark), out pointList);
540
      }
541
 
542
      public PointLatLng? GetPoint(Placemark placemark, out GeoCoderStatusCode status)
543
      {
544
         List<PointLatLng> pointList;
545
         status = GetLatLngFromGeocoderUrl(MakeGeocoderDetailedUrl(placemark), out pointList);
546
         return pointList != null && pointList.Count > 0 ? pointList[0] : (PointLatLng?)null;
547
      }
548
 
549
      string MakeGeocoderDetailedUrl(Placemark placemark)
550
      {
551
         string parameters = string.Empty;
552
 
553
         if(!AddFieldIfNotEmpty(ref parameters, "countryRegion", placemark.CountryNameCode))
554
            AddFieldIfNotEmpty(ref parameters, "countryRegion", placemark.CountryName);
555
 
556
         AddFieldIfNotEmpty(ref parameters, "adminDistrict", placemark.DistrictName);
557
         AddFieldIfNotEmpty(ref parameters, "locality", placemark.LocalityName);
558
         AddFieldIfNotEmpty(ref parameters, "postalCode", placemark.PostalCodeNumber);
559
 
560
         if(!string.IsNullOrEmpty(placemark.HouseNo))
561
            AddFieldIfNotEmpty(ref parameters, "addressLine", placemark.ThoroughfareName + " " + placemark.HouseNo);
562
         else
563
            AddFieldIfNotEmpty(ref parameters, "addressLine", placemark.ThoroughfareName);
564
 
565
         return MakeGeocoderUrl(parameters);
566
      }
567
 
568
      bool AddFieldIfNotEmpty(ref string Input, string FieldName, string Value)
569
      {
570
         if(!string.IsNullOrEmpty(Value))
571
         {
572
            if(string.IsNullOrEmpty(Input))
573
               Input = string.Empty;
574
            else
575
               Input = Input + "&";
576
 
577
            Input = Input + FieldName + "=" + Value;
578
 
579
            return true;
580
         }
581
         return false;
582
      }
583
 
584
      public GeoCoderStatusCode GetPlacemarks(PointLatLng location, out List<Placemark> placemarkList)
585
      {
586
         // http://msdn.microsoft.com/en-us/library/ff701713.aspx
587
         throw new NotImplementedException();
588
      }
589
 
590
      public Placemark? GetPlacemark(PointLatLng location, out GeoCoderStatusCode status)
591
      {
592
         // http://msdn.microsoft.com/en-us/library/ff701713.aspx
593
         throw new NotImplementedException();
594
      }
595
 
596
      string MakeGeocoderUrl(string keywords)
597
      {
598
         return string.Format(CultureInfo.InvariantCulture, GeocoderUrlFormat, keywords, SessionId);
599
      }
600
 
601
      GeoCoderStatusCode GetLatLngFromGeocoderUrl(string url, out List<PointLatLng> pointList)
602
      {
603
         var status = GeoCoderStatusCode.Unknow;
604
         pointList = null;
605
 
606
         try
607
         {
608
            string geo = GMaps.Instance.UseGeocoderCache ? Cache.Instance.GetContent(url, CacheType.GeocoderCache) : string.Empty;
609
 
610
            bool cache = false;
611
 
612
            if(string.IsNullOrEmpty(geo))
613
            {
614
               geo = GetContentUsingHttp(url);
615
 
616
               if(!string.IsNullOrEmpty(geo))
617
               {
618
                  cache = true;
619
               }
620
            }
621
 
622
            status = GeoCoderStatusCode.Unknow;
623
            if(!string.IsNullOrEmpty(geo))
624
            {
625
               if(geo.StartsWith("<?xml") && geo.Contains("<Response"))
626
               {
627
                  XmlDocument doc = new XmlDocument();
628
                  doc.LoadXml(geo);
629
                  XmlNode xn = doc["Response"];
630
                  string statuscode = xn["StatusCode"].InnerText;
631
                  switch(statuscode)
632
                  {
633
                     case "200":
634
                     {
635
                        pointList = new List<PointLatLng>();
636
                        xn = xn["ResourceSets"]["ResourceSet"]["Resources"];
637
                        XmlNodeList xnl = xn.ChildNodes;
638
                        foreach(XmlNode xno in xnl)
639
                        {
640
                           XmlNode latitude = xno["Point"]["Latitude"];
641
                           XmlNode longitude = xno["Point"]["Longitude"];
642
                           pointList.Add(new PointLatLng(Double.Parse(latitude.InnerText, CultureInfo.InvariantCulture),
643
                                                         Double.Parse(longitude.InnerText, CultureInfo.InvariantCulture)));
644
                        }
645
 
646
                        if(pointList.Count > 0)
647
                        {
648
                           status = GeoCoderStatusCode.G_GEO_SUCCESS;
649
                           if(cache && GMaps.Instance.UseGeocoderCache)
650
                           {
651
                              Cache.Instance.SaveContent(url, CacheType.GeocoderCache, geo);
652
                           }
653
                           break;
654
                        }
655
 
656
                        status = GeoCoderStatusCode.G_GEO_UNKNOWN_ADDRESS;
657
                        break;
658
                     }
659
 
660
                     case "400":
661
                     status = GeoCoderStatusCode.G_GEO_BAD_REQUEST;
662
                     break; // bad request, The request contained an error.
663
                     case "401":
664
                     status = GeoCoderStatusCode.G_GEO_BAD_KEY;
665
                     break; // Unauthorized, Access was denied. You may have entered your credentials incorrectly, or you might not have access to the requested resource or operation.
666
                     case "403":
667
                     status = GeoCoderStatusCode.G_GEO_BAD_REQUEST;
668
                     break; // Forbidden, The request is for something forbidden. Authorization will not help.
669
                     case "404":
670
                     status = GeoCoderStatusCode.G_GEO_UNKNOWN_ADDRESS;
671
                     break; // Not Found, The requested resource was not found. 
672
                     case "500":
673
                     status = GeoCoderStatusCode.G_GEO_SERVER_ERROR;
674
                     break; // Internal Server Error, Your request could not be completed because there was a problem with the service.
675
                     case "501":
676
                     status = GeoCoderStatusCode.Unknow;
677
                     break; // Service Unavailable, There's a problem with the service right now. Please try again later.
678
                     default:
679
                     status = GeoCoderStatusCode.Unknow;
680
                     break; // unknown, for possible future error codes
681
                  }
682
               }
683
            }
684
         }
685
         catch(Exception ex)
686
         {
687
            status = GeoCoderStatusCode.ExceptionInCode;
688
            Debug.WriteLine("GetLatLngFromGeocoderUrl: " + ex);
689
         }
690
 
691
         return status;
692
      }
693
 
694
      // http://dev.virtualearth.net/REST/v1/Locations/1%20Microsoft%20Way%20Redmond%20WA%2098052?o=xml&key=BingMapsKey
695
      static readonly string GeocoderUrlFormat = "http://dev.virtualearth.net/REST/v1/Locations?{0}&o=xml&key={1}";
696
 
697
      #endregion GeocodingProvider
698
   }
699
 
700
   /// <summary>
701
   /// BingMapProvider provider
702
   /// </summary>
703
   public class BingMapProvider : BingMapProviderBase
704
   {
705
      public static readonly BingMapProvider Instance;
706
 
707
      BingMapProvider()
708
      {
709
      }
710
 
711
      static BingMapProvider()
712
      {
713
         Instance = new BingMapProvider();
714
      }
715
 
716
      #region GMapProvider Members
717
 
718
      readonly Guid id = new Guid("D0CEB371-F10A-4E12-A2C1-DF617D6674A8");
719
      public override Guid Id
720
      {
721
         get
722
         {
723
            return id;
724
         }
725
      }
726
 
727
      readonly string name = "BingMap";
728
      public override string Name
729
      {
730
         get
731
         {
732
            return name;
733
         }
734
      }
735
 
736
      public override PureImage GetTileImage(GPoint pos, int zoom)
737
      {
738
         string url = MakeTileImageUrl(pos, zoom, LanguageStr);
739
 
740
         return GetTileImageUsingHttp(url);
741
      }
742
 
743
      public override void OnInitialized()
744
      {
745
         base.OnInitialized();
746
 
747
         if(!DisableDynamicTileUrlFormat)
748
         {
749
            //UrlFormat[Road]: http://ecn.{subdomain}.tiles.virtualearth.net/tiles/r{quadkey}.jpeg?g=3179&mkt={culture}&shading=hill
750
 
751
            UrlDynamicFormat = GetTileUrl("Road");
752
            if(!string.IsNullOrEmpty(UrlDynamicFormat))
753
            {
754
               UrlDynamicFormat = UrlDynamicFormat.Replace("{subdomain}", "t{0}").Replace("{quadkey}", "{1}").Replace("{culture}", "{2}");
755
            }
756
         }
757
      }
758
 
759
      #endregion
760
 
761
      string MakeTileImageUrl(GPoint pos, int zoom, string language)
762
      {
763
         string key = TileXYToQuadKey(pos.X, pos.Y, zoom);
764
 
765
         if(!DisableDynamicTileUrlFormat && !string.IsNullOrEmpty(UrlDynamicFormat))
766
         {
767
            return string.Format(UrlDynamicFormat, GetServerNum(pos, 4), key, language);
768
         }
769
 
770
         return string.Format(UrlFormat, GetServerNum(pos, 4), key, Version, language, ForceSessionIdOnTileAccess ? "&key=" + SessionId : string.Empty);
771
      }
772
 
773
      string UrlDynamicFormat = string.Empty;
774
 
775
      // http://ecn.t0.tiles.virtualearth.net/tiles/r120030?g=875&mkt=en-us&lbl=l1&stl=h&shading=hill&n=z
776
 
777
      static readonly string UrlFormat = "http://ecn.t{0}.tiles.virtualearth.net/tiles/r{1}?g={2}&mkt={3}&lbl=l1&stl=h&shading=hill&n=z{4}";
778
   }
779
}